diff --git a/.github/workflows/back-merge.yml b/.github/workflows/back-merge.yml index 9bdf4af0..9bb593a3 100644 --- a/.github/workflows/back-merge.yml +++ b/.github/workflows/back-merge.yml @@ -3,6 +3,7 @@ name: Back-merge # After a release on main, sync main back into next so its changelog, manifest, # and version bumps do not drift. No conflict -> push next directly (the App is # an "always" bypass actor on next). Conflict -> open a PR for a human. +# Any other failure -> open a tracking issue so the drift is never silent. on: release: @@ -50,3 +51,17 @@ jobs: --body "Automated back-merge hit conflicts (CHANGELOG / manifest / version files). Resolve manually, then merge into next." \ --repo "${{ github.repository }}" fi + + # Never let a back-merge fail silently: a rejected push or any other error + # opens a tracking issue so a human resyncs main into next. + - name: Open tracking issue on failure + if: failure() + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + gh issue create \ + --repo "${{ github.repository }}" \ + --title "Back-merge main into next failed (run ${{ github.run_id }})" \ + --label "back-merge-failed" \ + --body "The automated back-merge of \`main\` into \`next\` failed, so \`next\` is drifting from the latest release. Resync manually by opening a PR from \`main\` into \`next\`. Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ + || echo "issue creation failed; check the run logs" diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml new file mode 100644 index 00000000..57aac7bc --- /dev/null +++ b/.github/workflows/promote.yml @@ -0,0 +1,49 @@ +name: Promote next to main + +# One intuitive button to ship `next` to `main` the RIGHT way: a rebase-merge +# that preserves every conventional commit, so commitlint passes per commit and +# release-please reads the scopes to bump each plugin. A squash here collapses +# the commits into one (often non-conventional) message and breaks both, which +# is exactly the failure this workflow prevents. +# +# Run it from the Actions tab (Run workflow). It opens the next -> main PR and +# enables rebase auto-merge; CI gates it, then it merges itself. + +on: + workflow_dispatch: + +concurrency: + group: promote + cancel-in-progress: false + +permissions: {} + +jobs: + promote: + name: Open and rebase-merge next into main + runs-on: ubuntu-latest + steps: + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + id: app-token + with: + app-id: ${{ secrets.AIDD_BOT_APP_ID }} + private-key: ${{ secrets.AIDD_BOT_PRIVATE_KEY }} + + - name: Open or reuse the promote PR, enable rebase auto-merge + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + # Reuse an open next -> main PR if one exists, else open one with a + # conventional, squash-safe title. + PR=$(gh pr list --repo "$REPO" --base main --head next --state open --json number --jq '.[0].number' || true) + if [ -z "$PR" ]; then + PR=$(gh pr create --repo "$REPO" --base main --head next \ + --title "chore: promote next to main" \ + --body "Automated promotion of \`next\` to \`main\`. Merged by **rebase** to preserve conventional commits for release-please. Do not squash." \ + | grep -oE '[0-9]+$') + fi + echo "Promote PR: #$PR" + # Rebase auto-merge: GitHub merges it once CI is green. Never squash. + gh pr merge "$PR" --repo "$REPO" --rebase --auto diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b5092644..c2f81617 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -6,5 +6,5 @@ "plugins/aidd-pm": "2.1.0", "plugins/aidd-orchestrator": "2.1.0", "plugins/aidd-refine": "2.1.0", - "plugins/aidd-ui": "4.0.0" + "plugins/aidd-ui": "0.1.0-alpha.0" } diff --git a/docs/RELEASE.md b/docs/RELEASE.md new file mode 100644 index 00000000..2ec5e5d9 --- /dev/null +++ b/docs/RELEASE.md @@ -0,0 +1,58 @@ +# Releasing + +The release pipeline is automated. A human (or an AI agent) only triggers the +promotion; everything after that runs itself. + +## The flow + +``` +next --(promote)--> main --(release-please)--> version PR --(auto-merge)--> tags + GitHub releases + | + '--(back-merge)--> next (keeps next in sync) +``` + +1. **Work lands on `next`** via normal PRs (rebase or squash into `next`, your choice). +2. **Promote `next` to `main`.** Run the **Promote next to main** workflow (Actions tab -> Run workflow). It opens a `next -> main` PR and **rebase-merges** it. +3. **release-please** runs on the push to `main`, opens a version PR (bumps + changelogs), and the CI **auto-merges that version PR** (`--squash --admin`). No human needed. +4. **Tags and GitHub releases** are published per package and for the root. +5. **Back-merge** fires on `release: published` and syncs `main` back into `next` so the changelog and version files do not drift. + +## The one rule: promote with REBASE, never squash + +`next -> main` carries many conventional commits (`feat(scope):`, `fix(scope):`). +Two things depend on them: + +- **commitlint** checks every commit message. A squash collapses them into one + subject taken from the PR title; if that title is not a valid conventional + type (e.g. `release:`), commitlint fails on `main` and **release-please is + skipped** -- no release happens. +- **release-please** reads each commit's type and scope to bump the right plugin + by the right amount. A squash hides them, so it cannot compute the versions. + +So always use the **Promote** workflow (it rebase-merges). If you merge by hand, +use **Rebase and merge**, never **Squash**. The version PR that release-please +opens is its own single commit and is fine to squash -- that one is automated. + +## If a release breaks (recovery) + +Symptom: after a promote, `main` CI is red on **Commitlint** and **Release +Please** is skipped -- usually a squashed, non-conventional promote commit. + +1. An admin temporarily disables the `main protection` ruleset (Settings -> + Rules), force-pushes `main` back to the commit before the bad merge, then + re-enables the ruleset. +2. Re-run the **Promote** workflow (rebase). release-please then cuts the + release normally. + +## Pinning a specific version + +To force a package to a chosen version on the next cut, set `release-as` for it +in `release-please-config.json` (deterministic, overrides any `Release-As:` +commit footer). Remove the pin afterwards so automatic bumps resume. + +## Back-merge failures + +If the back-merge cannot push `next`, it opens an issue labelled +`back-merge-failed`. Resync by opening a `main -> next` PR. The root cause is the +bot app needing an `always` bypass on the `next` ruleset; align that and the +back-merge runs unattended. diff --git a/plugins/aidd-ui/.claude-plugin/plugin.json b/plugins/aidd-ui/.claude-plugin/plugin.json index 47026e16..bbb6bd9d 100644 --- a/plugins/aidd-ui/.claude-plugin/plugin.json +++ b/plugins/aidd-ui/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "aidd-ui", - "version": "4.0.0", + "version": "0.1.0-alpha.0", "description": "ALPHA, not ready for use. UI and UX concern for the AI-Driven Development framework. Use when the user wants to design, review, or improve a frontend interface. Do NOT use for backend-only or non-UI tasks.", "author": { "name": "AI-Driven Dev", diff --git a/plugins/aidd-ui/CHANGELOG.md b/plugins/aidd-ui/CHANGELOG.md index 573abc50..825c32f0 100644 --- a/plugins/aidd-ui/CHANGELOG.md +++ b/plugins/aidd-ui/CHANGELOG.md @@ -1,19 +1 @@ # Changelog - -## [4.0.0](https://github.com/ai-driven-dev/framework/compare/aidd-ui-v0.1.0-alpha.0...aidd-ui-v4.0.0) (2026-06-30) - - -### Features - -* **aidd-ui:** scaffold alpha plugin (0.1.0-alpha.0) ([#319](https://github.com/ai-driven-dev/framework/issues/319)) ([a56792a](https://github.com/ai-driven-dev/framework/commit/a56792afb6584ba17115011721823a2439fb7759)) - - -### Miscellaneous - -* **framework:** release as 4.0.0 ([5b0fc9d](https://github.com/ai-driven-dev/framework/commit/5b0fc9d9116e37abe7ef5dbb5d06438f607475e8)) -* **framework:** trigger ci recheck after history rewrite ([391760e](https://github.com/ai-driven-dev/framework/commit/391760e19eb69fe80e098c3aefc3c527cda2169a)) - - -### Refactoring - -* conform remaining skills to the authoring contract ([#334](https://github.com/ai-driven-dev/framework/issues/334)) ([dcc232a](https://github.com/ai-driven-dev/framework/commit/dcc232a5a7a7bcdf0c477b36399fd4d412685022)) diff --git a/release-please-config.json b/release-please-config.json index 85d6d3ac..1d887fb4 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -85,6 +85,7 @@ }, "plugins/aidd-ui": { "package-name": "aidd-ui", + "release-as": "0.1.0-alpha.0", "extra-files": [ { "type": "json",