1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108# Build and publish a release.
name: "Release"
on:
workflow_dispatch:
inputs:
commit:
description: "Commit SHA to release (default: latest on main)"
required: false
default: ""
build:
description: "Build date as YYYYMMDD (default: today)"
required: false
default: ""
publish:
description: "Publish to PyPI"
required: false
type: boolean
default: false
permissions:
contents: read
jobs:
resolve-ci-run:
name: "resolve ci run"
runs-on: ubuntu-latest
outputs:
run-id: ${{ steps.resolve.outputs.run-id }}
git-version: ${{ steps.resolve.outputs.git-version }}
build: ${{ steps.resolve.outputs.build }}
version: ${{ steps.resolve.outputs.version }}
steps:
- name: "Find CI run and resolve version"
id: resolve
env:
GH_TOKEN: ${{ github.token }}
run: |
# Resolve commit SHA
COMMIT="${{ inputs.commit }}"
if [ -z "$COMMIT" ]; then
COMMIT=$(gh api repos/${{ github.repository }}/commits/main --jq '.sha')
echo "Using latest commit on main: $COMMIT"
else
echo "Using specified commit: $COMMIT"
fi
# Find CI run for this commit
run_id=$(gh run list --repo ${{ github.repository }} --workflow=ci.yml --commit="$COMMIT" --limit=1 --json databaseId --jq '.[0].databaseId')
if [ -z "$run_id" ]; then
echo "::error::No CI run found for commit $COMMIT"
exit 1
fi
# Wait for CI to complete (if still running)
echo "Waiting for CI run $run_id to complete..."
gh run watch "$run_id" --repo ${{ github.repository }} --exit-status
echo "run-id=$run_id" >> "$GITHUB_OUTPUT"
# Verify artifacts are available
artifact_count=$(gh api repos/${{ github.repository }}/actions/runs/$run_id/artifacts --jq '.total_count')
if [ "$artifact_count" -eq 0 ]; then
echo "::error::No artifacts found for CI run $run_id - they may have expired"
exit 1
fi
echo "Found $artifact_count artifacts"
# Get the git version from the CI workflow file at that commit
# The version is defined in the plan job as: GIT_VERSION="x.y.z"
git_version=$(gh api repos/${{ github.repository }}/contents/.github/workflows/ci.yml?ref=$COMMIT --jq '.content' | base64 -d | grep 'GIT_VERSION=' | head -1 | sed 's/.*GIT_VERSION="\([^"]*\)".*/\1/')
if [ -z "$git_version" ]; then
echo "::error::Could not determine git version from commit $COMMIT"
exit 1
fi
echo "git-version=$git_version" >> "$GITHUB_OUTPUT"
# Resolve build date
BUILD="${{ inputs.build }}"
if [ -z "$BUILD" ]; then
BUILD=$(date -u +%Y%m%d)
fi
echo "build=$BUILD" >> "$GITHUB_OUTPUT"
echo "version=$git_version.$BUILD" >> "$GITHUB_OUTPUT"
echo "Releasing commit $COMMIT (CI run $run_id, git $git_version) -> version $git_version.$BUILD"
build-wheels:
needs: resolve-ci-run
uses: ./.github/workflows/build-wheels.yml
with:
git-version: ${{ needs.resolve-ci-run.outputs.git-version }}
build: ${{ needs.resolve-ci-run.outputs.build }}
run-id: ${{ needs.resolve-ci-run.outputs.run-id }}
test:
needs: build-wheels
uses: ./.github/workflows/test.yml
publish:
needs: test
if: ${{ inputs.publish }}
uses: ./.github/workflows/publish-pypi.yml
permissions:
id-token: write
attestations: write
contents: read