Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/back-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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"
49 changes: 49 additions & 0 deletions .github/workflows/promote.yml
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +40 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Handle the missing promote PR before merging

When there is no open next -> main PR yet, this assignment does not become empty: gh --jq uses jq query syntax per the GitHub CLI formatting docs, and jq -r '.[0].number' on [] renders the literal null. That makes [ -z "$PR" ] false, so the normal first run skips gh pr create and then calls gh pr merge null, causing the new promote button to fail unless someone already opened the PR; use a fallback such as .[0].number // empty or explicitly handle null.

Useful? React with 👍 / 👎.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use admin override when enabling promote merge

After a promote PR exists, this still asks GitHub to do a normal auto-merge. In the checked main ruleset, every PR needs a code-owner review, and the existing release workflow documents that this same App-token merge is refused by the base-branch policy unless gh pr merge uses --admin; the gh CLI docs also distinguish --auto (wait for requirements) from --admin (merge despite unmet requirements). As written, the workflow will leave the bot-created promote PR waiting for review/requirements instead of self-merging after CI.

Useful? React with 👍 / 👎.

2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Move the aidd-ui release boundary before re-cutting

Changing the tip manifest back to 0.1.0-alpha.0 is not enough to make release-please rebuild the deleted 4.0.0 release from the original aidd-ui changes: the last merged release PR already recorded plugins/aidd-ui as 4.0.0, and manifest mode normally uses that release PR as the previous marker. On the next run, the re-cut will be based only on commits after that release PR (the reset/pin commits), so the new alpha release notes/changelog will miss the original scaffold changes unless the release boundary is also moved (for example with last-release-sha or an appropriate tag/restore strategy).

Useful? React with 👍 / 👎.

}
58 changes: 58 additions & 0 deletions docs/RELEASE.md
Original file line number Diff line number Diff line change
@@ -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).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not allow squash merges into next

This step says squashing PRs into next is fine, but the promote flow can only preserve the commits that are already on next. If a multi-scope change is squashed into one generic PR-title commit before promotion, the later rebase into main still hides the original feat(scope): / fix(scope): commits that release-please needs to bump the right plugins, exactly the failure mode described below in this same document.

Useful? React with 👍 / 👎.

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.
2 changes: 1 addition & 1 deletion plugins/aidd-ui/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
18 changes: 0 additions & 18 deletions plugins/aidd-ui/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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))
1 change: 1 addition & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
},
"plugins/aidd-ui": {
"package-name": "aidd-ui",
"release-as": "0.1.0-alpha.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add aidd-ui to released plugin uploads

With this release-as pin, the next Release Please run is expected to release plugins/aidd-ui, but the release attachment job only matrices aidd-context, aidd-dev, aidd-vcs, aidd-pm, aidd-orchestrator, and aidd-refine in .github/workflows/ci.yml. When paths_released contains plugins/aidd-ui, no matrix cell matches it, so the new aidd-ui-v0.1.0-alpha.0 GitHub release is created without the per-plugin zip documented for plugin releases.

Useful? React with 👍 / 👎.

"extra-files": [
{
"type": "json",
Expand Down