diff --git a/.gitea/workflows/windows-build.yml b/.gitea/workflows/windows-build.yml index aa4d9de..ccd1759 100644 --- a/.gitea/workflows/windows-build.yml +++ b/.gitea/workflows/windows-build.yml @@ -1,12 +1,16 @@ -name: Build Windows EXE +name: Build Releases on: push: branches: - "**" +env: + APP_NAME: gitree + jobs: build-windows: + name: Build Windows x64 runs-on: ubuntu-latest steps: @@ -16,6 +20,16 @@ jobs: submodules: recursive fetch-depth: 0 + - name: Generate build names + env: + GITEA_SHA: ${{ gitea.sha }} + run: | + short_sha="$(printf '%s' "$GITEA_SHA" | cut -c1-7)" + + echo "BUILD_HASH=${short_sha}" >> "$GITHUB_ENV" + echo "WINDOWS_EXE=${APP_NAME}-windows-x64-${short_sha}.exe" >> "$GITHUB_ENV" + echo "WINDOWS_ARTIFACT=${APP_NAME}-windows-x64-${short_sha}" >> "$GITHUB_ENV" + - name: Install dependencies run: | sudo apt-get update @@ -26,10 +40,13 @@ jobs: cat > mingw-toolchain.cmake <<'EOF' set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_PROCESSOR x86_64) + set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) @@ -46,9 +63,32 @@ jobs: - name: Build Windows executable run: cmake --build build-win --parallel + - name: Locate Windows EXE + run: | + exe_path="" + + if [ -f "build-win/bin/${APP_NAME}.exe" ]; then + exe_path="build-win/bin/${APP_NAME}.exe" + elif [ -f "build-win/bin/Gitree.exe" ]; then + exe_path="build-win/bin/Gitree.exe" + elif [ -f "build-win/bin/gitree.exe" ]; then + exe_path="build-win/bin/gitree.exe" + else + exe_path="$(find build-win -type f -iname '*.exe' | head -n 1)" + fi + + if [ -z "$exe_path" ]; then + echo "Could not find built Windows EXE." + exit 1 + fi + + echo "WINDOWS_EXE_PATH=${exe_path}" >> "$GITHUB_ENV" + echo "Found Windows EXE: ${exe_path}" + - name: Verify static runtime linkage run: | - dependencies="$(x86_64-w64-mingw32-objdump -p build-win/bin/gitree.exe | sed -n 's/.*DLL Name: //p')" + dependencies="$(x86_64-w64-mingw32-objdump -p "$WINDOWS_EXE_PATH" | sed -n 's/.*DLL Name: //p')" + printf '%s\n' "$dependencies" if printf '%s\n' "$dependencies" | grep -Eqi 'lib(gcc|stdc\+\+|winpthread).*\.dll'; then @@ -56,36 +96,174 @@ jobs: exit 1 fi - - name: Generate EXE name - run: | - repo_name="$(basename "${GITEA_REPOSITORY}")" - short_sha="$(printf '%s' "${GITEA_SHA}" | cut -c1-7)" - - exe_name="${repo_name}-windows-x64-${GITEA_RUN_NUMBER}-${short_sha}.exe" - - echo "EXE_NAME=${exe_name}" >> "$GITHUB_ENV" - echo "ARTIFACT_NAME=${repo_name}-windows-x64-${GITEA_RUN_NUMBER}-${short_sha}" >> "$GITHUB_ENV" - - - name: Prepare artifact + - name: Prepare Windows artifact run: | mkdir -p dist - cp build-win/bin/gitree.exe "dist/${EXE_NAME}" + cp "$WINDOWS_EXE_PATH" "dist/${WINDOWS_EXE}" - name: Upload Windows build uses: actions/upload-artifact@v3 with: - name: ${{ env.ARTIFACT_NAME }} - path: dist/${{ env.EXE_NAME }} + name: ${{ env.WINDOWS_ARTIFACT }} + path: dist/${{ env.WINDOWS_EXE }} if-no-files-found: error - - name: Create prod release - if: ${{ gitea.ref_name == 'prod' }} + build-linux: + name: Build Linux x64 DEB + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Generate build names env: - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} - GITEA_SERVER_URL: ${{ gitea.server_url }} - GITEA_REPOSITORY: ${{ gitea.repository }} GITEA_SHA: ${{ gitea.sha }} - GITEA_RUN_NUMBER: ${{ gitea.run_number }} + run: | + short_sha="$(printf '%s' "$GITEA_SHA" | cut -c1-7)" + + echo "BUILD_HASH=${short_sha}" >> "$GITHUB_ENV" + echo "LINUX_DEB=${APP_NAME}-deb-x64-${short_sha}.deb" >> "$GITHUB_ENV" + echo "LINUX_ARTIFACT=${APP_NAME}-deb-x64-${short_sha}" >> "$GITHUB_ENV" + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake ninja-build curl jq dpkg-dev + + - name: Configure Linux release build + run: | + cmake -S . -B build-linux -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF + + - name: Build Linux executable + run: cmake --build build-linux --parallel + + - name: Locate Linux executable + run: | + exe_path="" + + if [ -f "build-linux/bin/${APP_NAME}" ]; then + exe_path="build-linux/bin/${APP_NAME}" + elif [ -f "build-linux/bin/Gitree" ]; then + exe_path="build-linux/bin/Gitree" + elif [ -f "build-linux/bin/gitree" ]; then + exe_path="build-linux/bin/gitree" + else + exe_path="$(find build-linux -type f -executable -name "${APP_NAME}" | head -n 1)" + fi + + if [ -z "$exe_path" ]; then + echo "Could not find built Linux executable." + exit 1 + fi + + echo "LINUX_EXE_PATH=${exe_path}" >> "$GITHUB_ENV" + echo "Found Linux executable: ${exe_path}" + + - name: Package Linux DEB + run: | + mkdir -p "pkg/DEBIAN" + mkdir -p "pkg/usr/bin" + + cp "$LINUX_EXE_PATH" "pkg/usr/bin/${APP_NAME}" + chmod 755 "pkg/usr/bin/${APP_NAME}" + + version="0.0.0+${BUILD_HASH}" + + cat > "pkg/DEBIAN/control" < + Description: ${APP_NAME} + ${APP_NAME} Linux x64 build. + EOF + + mkdir -p dist + dpkg-deb --build pkg "dist/${LINUX_DEB}" + + - name: Upload Linux DEB build + uses: actions/upload-artifact@v3 + with: + name: ${{ env.LINUX_ARTIFACT }} + path: dist/${{ env.LINUX_DEB }} + if-no-files-found: error + + release: + name: Create Release + runs-on: ubuntu-latest + needs: + - build-windows + - build-linux + if: ${{ always() && gitea.ref_name == 'prod' }} + + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + GITEA_SERVER_URL: ${{ gitea.server_url }} + GITEA_REPOSITORY: ${{ gitea.repository }} + GITEA_SHA: ${{ gitea.sha }} + WINDOWS_RESULT: ${{ needs.build-windows.result }} + LINUX_RESULT: ${{ needs.build-linux.result }} + APP_NAME: gitree + + steps: + - name: Check build results + run: | + echo "Windows result: ${WINDOWS_RESULT}" + echo "Linux result: ${LINUX_RESULT}" + + if [ "$WINDOWS_RESULT" != "success" ] && [ "$LINUX_RESULT" != "success" ]; then + echo "Both Windows and Linux builds failed. Refusing to create release." + exit 1 + fi + + - name: Check out repository + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Generate release names + run: | + short_sha="$(printf '%s' "$GITEA_SHA" | cut -c1-7)" + + echo "BUILD_HASH=${short_sha}" >> "$GITHUB_ENV" + echo "RELEASE_TAG=release-${short_sha}" >> "$GITHUB_ENV" + echo "RELEASE_NAME=Release ${short_sha}" >> "$GITHUB_ENV" + + echo "WINDOWS_EXE=${APP_NAME}-windows-x64-${short_sha}.exe" >> "$GITHUB_ENV" + echo "WINDOWS_ARTIFACT=${APP_NAME}-windows-x64-${short_sha}" >> "$GITHUB_ENV" + + echo "LINUX_DEB=${APP_NAME}-deb-x64-${short_sha}.deb" >> "$GITHUB_ENV" + echo "LINUX_ARTIFACT=${APP_NAME}-deb-x64-${short_sha}" >> "$GITHUB_ENV" + + - name: Install release dependencies + run: | + sudo apt-get update + sudo apt-get install -y curl jq + + - name: Download Windows artifact + if: ${{ needs.build-windows.result == 'success' }} + uses: actions/download-artifact@v3 + with: + name: ${{ env.WINDOWS_ARTIFACT }} + path: release-assets + + - name: Download Linux artifact + if: ${{ needs.build-linux.result == 'success' }} + uses: actions/download-artifact@v3 + with: + name: ${{ env.LINUX_ARTIFACT }} + path: release-assets + + - name: Create prod release run: | if [ -z "$GITEA_TOKEN" ]; then echo "The repository secret GITEA_TOKEN is required to publish prod releases." @@ -94,8 +272,6 @@ jobs: git fetch --tags --force - short_sha="$(printf '%s' "$GITEA_SHA" | cut -c1-7)" - tag="prod-${GITEA_RUN_NUMBER}-${short_sha}" api="${GITEA_SERVER_URL%/}/api/v1/repos/${GITEA_REPOSITORY}" repo_url="${GITEA_SERVER_URL%/}/${GITEA_REPOSITORY}" @@ -103,21 +279,16 @@ jobs: curl --fail-with-body --silent --show-error \ -H "Authorization: token ${GITEA_TOKEN}" \ "${api}/releases?limit=50" | - jq -r '[.[] | select(.tag_name | startswith("prod-"))][0].tag_name // empty' + jq -r '[.[] | select(.tag_name | startswith("release-"))][0].tag_name // empty' )" if [ -n "$previous_tag" ]; then range="${previous_tag}..${GITEA_SHA}" - echo "Generating release notes from ${previous_tag} to ${GITEA_SHA}" else range="${GITEA_SHA}" - echo "No previous prod release found. Generating release notes from current commit." fi { - echo "Automated Windows release from the prod branch." - echo - if [ -n "$previous_tag" ]; then echo "## Changes since ${previous_tag}" else @@ -140,6 +311,22 @@ jobs: done fi + echo + echo "## Builds" + echo + + if [ "$WINDOWS_RESULT" = "success" ]; then + echo "- ${WINDOWS_EXE}" + else + echo "- Windows x64 failed" + fi + + if [ "$LINUX_RESULT" = "success" ]; then + echo "- ${LINUX_DEB}" + else + echo "- Linux DEB x64 failed" + fi + echo echo "## Authors" echo @@ -175,9 +362,9 @@ jobs: } > release-notes.md payload="$(jq -n \ - --arg tag "$tag" \ + --arg tag "$RELEASE_TAG" \ --arg sha "$GITEA_SHA" \ - --arg name "${ARTIFACT_NAME}" \ + --arg name "$RELEASE_NAME" \ --rawfile body release-notes.md \ '{ tag_name: $tag, @@ -197,8 +384,18 @@ jobs: release_id="$(printf '%s' "$release" | jq -er '.id')" - curl --fail-with-body --silent --show-error \ - -X POST \ - -H "Authorization: token ${GITEA_TOKEN}" \ - -F "attachment=@dist/${EXE_NAME}" \ - "${api}/releases/${release_id}/assets?name=${EXE_NAME}" \ No newline at end of file + for asset in release-assets/*; do + if [ ! -f "$asset" ]; then + continue + fi + + asset_name="$(basename "$asset")" + + echo "Uploading ${asset_name}" + + curl --fail-with-body --silent --show-error \ + -X POST \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -F "attachment=@${asset}" \ + "${api}/releases/${release_id}/assets?name=${asset_name}" + done \ No newline at end of file