Files
OpenShell/.github/workflows/release-prerelease.yml
T
Simon Scatton 72bc3d3668 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>
2026-10-26 12:50:45 +00:00

229 lines
8.1 KiB
YAML

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
name: Pre-release
on:
push:
tags:
- "v*.*.*-pre.*"
workflow_dispatch:
inputs:
tag:
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: ${{ 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: [resolve, build]
permissions:
contents: read
pull-requests: read
uses: ./.github/workflows/release-notes.yml
with:
release-tag: ${{ needs.resolve.outputs.tag }}
advisory: true
secrets:
LLM_INFERENCE_API_KEY: ${{ secrets.LLM_INFERENCE_API_KEY }}
publish:
name: Publish
needs: [resolve, build]
permissions:
actions: read
contents: write
pull-requests: read
packages: write
id-token: write
attestations: write
artifact-metadata: write
uses: ./.github/workflows/release-publish.yml
with:
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 }}
npm-version: ${{ needs.build.outputs.npm_version }}
is-prerelease: true
secrets:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
qualify:
name: Qualify
needs: [resolve, build]
permissions:
actions: read
contents: read
packages: write
security-events: write
pull-requests: read
uses: ./.github/workflows/release-qualification.yml
with:
release-tag: ${{ needs.resolve.outputs.tag }}
source-sha: ${{ needs.build.outputs.source_sha }}
is-prerelease: true
secrets:
CODEX_SECURITY_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }}
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
notify-prerelease-success:
name: Notify Prerelease Success
needs: [resolve, build, publish, qualify]
if: success()
runs-on: ubuntu-latest
timeout-minutes: 2
permissions: {}
steps:
- name: Send Slack notification
continue-on-error: true
env:
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, needs.resolve.outputs.tag) }}
run: |
set -euo pipefail
if [[ -z "${SLACK_WEBHOOK_URL}" ]]; then
echo "::notice::SLACK_OPENSHELL_TRIAGE_WEBHOOK_URL is unset; skipping Slack notification."
exit 0
fi
jq -n --arg tag "${RELEASE_TAG}" --arg tag_url "${TAG_URL}" \
--arg attempt "${GITHUB_RUN_ATTEMPT}" --arg run_url "${RUN_URL}" \
'{text: (":white_check_mark: OpenShell prerelease <" + $tag_url + "|" + $tag + "> succeeded (attempt " + $attempt + ").\n<" + $run_url + "|View release run and artifacts>"), unfurl_links: false, unfurl_media: false}' |
curl --fail --silent --show-error --connect-timeout 5 --max-time 15 \
--header 'Content-Type: application/json' --data-binary @- "${SLACK_WEBHOOK_URL}"
notify-prerelease-failure:
name: Notify Prerelease Failure
needs: [resolve, build, publish, qualify]
if: failure()
runs-on: ubuntu-latest
timeout-minutes: 2
permissions:
actions: read
defaults:
run:
shell: bash
steps:
- name: Send Slack notification
continue-on-error: true
env:
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 }}
GH_TOKEN: ${{ github.token }}
RUN_URL: ${{ format('{0}/{1}/actions/runs/{2}/attempts/{3}', github.server_url, github.repository, github.run_id, github.run_attempt) }}
run: |
set -euo pipefail
if [[ -z "${SLACK_WEBHOOK_URL}" ]]; then
echo "::notice::SLACK_OPENSHELL_TRIAGE_WEBHOOK_URL is unset; skipping Slack notification."
exit 0
fi
message=":x: OpenShell prerelease ${RELEASE_TAG} failed (attempt ${GITHUB_RUN_ATTEMPT})."
if [[ "${PUBLICATION_RESULT}" == "success" ]]; then
message+=" Published artifacts remain available."
fi
if [[ -n "${SLACK_MENTION}" ]]; then
message+=" ${SLACK_MENTION}"
fi
failed_jobs=$(gh api --paginate \
"repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/attempts/${GITHUB_RUN_ATTEMPT}/jobs?per_page=100" \
--jq '.jobs[] | select(.conclusion == "failure" or .conclusion == "timed_out") | "• <\(.html_url)|\(.name)>"') || {
echo "::warning::Could not list failed jobs; sending the notification without them."
failed_jobs=""
}
if [[ -n "${failed_jobs}" ]]; then
message+=$'\n\nFailed jobs\n'"${failed_jobs}"
fi
jq -n --arg text "${message}" --arg run_url "${RUN_URL}" \
'{text: ($text + "\n<" + $run_url + "|View failed release run>"), unfurl_links: false, unfurl_media: false}' |
curl --fail --silent --show-error --connect-timeout 5 --max-time 15 \
--header 'Content-Type: application/json' --data-binary @- "${SLACK_WEBHOOK_URL}"