77 lines
3.7 KiB
YAML
77 lines
3.7 KiB
YAML
# Create a GitHub Release entry (the `…/releases` page) when a version tag is
|
|
# pushed. This is METADATA ONLY — it does NOT build or publish any installable
|
|
# artifact. PyPI publishing lives in the central secure-release repo
|
|
# (databricks/secure-public-registry-releases-eng → `omnigent` workflow), on
|
|
# hardened runners with OIDC Trusted Publishing and a mandatory dependency
|
|
# scan. Keeping those concerns separate is deliberate (see RELEASING.md):
|
|
#
|
|
# * This job runs NO project or third-party code — no build, no `pip
|
|
# install`/`npm ci`, no tests. Its only action is SHA-pinned
|
|
# `actions/checkout` plus `gh release create`. A malicious tagged commit
|
|
# therefore cannot execute anything here.
|
|
# * It uses the ephemeral `GITHUB_TOKEN` (no stored secret / PAT). The single
|
|
# elevated scope, `contents: write`, is the minimum GitHub requires to
|
|
# create a release and nothing else in the job uses it.
|
|
# * It attaches NO wheels. The release carries only a placeholder body and the
|
|
# source tarball GitHub auto-attaches, so PyPI (the scanned, securely
|
|
# published channel) stays the single source of installable artifacts.
|
|
# * The body is a short placeholder — the curated notes are filled in by
|
|
# `draft-release-notes.yml` (which fires after this on `workflow_run`). We do
|
|
# NOT use `--generate-notes`: we write our own notes, and for a large
|
|
# PR range GitHub's auto-notes overflow the 125k release-body limit.
|
|
# * The release is created as a DRAFT: a human verifies/edits the drafted
|
|
# notes and publishes it (ideally after the prod PyPI publish lands), so a
|
|
# bot never makes a public release on its own.
|
|
name: GitHub Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
# Version tags only (v0.2.0, v0.2.0rc1, …) — `v[0-9]*` avoids triggering
|
|
# on non-release tags like `v-infra-*`.
|
|
- "v[0-9]*"
|
|
|
|
# Least privilege: creating a release requires `contents: write`; nothing here
|
|
# needs anything more.
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
draft-release:
|
|
# Inert in forks / mirrors — only the canonical repo should cut releases.
|
|
if: github.repository == 'omnigent-ai/omnigent'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
|
|
- name: Draft release with a placeholder body
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
TAG: ${{ github.ref_name }}
|
|
run: |
|
|
# Rerun-safe: if a release for this tag already exists (a rerun, a
|
|
# deleted-and-re-pushed tag, or a manual release), skip instead of
|
|
# failing the job. An `if` so this can't trip `set -e`.
|
|
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
|
echo "Release $TAG already exists — skipping." | tee -a "$GITHUB_STEP_SUMMARY"
|
|
exit 0
|
|
fi
|
|
# rc / dev / alpha / beta tags are flagged as pre-releases.
|
|
pre=""
|
|
case "$TAG" in
|
|
*rc*|*dev*|*a[0-9]*|*b[0-9]*) pre="--prerelease" ;;
|
|
esac
|
|
# $pre is intentionally UNQUOTED: it word-splits to nothing when empty,
|
|
# and is only ever "" or "--prerelease" (set just above, never from
|
|
# external input). Quoting it would pass an empty positional arg.
|
|
gh release create "$TAG" \
|
|
--repo "$GITHUB_REPOSITORY" \
|
|
--draft \
|
|
--verify-tag \
|
|
--notes "_Release notes are being drafted automatically — check back shortly._" \
|
|
--title "$TAG" \
|
|
$pre
|
|
echo "Drafted release $TAG — curated notes will be filled in by draft-release-notes.yml; review and publish from the Releases page." \
|
|
| tee -a "$GITHUB_STEP_SUMMARY"
|