Skip to content

ci: add hotfix workflow; align workflow names#2307

Merged
alandtse merged 5 commits into
community-shaders:devfrom
alandtse:ci/hotfix-release-workflow
May 10, 2026
Merged

ci: add hotfix workflow; align workflow names#2307
alandtse merged 5 commits into
community-shaders:devfrom
alandtse:ci/hotfix-release-workflow

Conversation

@alandtse
Copy link
Copy Markdown
Collaborator

@alandtse alandtse commented May 9, 2026

Summary

Adds release-hotfix.yaml — a workflow_dispatch entry point that automates the prep stages of the wiki's Hotfix Release Process (steps 2–3) without touching dev. The standard release pipeline from step 4 onward (manual Release: Semantic Version → tagged build → publish → Nexus) is unchanged.

What it does

  • Auto-detects the latest stable tag (filters out -rc/-pr/-alpha/-beta); optional release_line input pins a specific line (e.g. 1.5).
  • Derives hotfix/X.Y.x from the tag, creating the branch on origin if it does not exist.
  • Cherry-picks commits from dev onto a fresh hotfix-staging/X.Y.x-<run_id> branch:
    • scope dropdown: fix-only (default) / fix+perf / fix+perf+chore. Breaking changes always excluded.
    • Optional commits input accepts an explicit SHA list, bypassing the type filter.
    • git cherry patch-id dedup handles re-runs and prior patches already on the maintenance branch.
  • Opens a PR staging → hotfix/X.Y.x so the existing pr-checks.yaml builds the candidate and publishes a vX.Y.Z-prNNNN prerelease for testing.
  • dry_run: true (default) previews the plan in the run summary without any remote writes.

Failure / rerun semantics

Scenario Behavior
Test fails, rerun Prior open hotfix-staging/X.Y.x-* PRs auto-closed, branches deleted, fresh PR opened.
New fix added on dev mid-flight Same — supersedes the prior candidate.
Cherry-pick conflict Conflict aborted; commit listed in run summary and PR body with resolution instructions; remaining picks proceed.
Picked = 0 No remote pushes; maintenance branch and staging branch only exist locally in the runner and are discarded.
Second hotfix after publish Auto-detected base tag advances to the just-published patch; new candidate built off it.

Pipeline integration

release-hotfix.yaml (this PR)
  → pr-checks.yaml          (auto: build, publish vX.Y.Z-prNNNN prerelease)
  → human                   (install, verify, merge candidate PR)
  → Release: Semantic Version (manual: dispatch on hotfix/X.Y.x, release_type=stable)
  → release-build.yaml      (auto: build on tag, create draft)
  → human                   (review + publish draft)
  → nexus-upload.yaml       (auto: dry-run on publish)
  → human                   (Nexus: Upload Release with dry_run=false)

Steps 4 onward are identical to the documented manual hotfix flow.

Notes

  • Reuses RELEASE_PAT (same secret as release-semantic.yaml).
  • Hotfix branches remain ephemeral per the wiki: created on demand, deletable post-release. The workflow recreates them as needed.

Test plan

  • Dry-run on dev (default release_line empty, scope: fix-only, dry_run: true) — verify run summary shows expected base tag, branch names, and candidate list with no remote pushes.
  • Real run with dry_run: false against a low-stakes line — verify staging branch + PR appear, prerelease build fires, candidate is installable.
  • Rerun while prior PR is still open — verify prior PR is closed with "superseded" comment and prior staging branch is deleted.
  • Run with commits input set to a specific SHA — verify only that commit is picked.
  • Trigger a deliberate cherry-pick conflict (e.g. via commits input with a known-conflicting SHA) — verify it surfaces in PR body and the run continues.
  • Merge a candidate PR, then dispatch Release: Semantic Version with release_type=stable on the hotfix branch — verify the standard pipeline produces the expected patch tag and draft release.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added a manual "Release: Hotfix Candidate" workflow to plan and prepare hotfix staging branches, select commit scopes or specific SHAs, run dry-run previews, cherry-pick eligible commits (excluding breaking changes), and open a labeled staging→maintenance PR when applicable.
    • Renamed several workflows for clearer scope: "Maint: Cleanup Obsolete Releases", "Maint: TODO to Issue", "Maint: Update Buffers Wiki", "PR: Lint", "PR: WIP", and "Release: Semantic Version".

