Skip to content

feat: add release automation script#1992

Open
TerryHowe wants to merge 16 commits into
oras-project:mainfrom
TerryHowe:feature/release-script
Open

feat: add release automation script#1992
TerryHowe wants to merge 16 commits into
oras-project:mainfrom
TerryHowe:feature/release-script

Conversation

@TerryHowe

@TerryHowe TerryHowe commented Mar 4, 2026

Copy link
Copy Markdown
Member

Summary

Adds scripts/release.sh, a bash release automation script that codifies the manual steps from https://oras.land/community/release-process into four repeatable phases.

Phases

  • prep <version> - Validates semver format, checks gh/gpg prerequisites, updates internal/version/version.go (sets Version, clears BuildMetadata), creates branch chore/release-v<version>, commits, pushes, creates a PR titled "bump: tag and release ORAS CLI v<version>" targeting main (or the release branch for patches), and prints the commit SHA with a Slack vote template.

  • tag <version> <sha> - Validates that the commit at the given SHA contains the correct version and cleared BuildMetadata, creates a signed git tag v<version>, pushes the tag, and creates a release branch (e.g. release-X.Y) for new minor versions (patch==0, no pre-release suffix).

  • validate <version> - Polls the release-ghcr and release-github GitHub Actions workflows until they complete, runs make fetch-dist to download artifacts, verifies checksums with shasum, and tests the linux/amd64 binary reports the expected version.

  • publish <version> - Runs make sign to GPG-sign artifacts, verifies all GPG signatures, uploads .asc files to the GitHub release, appends signing key verification instructions to release notes, publishes the release (--draft=false), triggers the snap workflow, cleans up _dist/, and prints a post-release Slack template.

Features

  • --dry-run flag for safe testing
  • ORAS_REMOTE env var to configure the upstream remote (default: upstream)
  • Color-coded output for readability
  • Confirmation prompts before all destructive actions
  • Slack templates for vote and announcement

Makefile Targets

Also adds convenience Makefile targets: release-prep, release-tag, release-validate, release-publish.

Test plan

  • Run scripts/release.sh --help to verify usage output
  • Run scripts/release.sh --dry-run prep 1.3.0 to verify prep phase logic
  • Run scripts/release.sh --dry-run tag 1.3.0 abc1234 to verify tag phase logic
  • Run scripts/release.sh --dry-run validate 1.3.0 to verify validate phase logic
  • Run scripts/release.sh --dry-run publish 1.3.0 to verify publish phase logic
  • Verify make help shows the new release targets

@codecov

codecov Bot commented Mar 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.27%. Comparing base (ce35c7f) to head (fc91d0e).
⚠️ Report is 13 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1992      +/-   ##
==========================================
+ Coverage   87.26%   87.27%   +0.01%     
==========================================
  Files         138      138              
  Lines        5465     5486      +21     
==========================================
+ Hits         4769     4788      +19     
- Misses        415      417       +2     
  Partials      281      281              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new scripts/release.sh automation script to codify the ORAS CLI release process into repeatable phases, and exposes those phases via make targets for convenience.

Changes:

  • Added scripts/release.sh implementing prep, tag, validate, and publish release phases (with --dry-run support).
  • Added Makefile targets (release-prep, release-tag, release-validate, release-publish) to invoke the script.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
scripts/release.sh New bash script that automates version bump PR creation, tagging, CI/artifact validation, and publishing/signing steps.
Makefile Adds convenience targets to run the release script phases via make.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh
Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh
Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh Outdated

@sabre1041 sabre1041 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks really good. one small comment

Comment thread Makefile Outdated
@TerryHowe TerryHowe added this to the v1.4.0 milestone May 24, 2026
TerryHowe and others added 16 commits June 28, 2026 06:20
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
- Extract check_prerequisites() as shared function called from both
  do_prep and do_tag, ensuring GPG/gh/remote are validated before tagging
