mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
* feat: 3-tier release strategy with hotfix, release, and CI workflows Supersedes PRs #1208 and #1210 with a consolidated approach: - VERSIONING.md: Strategy document with 3 release tiers (patch/minor/major) - hotfix.yml: Emergency patch releases to latest - release.yml: Standard release cycle with RC/beta pre-releases to next - auto-branch.yml: Create branches from issue labels - branch-naming.yml: Convention validation (advisory) - pr-gate.yml: PR size analysis and labeling - stale.yml: Weekly cleanup of inactive issues/PRs - dependabot.yml: Automated dependency updates npm dist-tags: latest (stable) and next (pre-release) only, following Angular/Next.js convention. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review findings for release workflow security and correctness - Move all ${{ }} expression interpolation from run: blocks into env: mappings in both hotfix.yml (~12 instances) and release.yml (~16 instances) to prevent potential command injection via GitHub Actions expression evaluation - Reorder rc job in release.yml to run npm ci and test:coverage before pushing the git tag, preventing broken tagged commits when tests fail - Update VERSIONING.md to accurately describe the implementation: major releases use beta pre-releases only, minor releases use rc pre-releases only (no beta-then-rc progression) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * security: harden release workflows — SHA pinning, provenance, dry-run guards Addresses deep adversarial review + best practices research: HIGH: - Fix release.yml rc/finalize: dry_run now gates tag+push (not just npm publish) - Fix hotfix.yml finalize: reorder tag-before-publish (was publish-before-tag) MEDIUM — Security hardening: - Pin ALL actions to SHA hashes (actions/checkout@11bd7190, actions/setup-node@39370e39, actions/github-script@60a0d830) - Add --provenance --access public to all npm publish commands - Add id-token: write permission for npm provenance OIDC - Add concurrency groups (cancel-in-progress: false) on both workflows - Add branch-naming.yml permissions: {} (deny-all default) - Scope permissions per-job instead of workflow-level where possible MEDIUM — Reliability: - Add post-publish verification (npm view + dist-tag check) after every publish - Add npm publish --dry-run validation step before actual publish - Add branch existence pre-flight check in create jobs LOW: - Fix VERSIONING.md Semver Rules: MINOR = "enhancements" not "new features" (aligns with Release Tiers table) Tests: 1166/1166 pass Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * security: pin actions/stale to SHA hash Last remaining action using a mutable version tag. Now all actions across all workflow files are pinned to immutable SHA hashes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address all Copilot review findings on release strategy workflows - Configure git identity in all committing jobs (hotfix + release) - Base hotfix on latest patch tag instead of vX.Y.0 - Add issues: write permission for PR size labeling - Remove stale size labels before adding new one - Make tagging and PR creation idempotent for reruns - Run dry-run publish validation unconditionally - Paginate listFiles for large PRs - Fix VERSIONING.md table formatting and docs accuracy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: clean up next dist-tag after finalize in release and hotfix workflows After finalizing a release, the next dist-tag was left pointing at the last RC pre-release. Anyone running npm install @next would get a stale version older than @latest. Now both workflows point next to the stable release after finalize, matching Angular/Next.js convention. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(ci): address blocking issues in 3-tier release workflows - Move back-merge PR creation before npm publish in hotfix/release finalize - Move version bump commit after test step in rc workflow - Gate hotfix create branch push behind dry_run check - Add confirmed-bug and confirmed to stale.yml exempt labels - Fix auto-branch priority: critical prefix collision with hotfix/ naming Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
86 lines
2.7 KiB
YAML
86 lines
2.7 KiB
YAML
name: Auto-Branch from Issue Label
|
|
|
|
on:
|
|
issues:
|
|
types: [labeled]
|
|
|
|
permissions:
|
|
contents: write
|
|
issues: write
|
|
|
|
jobs:
|
|
create-branch:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 2
|
|
if: >-
|
|
contains(fromJSON('["bug", "enhancement", "priority: critical", "type: chore", "area: docs"]'),
|
|
github.event.label.name)
|
|
steps:
|
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
|
|
- name: Create branch
|
|
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
|
with:
|
|
script: |
|
|
const label = context.payload.label.name;
|
|
const issue = context.payload.issue;
|
|
const number = issue.number;
|
|
|
|
// Generate slug from title
|
|
const slug = issue.title
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-+|-+$/g, '')
|
|
.substring(0, 40);
|
|
|
|
// Map label to branch prefix
|
|
const prefixMap = {
|
|
'bug': 'fix',
|
|
'enhancement': 'feat',
|
|
'priority: critical': 'fix',
|
|
'type: chore': 'chore',
|
|
'area: docs': 'docs',
|
|
};
|
|
const prefix = prefixMap[label];
|
|
if (!prefix) return;
|
|
|
|
// For priority: critical, use fix/critical-NNN-slug to avoid
|
|
// colliding with the hotfix workflow's hotfix/X.Y.Z naming.
|
|
const branch = label === 'priority: critical'
|
|
? `fix/critical-${number}-${slug}`
|
|
: `${prefix}/${number}-${slug}`;
|
|
|
|
// Check if branch already exists
|
|
try {
|
|
await github.rest.git.getRef({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
ref: `heads/${branch}`,
|
|
});
|
|
core.info(`Branch ${branch} already exists`);
|
|
return;
|
|
} catch (e) {
|
|
if (e.status !== 404) throw e;
|
|
}
|
|
|
|
// Create branch from main HEAD
|
|
const mainRef = await github.rest.git.getRef({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
ref: 'heads/main',
|
|
});
|
|
|
|
await github.rest.git.createRef({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
ref: `refs/heads/${branch}`,
|
|
sha: mainRef.data.object.sha,
|
|
});
|
|
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: number,
|
|
body: `Branch \`${branch}\` created.\n\n\`\`\`bash\ngit fetch origin && git checkout ${branch}\n\`\`\``,
|
|
});
|