Review Change Stack

Adds release-hotfix.yaml — a workflow_dispatch entry point that prepares
a maintenance release candidate without touching dev:

- Auto-detects the latest stable tag, derives `hotfix/X.Y.x` from it
  (creates the branch from the tag if it does not yet exist on origin).
- Cherry-picks eligible commits from `dev` onto a fresh
  `hotfix-staging/X.Y.x-<run_id>` branch. Selection is via a
  conventional-commit type filter (fix-only / fix+perf / fix+perf+chore;
  breaking changes always excluded) or an explicit SHA list. `git cherry`
  patch-id dedup handles re-runs cleanly.
- Opens a PR `staging -> hotfix/X.Y.x` so the existing pr-checks.yaml
  pipeline builds the candidate and publishes a `vX.Y.Z-prNNNN`
  prerelease for verification.
- Re-running supersedes prior open candidates: open hotfix-staging PRs
  for the same line are auto-closed and their branches deleted.
- On no eligible commits or dry-run, no remote pushes happen.

Pipeline integration matches the wiki's documented hotfix flow from
step 4 onward — once the candidate PR is merged, a maintainer dispatches
Release: Semantic Version with release_type=stable on hotfix/X.Y.x and
the standard release-build / publish / Nexus pipeline takes over.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new "Hotfix Release" GitHub Actions workflow that selects a base tag, derives maintenance/staging branches, cherry-picks eligible commits (by scope or explicit SHAs) into a staging branch, reports results, and optionally pushes branches, closes superseded staging PRs, and opens a labeled hotfix PR.

Changes

Hotfix Release Workflow

Layer / File(s) Summary
Workflow Inputs & Permissions
.github/workflows/release-hotfix.yaml
Defines workflow_dispatch inputs: release_line, scope (fix-only / fix+perf / fix+perf+chore), commits, and dry_run; sets concurrency and repository/PR permissions.
Checkout & Git Identity
.github/workflows/release-hotfix.yaml
Checks out full repo history, sets git user/email, and configures use of the release PAT for git/PR operations.
Stable Tag & Branch Derivation
.github/workflows/release-hotfix.yaml
Computes the base stable v* tag (auto-detected or filtered by release_line), derives hotfix/X.Y.x maintenance branch and uniquely named hotfix-staging/X.Y.x-<run_id> staging branch; exports values.
Maintenance Branch Setup
.github/workflows/release-hotfix.yaml
Ensures maintenance branch exists by fetching from origin or creating it locally from the stable tag; records whether it pre-existed.
Cherry-pick & Staging Branch
.github/workflows/release-hotfix.yaml
Creates staging branch and cherry-picks candidate commits (explicit SHAs or filtered origin/dev by conventional-commit type), excludes breaking changes, aborts/skips conflicting cherry-picks, and records picked/dedup/conflict/skipped counts.
Reporting & Metadata
.github/workflows/release-hotfix.yaml
Writes GITHUB_STEP_SUMMARY with a metadata table and conditional lists (picked, already-applied, skipped-breaking, conflicts); exports counts and a human-readable source_desc.
Superseded PR Cleanup
.github/workflows/release-hotfix.yaml
When not dry_run and commits were picked, finds open staging PRs matching the staging prefix for the same maintenance base, posts superseded comments, closes them, and deletes their branches.
Push Branches
.github/workflows/release-hotfix.yaml
Pushes maintenance branch only if it was newly created; pushes staging branch with upstream when commits were picked and not dry-run.
Hotfix PR Creation
.github/workflows/release-hotfix.yaml
When not dry-run and picked_count > 0, creates a PR from staging into maintenance with a generated body summarizing picked/dedup/skipped/conflict lists and applies the hotfix label.
Empty Commits Handler
.github/workflows/release-hotfix.yaml
Emits a notice and stops when no eligible commits were found (picked_count == 0).
Workflow Display Name Updates
.github/workflows/maint-cleanup-releases.yaml, .github/workflows/maint-todo-issues.yaml, .github/workflows/maint-update-wiki.yaml, .github/workflows/pr-lint.yaml, .github/workflows/pr-wip.yaml, .github/workflows/release-semantic.yaml
Top-level name strings updated to use consistent Maint:, PR:, and Release: prefixes; no other workflow behavior changed.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ActionsRunner
  participant GitRemote
  participant GitHubAPI
  User->>ActionsRunner: Manually dispatch workflow (inputs)
  ActionsRunner->>GitRemote: fetch tags/branches, checkout
  ActionsRunner->>GitRemote: create/checkout maintenance & staging branches
  ActionsRunner->>GitRemote: cherry-pick commits sequentially
  ActionsRunner->>GitHubAPI: list/open/close PRs, push branches, create PR
  GitHubAPI-->>User: return PR URL / comments
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • davo0411
  • SkrubbySkrubInAShrub
  • doodlum

