ci-release-build #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Release build: produces signed installers and winget manifests for a tagged | |
| # xonsh release. | |
| # | |
| # Triggers: | |
| # * schedule — polls xonsh/xonsh upstream for a new release tag; if it finds | |
| # one that does not yet exist here, creates a matching release in this repo | |
| # and builds installers for it. This is the main automation path. | |
| # * release (created) — someone created a release in this repo by hand; reuse | |
| # its tag as the version and attach installers to it. | |
| # * workflow_dispatch — manual rebuild. Uses whatever xonsh/xonsh's latest | |
| # release is; if a release with that tag already exists here, re-uploads | |
| # assets (--clobber) instead of skipping. | |
| name: ci-release-build | |
| on: | |
| release: | |
| types: [created] | |
| workflow_dispatch: | |
| schedule: | |
| # Once a day at 04:00 UTC (just after the nightly build at 03:00). | |
| - cron: "0 4 * * *" | |
| permissions: | |
| contents: write | |
| jobs: | |
| prepare: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.resolve.outputs.version }} | |
| skip: ${{ steps.resolve.outputs.skip }} | |
| steps: | |
| - name: Resolve version & ensure release exists | |
| id: resolve | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| # Release was created in this repo by hand — reuse its tag. | |
| VERSION="${{ github.event.release.tag_name }}" | |
| echo "Using release tag: $VERSION" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # schedule / workflow_dispatch: mirror xonsh/xonsh's latest release. | |
| VERSION=$(gh api repos/xonsh/xonsh/releases/latest --jq '.tag_name') | |
| echo "xonsh/xonsh latest release: $VERSION" | |
| if gh release view "$VERSION" >/dev/null 2>&1; then | |
| if [ "${{ github.event_name }}" = "schedule" ]; then | |
| echo "Release $VERSION already built — skipping." | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # workflow_dispatch: rebuild existing release, overwriting assets. | |
| echo "Release $VERSION exists — will rebuild and overwrite assets." | |
| else | |
| echo "Creating release $VERSION." | |
| UPSTREAM_URL="https://github.com/xonsh/xonsh/releases/tag/$VERSION" | |
| gh release create "$VERSION" \ | |
| --title "$VERSION" \ | |
| --notes "Installer build for [xonsh/xonsh $VERSION]($UPSTREAM_URL)." \ | |
| --target "${{ github.sha }}" | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| build: | |
| needs: prepare | |
| if: needs.prepare.outputs.skip != 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Inno Setup 6 + latest Python — main build for Windows 10/11. | |
| # This one gets signed and used for the winget manifest. | |
| - inno: "6" | |
| python: "3.14.3" | |
| variant: "inno6" | |
| extra-args: "" | |
| # Inno Setup 5 + Python 3.13 — legacy build for Windows 8.1. | |
| # Python 3.13 is the last version supporting Windows 8.1. | |
| # https://docs.python.org/3.13/using/windows.html | |
| - inno: "5" | |
| python: "3.13.1" | |
| variant: "inno5" | |
| extra-args: "--include-python-tag --include-inno-tag" | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: pip install . | |
| - name: Install Inno Setup 6 | |
| if: matrix.inno == '6' | |
| run: choco install innosetup -y | |
| - name: Install Inno Setup 5 | |
| if: matrix.inno == '5' | |
| shell: pwsh | |
| run: | | |
| $url = "https://files.jrsoftware.org/is/5/innosetup-5.6.1.exe" | |
| $exe = "$env:RUNNER_TEMP\innosetup5.exe" | |
| Invoke-WebRequest -Uri $url -OutFile $exe | |
| Start-Process -FilePath $exe -ArgumentList '/VERYSILENT','/SUPPRESSMSGBOXES','/NORESTART','/SP-' -Wait | |
| - name: Build installer | |
| shell: bash | |
| run: | | |
| VERSION="${{ needs.prepare.outputs.version }}" | |
| xonsh build.xsh build --version "$VERSION" --python-version "${{ matrix.python }}" | |
| xonsh build.xsh installer --version "$VERSION" --inno-version "${{ matrix.inno }}" ${{ matrix.extra-args }} | |
| - name: Upload unsigned installer | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: xonsh-${{ matrix.variant }}-unsigned | |
| path: dist/xonsh-*-setup.exe | |
| sign: | |
| needs: [prepare, build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write | |
| contents: write | |
| steps: | |
| - name: Look up inno6 artifact ID | |
| id: artifact | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| ID=$(gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts" \ | |
| --jq '.artifacts[] | select(.name == "xonsh-inno6-unsigned") | .id') | |
| echo "id=$ID" >> "$GITHUB_OUTPUT" | |
| - name: Sign installer (inno6) | |
| uses: signpath/github-action-submit-signing-request@v1 | |
| with: | |
| api-token: ${{ secrets.SIGNPATH_API_TOKEN }} | |
| organization-id: ${{ vars.SIGNPATH_ORGANIZATION_ID }} | |
| project-slug: xonsh-winget | |
| signing-policy-slug: release-signing | |
| github-artifact-id: ${{ steps.artifact.outputs.id }} | |
| wait-for-completion: true | |
| output-artifact-directory: signed/ | |
| - name: Upload signed installer artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: xonsh-inno6-signed | |
| path: signed/ | |
| - name: Upload signed installer to release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: gh release upload "${{ needs.prepare.outputs.version }}" signed/xonsh-*-setup.exe --clobber | |
| upload-legacy: | |
| # The inno5 build is unsigned — upload it directly to the release. | |
| needs: [prepare, build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download legacy installer | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: xonsh-inno5-unsigned | |
| path: dist/ | |
| - name: Upload to release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: gh release upload "${{ needs.prepare.outputs.version }}" dist/xonsh-*-setup.exe --clobber | |
| manifests: | |
| # winget manifest points at the main (inno6, signed) installer. | |
| needs: [prepare, build, sign] | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: pip install . | |
| - name: Download signed installer | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: xonsh-inno6-signed | |
| path: dist/ | |
| - name: Generate winget manifests | |
| shell: bash | |
| run: xonsh build.xsh manifest --version "${{ needs.prepare.outputs.version }}" | |
| - name: Upload manifest artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: winget-manifests | |
| path: manifests/ |