Nightly wheels #8
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
| # Nightly engine wheels: build on the self-hosted EC2 node and publish to the | |
| # FreeToken-Web rolling `beta` release. | |
| # | |
| # The node currently runs ALWAYS-ON, so this workflow does no power management. | |
| # Reintroduce the elastic variant (OIDC start-node/stop-node jobs around the build, | |
| # plus an on-node idle watchdog) when the node should go back to stop/start. | |
| # | |
| # Trigger policy -- only trusted paths, because the build job runs on a self-hosted | |
| # runner and this repo will be public: | |
| # - schedule: fired by GitHub itself on the default branch. | |
| # - workflow_dispatch: GitHub requires write permission to dispatch. | |
| # There is deliberately NO pull_request trigger here; fork code must never reach the | |
| # self-hosted node. PR smoke builds belong in a separate hosted-runner workflow. | |
| # | |
| # The wheels carry the +g<sha> stamp from scripts/build-release-wheels.sh, so a | |
| # nightly is fully identified by the commit it was built from. Nights where HEAD is | |
| # already published are skipped before the EC2 node is ever started. | |
| # | |
| # Formal (tagged) releases are out of scope here for now -- this workflow is the | |
| # nightly channel only. | |
| name: Nightly wheels | |
| on: | |
| schedule: | |
| - cron: "17 20 * * *" # off the top-of-hour congestion (cron is UTC) | |
| workflow_dispatch: | |
| inputs: | |
| force: | |
| description: "Build even if this commit is already published" | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| # Serialize runs: a parallel run's stop-node would power off the instance while | |
| # another run is still building on it. No cancel-in-progress for the same reason. | |
| concurrency: | |
| group: nightly-wheels | |
| env: | |
| WEB_REPO: FlashML-org/FreeToken-Web | |
| WEB_TAG: beta | |
| jobs: | |
| # Decide whether HEAD needs building at all. Runs on a hosted runner so a no-op | |
| # night costs nothing and never touches AWS. | |
| check: | |
| # Guard against runs from forks of this repo; update on an org transfer. | |
| if: github.repository == 'FlashML-org/FreeToken' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| build: ${{ steps.decide.outputs.build }} | |
| steps: | |
| - name: Compare HEAD against the published beta stamp | |
| id: decide | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| FORCE: ${{ inputs.force }} | |
| run: | | |
| head_stamp="+g${GITHUB_SHA:0:9}" | |
| # The release also carries win_amd64 wheels with their own stamp; this | |
| # workflow only builds linux, so compare the linux runtime wheel only. | |
| published_stamp="$(gh api "repos/$WEB_REPO/releases/tags/$WEB_TAG" \ | |
| --jq '.assets[].name' 2>/dev/null \ | |
| | grep -E '^freetoken-.*linux_x86_64\.whl$' \ | |
| | grep -oE '\+g[0-9a-f]{7,}' | head -1 || true)" | |
| echo "HEAD: $head_stamp published: ${published_stamp:-<none>}" | |
| if [ "$FORCE" = "true" ] || [ "$head_stamp" != "$published_stamp" ]; then | |
| echo "build=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "build=false" >> "$GITHUB_OUTPUT" | |
| echo "this commit is already published -- skipping" | |
| fi | |
| build: | |
| needs: check | |
| if: needs.check.outputs.build == 'true' | |
| runs-on: [self-hosted, linux, engine-build] | |
| timeout-minutes: 40 | |
| steps: | |
| # The build container runs as root; an interrupted build can leave root-owned | |
| # files that a plain checkout cannot delete. Wipe via a root container first. | |
| - name: Clean workspace | |
| run: | | |
| docker run --rm -v "${{ github.workspace }}:/workspace" alpine:3 \ | |
| sh -c 'rm -rf /workspace/..?* /workspace/.[!.]* /workspace/*' || true | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| - name: Build wheels (manylinux container) | |
| run: scripts/ci/manylinux-build.sh | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: wheels | |
| path: dist/*.whl | |
| if-no-files-found: error | |
| retention-days: 7 | |
| # Publish from a hosted runner: the cross-repo token is never present on the | |
| # self-hosted node, so a compromised build node cannot reach the release channel. | |
| publish: | |
| needs: [check, build] | |
| if: needs.check.outputs.build == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| environment: release | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| name: wheels | |
| path: dist | |
| - name: Publish to the beta release | |
| env: | |
| GH_TOKEN: ${{ secrets.FREETOKEN_WEB_TOKEN }} | |
| FREETOKEN_WEB_REPO: ${{ env.WEB_REPO }} | |
| FREETOKEN_WEB_TAG: ${{ env.WEB_TAG }} | |
| run: scripts/publish-wheels.sh dist |