Poem

🐰 I hop from tag to staging tree,
I pluck the fixes one, two, three,
I skip the breaks and note each try,
Close old PRs and push the sky,
A hotfix blooms—then I hop by.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely summarizes the two main changes: adding a hotfix workflow and standardizing workflow display names.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

No actionable suggestions for changed features.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release-hotfix.yaml:
- Around line 114-116: The workflow currently accepts EXPLICIT_COMMITS verbatim
into CANDIDATES and sets SOURCE_DESC, which bypasses the existing safety checks;
instead, parse EXPLICIT_COMMITS into an initial list but then run each candidate
through the same validation/filtering path used for normal discovery (i.e., the
code that enforces the breaking-change exclusion and patch-id deduplication)
before finalizing CANDIDATES and SOURCE_DESC. Concretely, replace the direct
mapfile assignment with logic that splits EXPLICIT_COMMITS, feeds each SHA into
the existing validation functions/loops (the same checks that normally filter
discovered commits), and only append validated SHAs to CANDIDATES so SOURCE_DESC
reflects the count of post-filtered commits.
- Around line 50-52: Add a concurrency section to the hotfix job to serialize
runs that target the same hotfix line: under the job named "hotfix" add a
concurrency.group that derives from the hotfix line identifier (for example
using the dispatch payload or branch/ref like github.event.client_payload.line
or github.ref) so concurrent dispatches for the same line share a group, and set
cancel-in-progress as appropriate to avoid racing deletions; update the job
"hotfix" configuration to use that concurrency group so only one candidate for a
given line runs at a time.
- Around line 124-129: The filter only inspects the subject (SUBJECT) so commits
with a BREAKING CHANGE: footer slip through; update the loop that builds
CANDIDATES to fetch the full commit body (e.g., FULL_MSG=$(git log -1
--pretty=%B "${sha}")), use that full message for the TYPE_RE match (or still
test the subject extracted from FULL_MSG) and explicitly skip any commit where
FULL_MSG contains a BREAKING CHANGE: trailer (case-sensitive or anchored, e.g.,
grep -qE '^BREAKING CHANGE:'), so CANDIDATES only includes non-breaking commits;
refer to the variables TYPE_RE, UNMERGED, SUBJECT (replace/augment with
FULL_MSG) and the for sha in "${UNMERGED[@]}" loop when making this change.
- Around line 71-79: The grep -Ev in the BASE_TAG assignments can return exit
code 1 when there are no matches and, because of set -euo pipefail, will abort
the script before your explicit empty-BAS E_TAG check; change the two command
substitutions that set BASE_TAG (the branches that run git tag ... | grep -Ev --
'-(rc|pr|alpha|beta)' ...) to make the grep step non-fatal (for example append a
fallthrough like "|| true" to the grep pipeline) so the command substitution
always returns, then let the existing if [[ -z "${BASE_TAG}" ]] block handle the
no-stable-tag case; references: RELEASE_LINE, BASE_TAG, set -euo pipefail, grep
-Ev.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 344bb2fc-f5a7-455f-ab65-b09894d133b5