- Add dirty working tree guard in do_prep before creating branch
- Add portable checksum verification: prefer sha256sum over shasum with
  fallback and fatal error if neither is available
- Use make SHELL=/bin/bash sign to avoid POSIX brace glob issue
- Fix .asc upload to avoid glob expansion in dry-run mode
- Fix snap workflow: use release-snap.yml with required version and
  isStable fields, pass --ref for correct trigger

Signed-off-by: Terry Howe <terrylhowe@gmail.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
- Replace make fetch-dist with gh release download in validate phase
  so artifact fetching works against draft releases (curl on the public
  /releases/download/ URL returns 404 for drafts)
- Add ORAS_REPO variable to Makefile so the repo is not hardcoded
- Add gh CLI prerequisite check to fetch-dist target with install URL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
- Replace make sign with a direct gpg loop covering all artifact types
  including .zip (make sign only covered *.{gz,txt})
- Fail immediately if any gpg signing fails instead of swallowing errors
- Scope verify and upload globs to oras_<version>_* to avoid picking up
  leftover files from prior releases
- Add --clobber to gh release upload so publish is safely retryable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
Bash arithmetic (( expr )) exits with code 1 when the expression
evaluates to 0. Post-increment (( n++ )) returns the old value, so
the first increment from 0 to 1 silently kills the script under
set -euo pipefail. Use $(( n + 1 )) assignment instead.

Affected: attempt counter in validate and sig_count in publish.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
gpg consumes stdin during signing, leaving confirm's read at EOF which
silently treats the response as empty (N) and aborts. Reading from
/dev/tty ensures interactive prompts always reach the terminal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
- Remove all confirm() calls and the confirm function itself; the script
  now runs non-interactively without pausing for user input
- Replace the branch warning in prep with a hard failure: the current
  branch must be 'main' or 'release-X.Y' where X.Y matches the
  major.minor of the version being released (e.g. v1.3.2 requires
  main or release-1.3)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
validate and publish now read the version from internal/version/version.go
when no version argument is supplied, so running just
'scripts/release.sh validate' or 'scripts/release.sh publish' works
from the release branch without repeating the version string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
When running prep from 'main', the version's major.minor must match
MAIN_RELEASE_VERSION (default 2.0). This prevents accidentally cutting
a 1.x patch release from main. Override with ORAS_MAIN_RELEASE_VERSION
when the next main-branch series changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
…N from validate/publish make targets

- Remove redundant *Changelog:* line from the publish Slack announcement
  (it was the same URL as *Release:*)
- Drop $(VERSION) from release-validate and release-publish Makefile
  targets since the script now reads the version from version.go

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
… docs

- Auto-detect the canonical oras-project/oras remote by URL instead of
  assuming it is named 'upstream'; ORAS_REMOTE still overrides.
- Target the release branch the PR is cut from (main or release-X.Y) so
  patch-release PRs no longer always target main.
- Match the documented vote requirement (super-majority of ORAS maintainer
  approval) instead of the unspecified 72h / 3-binding-vote / veto rules.

Signed-off-by: Terry Howe <terrylhowe@gmail.com>
Match the documented release note: use the full 40-char GPG fingerprint and
attribute the signer via their GitHub handle (from the authenticated gh user),
linking to their key at github.com/<handle>.gpg. Falls back gracefully when the
handle cannot be resolved.

Signed-off-by: Terry Howe <terrylhowe@gmail.com>
parse_global_flags ran inside a command substitution, so DRY_RUN=true was set
only in the subshell and lost. --dry-run was silently ignored and prep ran for
real (creating branches/PRs). Parse flags into a POSITIONAL_ARGS global in the
current shell instead, so DRY_RUN sticks.

Also point the release vote message at the #oras-maintainers Slack channel.

Signed-off-by: Terry Howe <terrylhowe@gmail.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
@TerryHowe
TerryHowe force-pushed the feature/release-script branch from ea94983 to fc91d0e Compare June 28, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants