mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-30 07:33:59 +08:00
ci(release): infer optional workflow tags (#4707)
* ci(release): infer optional workflow tags Signed-off-by: Simon Scatton <sscatton@nvidia.com> * fix(release): use resolved tag in success notifications Signed-off-by: Simon Scatton <sscatton@nvidia.com> * fix(release): pin prerelease notes to resolved candidate Signed-off-by: Simon Scatton <sscatton@nvidia.com> --------- Signed-off-by: Simon Scatton <sscatton@nvidia.com>
This commit is contained in:
@@ -21,69 +21,43 @@ jobs:
|
||||
create-tag:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
concurrency:
|
||||
group: release-prerelease-tags
|
||||
cancel-in-progress: false
|
||||
queue: max
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
||||
with:
|
||||
version: "0.10.12"
|
||||
python-version: "3.13"
|
||||
enable-cache: false
|
||||
|
||||
- name: Determine next pre-release version
|
||||
id: version
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tags=$(git tag -l)
|
||||
latest=$(printf '%s\n' "$tags" | \
|
||||
{ grep -E '^v[0-9]+\.[0-9]+\.[0-9]+(-pre\.[1-9][0-9]*)?$' || true; } | \
|
||||
sort -V | tail -1)
|
||||
if [[ ! "$latest" =~ ^(v[0-9]+\.[0-9]+\.[0-9]+)-pre\.([1-9][0-9]*)$ ]]; then
|
||||
echo "No active pre-release series — skipping tag creation"
|
||||
next=$(uv run --no-project python tasks/scripts/next-prerelease-tag.py --scheduled)
|
||||
if [[ -z "${next}" ]]; then
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
base=${BASH_REMATCH[1]}
|
||||
number=${BASH_REMATCH[2]}
|
||||
if ! git show-ref --verify --quiet "refs/tags/${base}-pre.1"; then
|
||||
echo "No ${base}-pre.1 seed — skipping tag creation"
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if git show-ref --verify --quiet "refs/tags/${base}"; then
|
||||
echo "$base is already stable — skipping tag creation"
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if ! git merge-base --is-ancestor "$latest" HEAD; then
|
||||
echo "::error::Latest pre-release $latest is not an ancestor of main"
|
||||
exit 1
|
||||
fi
|
||||
echo "Latest tag: $latest"
|
||||
|
||||
# Skip if no new commits since the latest tag
|
||||
commit_count=$(git rev-list "${latest}..HEAD" --count)
|
||||
echo "Commits since $latest: $commit_count"
|
||||
if [ "$commit_count" -eq 0 ]; then
|
||||
echo "No new commits since $latest — skipping tag creation"
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
next="${base}-pre.$((number + 1))"
|
||||
|
||||
if git tag -l "$next" | grep -q .; then
|
||||
echo "::error::Tag $next already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "next=$next" >> "$GITHUB_OUTPUT"
|
||||
echo "Next tag: $next"
|
||||
|
||||
- name: Create and push tag
|
||||
- name: Create tag
|
||||
if: steps.version.outputs.skip != 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
NEXT_TAG: ${{ steps.version.outputs.next }}
|
||||
run: |
|
||||
git tag "$NEXT_TAG"
|
||||
git push origin "refs/tags/$NEXT_TAG"
|
||||
gh api --method POST "repos/${GITHUB_REPOSITORY}/git/refs" \
|
||||
-f "ref=refs/tags/${NEXT_TAG}" -f "sha=$(git rev-parse HEAD)"
|
||||
|
||||
- name: Trigger Pre-release workflow
|
||||
if: steps.version.outputs.skip != 'true'
|
||||
|
||||
@@ -11,7 +11,7 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
expected-source-sha:
|
||||
description: Qualified source commit that the release tag must resolve to
|
||||
description: Expected source commit that the release tag must resolve to
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -n "${EXPECTED_SOURCE_SHA}" && "$(git rev-parse HEAD)" != "${EXPECTED_SOURCE_SHA}" ]]; then
|
||||
echo "Release tag ${RELEASE_TAG} does not match the qualified commit ${EXPECTED_SOURCE_SHA}." >&2
|
||||
echo "Release tag ${RELEASE_TAG} does not match the expected commit ${EXPECTED_SOURCE_SHA}." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${RELEASE_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-pre\.[1-9][0-9]*$ ]]; then
|
||||
|
||||
@@ -10,43 +10,107 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Pre-release tag to publish and qualify (e.g. v0.0.4-pre.1)"
|
||||
required: true
|
||||
description: "Existing prerelease tag (e.g. v0.0.4-pre.1); omit to create the next candidate on this branch"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
resolve:
|
||||
name: Resolve Prerelease Tag
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: write
|
||||
concurrency:
|
||||
group: release-prerelease-tags
|
||||
cancel-in-progress: false
|
||||
queue: max
|
||||
outputs:
|
||||
tag: ${{ steps.tag.outputs.tag }}
|
||||
source-sha: ${{ steps.tag.outputs.source_sha }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
||||
with:
|
||||
version: "0.10.12"
|
||||
python-version: "3.13"
|
||||
enable-cache: false
|
||||
|
||||
- name: Resolve or create candidate tag
|
||||
id: tag
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RELEASE_TAG: ${{ inputs.tag }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
REF_TYPE: ${{ github.ref_type }}
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag="${RELEASE_TAG}"
|
||||
if [[ "${EVENT_NAME}" == "push" ]]; then
|
||||
tag="${REF_NAME}"
|
||||
fi
|
||||
if [[ -z "${tag}" ]]; then
|
||||
test "${REF_TYPE}" = branch
|
||||
tag=$(uv run --no-project python tasks/scripts/next-prerelease-tag.py)
|
||||
source_sha=$(git rev-parse HEAD)
|
||||
gh api --method POST "repos/${GITHUB_REPOSITORY}/git/refs" \
|
||||
-f "ref=refs/tags/${tag}" -f "sha=${source_sha}"
|
||||
else
|
||||
if [[ ! "${tag}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-pre\.[1-9][0-9]*$ ]]; then
|
||||
echo "Unsupported prerelease tag: ${tag}" >&2
|
||||
exit 1
|
||||
fi
|
||||
source_sha=$(git rev-parse "refs/tags/${tag}^{commit}")
|
||||
fi
|
||||
{
|
||||
echo "tag=${tag}"
|
||||
echo "source_sha=${source_sha}"
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
{
|
||||
echo "## Prerelease candidate"
|
||||
echo "- Tag: \`${tag}\`"
|
||||
echo "- Source commit: \`${source_sha}\`"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
|
||||
build:
|
||||
name: Build
|
||||
needs: resolve
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
packages: write
|
||||
uses: ./.github/workflows/release-build.yml
|
||||
with:
|
||||
release-tag: ${{ inputs.tag || github.ref_name }}
|
||||
release-tag: ${{ needs.resolve.outputs.tag }}
|
||||
expected-source-sha: ${{ needs.resolve.outputs.source-sha }}
|
||||
is-prerelease: true
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
|
||||
release-notes:
|
||||
name: Preview Release Notes
|
||||
needs: build
|
||||
needs: [resolve, build]
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/release-notes.yml
|
||||
with:
|
||||
release-tag: ${{ inputs.tag || github.ref_name }}
|
||||
release-tag: ${{ needs.resolve.outputs.tag }}
|
||||
advisory: true
|
||||
secrets:
|
||||
LLM_INFERENCE_API_KEY: ${{ secrets.LLM_INFERENCE_API_KEY }}
|
||||
|
||||
publish:
|
||||
name: Publish
|
||||
needs: build
|
||||
needs: [resolve, build]
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
@@ -57,7 +121,7 @@ jobs:
|
||||
artifact-metadata: write
|
||||
uses: ./.github/workflows/release-publish.yml
|
||||
with:
|
||||
release-tag: ${{ inputs.tag || github.ref_name }}
|
||||
release-tag: ${{ needs.resolve.outputs.tag }}
|
||||
source-sha: ${{ needs.build.outputs.source_sha }}
|
||||
semver: ${{ needs.build.outputs.semver }}
|
||||
python-version: ${{ needs.build.outputs.python_version }}
|
||||
@@ -68,7 +132,7 @@ jobs:
|
||||
|
||||
qualify:
|
||||
name: Qualify
|
||||
needs: build
|
||||
needs: [resolve, build]
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -77,7 +141,7 @@ jobs:
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/release-qualification.yml
|
||||
with:
|
||||
release-tag: ${{ inputs.tag || github.ref_name }}
|
||||
release-tag: ${{ needs.resolve.outputs.tag }}
|
||||
source-sha: ${{ needs.build.outputs.source_sha }}
|
||||
is-prerelease: true
|
||||
secrets:
|
||||
@@ -86,7 +150,7 @@ jobs:
|
||||
|
||||
notify-prerelease-success:
|
||||
name: Notify Prerelease Success
|
||||
needs: [build, publish, qualify]
|
||||
needs: [resolve, build, publish, qualify]
|
||||
if: success()
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
@@ -95,10 +159,10 @@ jobs:
|
||||
- name: Send Slack notification
|
||||
continue-on-error: true
|
||||
env:
|
||||
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
|
||||
RELEASE_TAG: ${{ needs.resolve.outputs.tag }}
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_OPENSHELL_TRIAGE_WEBHOOK_URL }}
|
||||
RUN_URL: ${{ format('{0}/{1}/actions/runs/{2}/attempts/{3}', github.server_url, github.repository, github.run_id, github.run_attempt) }}
|
||||
TAG_URL: ${{ format('{0}/{1}/tree/{2}', github.server_url, github.repository, inputs.tag || github.ref_name) }}
|
||||
TAG_URL: ${{ format('{0}/{1}/tree/{2}', github.server_url, github.repository, needs.resolve.outputs.tag) }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -z "${SLACK_WEBHOOK_URL}" ]]; then
|
||||
@@ -114,7 +178,7 @@ jobs:
|
||||
|
||||
notify-prerelease-failure:
|
||||
name: Notify Prerelease Failure
|
||||
needs: [build, publish, qualify]
|
||||
needs: [resolve, build, publish, qualify]
|
||||
if: failure()
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
@@ -127,7 +191,7 @@ jobs:
|
||||
- name: Send Slack notification
|
||||
continue-on-error: true
|
||||
env:
|
||||
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
|
||||
RELEASE_TAG: ${{ needs.resolve.outputs.tag || inputs.tag || github.ref_name }}
|
||||
PUBLICATION_RESULT: ${{ needs.publish.result }}
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_OPENSHELL_TRIAGE_WEBHOOK_URL }}
|
||||
SLACK_MENTION: ${{ secrets.SLACK_OPENSHELL_TRIAGE_MENTION }}
|
||||
|
||||
@@ -7,8 +7,8 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Stable version to promote from its latest passing prerelease (e.g. v0.0.4)"
|
||||
required: true
|
||||
description: "Stable version (e.g. v0.0.4); omit to detect the highest prerelease version on this branch"
|
||||
required: false
|
||||
type: string
|
||||
notes-only:
|
||||
description: "Generate a release notes artifact without promoting or publishing"
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
- name: Retain promotion record
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: stable-promotion-${{ inputs.tag }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
name: stable-promotion-${{ steps.candidate.outputs.tag }}-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: promotion.json
|
||||
retention-days: 90
|
||||
if-no-files-found: error
|
||||
|
||||
Reference in New Issue
Block a user