📥 Commits

Reviewing files that changed from the base of the PR and between 58d53e3 and 367e4d9.

📒 Files selected for processing (1)
  • .github/workflows/release-hotfix.yaml

Comment thread .github/workflows/release-hotfix.yaml
Comment thread .github/workflows/release-hotfix.yaml
Comment thread .github/workflows/release-hotfix.yaml Outdated
Comment thread .github/workflows/release-hotfix.yaml Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

✅ A pre-release build is available for this PR:
Download

alandtse added 4 commits May 9, 2026 14:20
- Add `concurrency` group keyed on the hotfix line so simultaneous
  dispatches for the same line queue instead of racing on PR-close +
  branch-delete + push.
- Make tag-detection grep tolerate no matches (`|| true`) so the
  explicit empty-BASE_TAG error path is reached under `set -e`.
- Apply a unified breaking-change filter to both explicit-SHA and
  scope-discovered paths: catches `type!:` subjects AND
  `BREAKING CHANGE:` / `BREAKING-CHANGE:` footers.
- Detect already-applied patches at runtime (cherry-pick produces an
  empty result) and report them as a separate `dedup` category instead
  of mislabeling them as conflicts. Works for both selection paths.
- Surface breaking-skipped and dedup categories in the run summary and
  PR body alongside picked / conflicts.

Addresses CodeRabbit feedback on community-shaders#2307.
Bash 5.2 (`ubuntu-latest`'s default) refuses inline regex with a
parenthesized group inside `[[ =~ ]]`:

  syntax error in conditional expression: unexpected token `)'
  near `^[a-zA-Z]+(\([^)]+\))?'

Moves the pattern into BREAKING_SUBJECT_RE so the parser sees a plain
variable reference. Caught by exercising the script locally against a
v1.5.1 worktree before dispatching the workflow on CI.
Aligns with release-build.yaml's 'Release: ...' colon style so all
release workflows cluster together alphabetically in the Actions
sidebar. 'Candidate' disambiguates from the release-cutting step
(Release: Semantic Version) — this workflow only prepares the PR.
All workflow display names now follow the existing `<Group>: <Action>`
pattern matching the file prefix, so they cluster alphabetically in the
Actions sidebar:

- Cleanup Obsolete Releases (PRs and RCs) → Maint: Cleanup Obsolete Releases
- Run TODO to Issue                        → Maint: TODO to Issue
- Update Buffers Wiki                      → Maint: Update Buffers Wiki
- Lint PR                                  → PR: Lint
- WIP                                      → PR: WIP
- Semantic Release                         → Release: Semantic Version
  (matches the wiki's documented label for this workflow)

The release-semantic.yaml step name "Semantic Release" is unchanged —
that's a step inside the job, not a workflow display name.
@alandtse alandtse changed the title ci: add automated hotfix release candidate workflow ci: add hotfix workflow; align workflow names May 10, 2026
@alandtse alandtse merged commit fe589ec into community-shaders:dev May 10, 2026
27 checks passed
@alandtse alandtse deleted the ci/hotfix-release-workflow branch May 10, 2026 05:27
ParticleTroned pushed a commit to ParticleTroned/skyrim-community-shaders that referenced this pull request May 15, 2026
ParticleTroned pushed a commit to ParticleTroned/skyrim-community-shaders that referenced this pull request May 16, 2026
IgorAlanAlbuquerque pushed a commit to IgorAlanAlbuquerque/skyrim-community-shaders that referenced this pull request May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants