# SPDX-License-Identifier: LGPL-2.1-or-later name: Release Build on: push: tags: ["v*", "latest"] workflow_dispatch: inputs: tag: description: "Release tag (e.g., v0.1.0)" required: true type: string jobs: # --------------------------------------------------------------------------- # Linux: AppImage + .deb # --------------------------------------------------------------------------- build-linux: runs-on: ubuntu-latest env: CCACHE_DIR: /tmp/ccache-kindred-create CCACHE_COMPRESS: "true" CCACHE_COMPRESSLEVEL: "6" CCACHE_MAXSIZE: "4G" CCACHE_SLOPPINESS: "include_file_ctime,include_file_mtime,pch_defines,time_macros" CCACHE_COMPILERCHECK: "content" CCACHE_BASEDIR: ${{ github.workspace }} BUILD_TAG: ${{ github.ref_name || inputs.tag }} CFLAGS: "-O3" CXXFLAGS: "-O3" DEBIAN_FRONTEND: noninteractive NODE_EXTRA_CA_CERTS: /etc/ssl/certs/ca-certificates.crt steps: - name: Trust Cloudflare origin CA run: | apt-get update -qq apt-get install -y --no-install-recommends ca-certificates update-ca-certificates - name: Free disk space run: | echo "=== Disk usage before cleanup ===" df -h / # Remove pre-installed bloat common in runner images rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache 2>/dev/null || true rm -rf /usr/local/share/boost /usr/share/swift 2>/dev/null || true apt-get autoremove -y 2>/dev/null || true apt-get clean 2>/dev/null || true echo "=== Disk usage after cleanup ===" df -h / - name: Install system prerequisites run: | apt-get update -qq apt-get install -y --no-install-recommends \ ca-certificates curl git file fuse3 xvfb xauth openssl sudo dpkg-dev \ libgl1-mesa-dev libglu1-mesa-dev libx11-dev libxkbcommon-dev \ libxcb-xkb-dev libfontconfig1-dev - name: Checkout repository uses: https://git.kindred-systems.com/actions/checkout.git@v4 with: submodules: recursive fetch-depth: 1 - name: Fetch latest tag (for git describe) run: | latest_tag=$(git ls-remote --tags --sort=-v:refname origin 'refs/tags/v*' | grep -v '\^{}' | head -n1 | awk '{print $2}') if [ -n "$latest_tag" ]; then git fetch --no-recurse-submodules --force --depth=1 origin "+${latest_tag}:${latest_tag}" fi - name: Install pixi run: | curl -fsSL https://pixi.sh/install.sh | bash echo "$HOME/.pixi/bin" >> $GITHUB_PATH export PATH="$HOME/.pixi/bin:$PATH" pixi --version - name: Restore ccache id: ccache-restore uses: https://git.kindred-systems.com/actions/cache.git/restore@v4 with: path: /tmp/ccache-kindred-create key: ccache-release-linux-${{ github.run_id }} restore-keys: | ccache-release-linux- ccache-build-main- - name: Prepare ccache run: | mkdir -p $CCACHE_DIR # Ensure ccache is accessible to rattler-build's subprocess export PATH="$(pixi run bash -c 'echo $PATH')" pixi run ccache -z pixi run ccache -p - name: Build release package (AppImage) working-directory: package/rattler-build run: | pixi install pixi run -e package create_bundle - name: Show ccache statistics run: pixi run ccache -s - name: Save ccache if: always() uses: https://git.kindred-systems.com/actions/cache.git/save@v4 with: path: /tmp/ccache-kindred-create key: ccache-release-linux-${{ github.run_id }} - name: Clean up intermediate build files run: | # Remove pixi package cache and build work dirs to free space for .deb rm -rf package/rattler-build/.pixi/build 2>/dev/null || true find /root/.cache/rattler -type f -delete 2>/dev/null || true echo "=== Disk usage after cleanup ===" df -h / - name: Build .deb package run: | ./package/debian/build-deb.sh \ package/rattler-build/linux/AppDir/usr \ package/rattler-build/linux \ "${BUILD_TAG}" - name: List built artifacts run: | echo "=== Linux release artifacts ===" ls -lah package/rattler-build/linux/*.AppImage* 2>/dev/null || true ls -lah package/rattler-build/linux/*.deb* 2>/dev/null || true ls -lah package/rattler-build/linux/*-SHA256.txt 2>/dev/null || true - name: Upload Linux artifacts uses: https://git.kindred-systems.com/actions/upload-artifact.git@v3 with: name: release-linux path: | package/rattler-build/linux/FreeCAD_*.AppImage package/rattler-build/linux/*.deb package/rattler-build/linux/*-SHA256.txt package/rattler-build/linux/*.sha256 if-no-files-found: error # --------------------------------------------------------------------------- # macOS: DMG (Intel + Apple Silicon) # TODO: Re-enable when macOS runners are available or cross-compilation is set up # --------------------------------------------------------------------------- # build-macos: # strategy: # fail-fast: false # matrix: # include: # - runner: macos-13 # arch: x86_64 # - runner: macos-14 # arch: arm64 # # runs-on: ${{ matrix.runner }} # # env: # CCACHE_DIR: /tmp/ccache-kindred-create # CCACHE_COMPRESS: "true" # CCACHE_COMPRESSLEVEL: "6" # CCACHE_MAXSIZE: "4G" # CCACHE_SLOPPINESS: "include_file_ctime,include_file_mtime,pch_defines,time_macros" # CCACHE_BASEDIR: ${{ github.workspace }} # BUILD_TAG: ${{ github.ref_name || inputs.tag }} # CFLAGS: "-O3" # CXXFLAGS: "-O3" # # steps: # - name: Checkout repository # uses: https://git.kindred-systems.com/actions/checkout.git@v4 # with: # submodules: recursive # fetch-depth: 1 # # - name: Fetch tags # run: git fetch --tags --force --no-recurse-submodules origin # # - name: Install pixi # run: | # curl -fsSL https://pixi.sh/install.sh | bash # echo "$HOME/.pixi/bin" >> $GITHUB_PATH # export PATH="$HOME/.pixi/bin:$PATH" # pixi --version # # - name: Restore ccache # id: ccache-restore # uses: https://git.kindred-systems.com/actions/cache.git/restore@v4 # with: # path: /tmp/ccache-kindred-create # key: ccache-release-macos-${{ matrix.arch }}-${{ github.sha }} # restore-keys: | # ccache-release-macos-${{ matrix.arch }}- # # - name: Prepare ccache # run: | # mkdir -p $CCACHE_DIR # pixi run ccache -z # # - name: Build release package (DMG) # working-directory: package/rattler-build # run: | # pixi install # pixi run -e package create_bundle # # - name: Show ccache statistics # run: pixi run ccache -s # # - name: Save ccache # if: always() # uses: https://git.kindred-systems.com/actions/cache.git/save@v4 # with: # path: /tmp/ccache-kindred-create # key: ccache-release-macos-${{ matrix.arch }}-${{ github.sha }} # # - name: List built artifacts # run: | # echo "=== macOS ${{ matrix.arch }} release artifacts ===" # ls -lah package/rattler-build/osx/*.dmg* 2>/dev/null || true # # - name: Upload macOS artifacts # uses: https://git.kindred-systems.com/actions/upload-artifact.git@v3 # with: # name: release-macos-${{ matrix.arch }} # path: | # package/rattler-build/osx/*.dmg # package/rattler-build/osx/*-SHA256.txt # if-no-files-found: error # --------------------------------------------------------------------------- # Windows: .exe installer + .7z archive # TODO: Re-enable when Windows runners are available or cross-compilation is set up # --------------------------------------------------------------------------- # build-windows: # runs-on: windows-latest # # env: # CCACHE_DIR: C:\ccache-kindred-create # CCACHE_COMPRESS: "true" # CCACHE_COMPRESSLEVEL: "6" # CCACHE_MAXSIZE: "4G" # CCACHE_SLOPPINESS: "include_file_ctime,include_file_mtime,pch_defines,time_macros" # CCACHE_BASEDIR: ${{ github.workspace }} # BUILD_TAG: ${{ github.ref_name || inputs.tag }} # CFLAGS: "/O2" # CXXFLAGS: "/O2" # MAKE_INSTALLER: "true" # # steps: # - name: Checkout repository # uses: https://git.kindred-systems.com/actions/checkout.git@v4 # with: # submodules: recursive # fetch-depth: 1 # # - name: Fetch tags # shell: bash # run: git fetch --tags --force --no-recurse-submodules origin # # - name: Install pixi # shell: bash # run: | # curl -fsSL https://pixi.sh/install.sh | bash # echo "$HOME/.pixi/bin" >> $GITHUB_PATH # export PATH="$HOME/.pixi/bin:$PATH" # pixi --version # # - name: Restore ccache # id: ccache-restore # uses: https://git.kindred-systems.com/actions/cache.git/restore@v4 # with: # path: C:\ccache-kindred-create # key: ccache-release-windows-${{ github.sha }} # restore-keys: | # ccache-release-windows- # # - name: Build release package # shell: bash # working-directory: package/rattler-build # run: | # pixi install # pixi run -e package create_bundle # # - name: Save ccache # if: always() # uses: https://git.kindred-systems.com/actions/cache.git/save@v4 # with: # path: C:\ccache-kindred-create # key: ccache-release-windows-${{ github.sha }} # # - name: List built artifacts # shell: bash # run: | # echo "=== Windows release artifacts ===" # ls -lah package/rattler-build/windows/*.7z* 2>/dev/null || true # ls -lah package/rattler-build/windows/*.exe 2>/dev/null || true # ls -lah package/rattler-build/windows/*-SHA256.txt 2>/dev/null || true # # - name: Upload Windows artifacts # uses: https://git.kindred-systems.com/actions/upload-artifact.git@v3 # with: # name: release-windows # path: | # package/rattler-build/windows/*.7z # package/rattler-build/windows/*.exe # package/rattler-build/windows/*-SHA256.txt # if-no-files-found: error # --------------------------------------------------------------------------- # Create Gitea release from all platform artifacts # --------------------------------------------------------------------------- publish-release: needs: [build-linux] # TODO: Add build-macos, build-windows when runners are available runs-on: ubuntu-latest env: BUILD_TAG: ${{ github.ref_name || inputs.tag }} COMMIT_SHA: ${{ github.sha }} NODE_EXTRA_CA_CERTS: /etc/ssl/certs/ca-certificates.crt steps: - name: Trust Cloudflare origin CA run: | apt-get update -qq apt-get install -y --no-install-recommends ca-certificates update-ca-certificates - name: Download all artifacts uses: https://git.kindred-systems.com/actions/download-artifact.git@v3 with: path: artifacts - name: List all release artifacts run: | echo "=== All release artifacts ===" find artifacts -type f | sort - name: Collect release files run: | mkdir -p release find artifacts -type f \( \ -name "*.AppImage" -o \ -name "*.deb" -o \ -name "*.dmg" -o \ -name "*.7z" -o \ -name "*.exe" -o \ -name "*SHA256*" -o \ -name "*.sha256" \ \) -exec cp {} release/ \; echo "=== Release files ===" ls -lah release/ - name: Create release env: GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }} GITEA_URL: ${{ github.server_url }} REPO: ${{ github.repository }} run: | TAG="${BUILD_TAG}" # Build JSON payload entirely in Python to avoid shell/Python type mismatches PAYLOAD=$(python3 -c " import json, re tag = '${TAG}' prerelease = bool(re.search(r'(rc|beta|alpha)', tag)) body = '''## Kindred Create {tag} ### Downloads | Platform | File | |----------|------| | Linux (AppImage) | \`KindredCreate-*-Linux-x86_64.AppImage\` | | Linux (Debian/Ubuntu) | \`kindred-create_*.deb\` | *macOS and Windows builds are not yet available.* SHA256 checksums are provided alongside each artifact.'''.format(tag=tag) print(json.dumps({ 'tag_name': tag, 'name': f'Kindred Create {tag}', 'body': body, 'prerelease': prerelease, 'target_commitish': '${COMMIT_SHA}', })) ") # Delete existing release for this tag (if any) so we can recreate existing=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: token ${GITEA_TOKEN}" \ "${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}") if [ "$existing" = "200" ]; then release_id=$(curl -s \ -H "Authorization: token ${GITEA_TOKEN}" \ "${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}" | \ python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") curl -s -X DELETE \ -H "Authorization: token ${GITEA_TOKEN}" \ "${GITEA_URL}/api/v1/repos/${REPO}/releases/${release_id}" echo "Deleted existing release ${release_id} for tag ${TAG}" fi # Create release response=$(curl -s -w "\n%{http_code}" -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ "${GITEA_URL}/api/v1/repos/${REPO}/releases") http_code=$(echo "$response" | tail -1) body=$(echo "$response" | sed '$d') if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then echo "::error::Failed to create release (HTTP ${http_code}): ${body}" exit 1 fi release_id=$(echo "$body" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") echo "Created release ${release_id}" # Upload assets for file in release/*; do filename=$(basename "$file") echo "Uploading ${filename}..." upload_resp=$(curl -s -w "\n%{http_code}" -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -F "attachment=@${file}" \ "${GITEA_URL}/api/v1/repos/${REPO}/releases/${release_id}/assets?name=${filename}") upload_code=$(echo "$upload_resp" | tail -1) if [ "$upload_code" -lt 200 ] || [ "$upload_code" -ge 300 ]; then echo "::warning::Failed to upload ${filename} (HTTP ${upload_code})" else echo " done." fi done