From 229b61283c5cefe7b3336af6a65b4c95c60d48a5 Mon Sep 17 00:00:00 2001 From: Lam Nguyen Date: Tue, 7 Jul 2026 17:34:23 +0700 Subject: [PATCH] =?UTF-8?q?chore(ci):=20flatten=20gitflow=20to=20develop?= =?UTF-8?q?=20=E2=86=92=20master?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the develop → main/ → stable stabilization layer (solo maintainer; the ceremony isn't earning its keep). New release train is develop → master, with master as the single release branch. Changes: - branch-policy.yml: allow only develop/hotfix → master (was stable ← main/hotfix). Triggers on PRs to master. - bump-version-on-pr-to-{stable→master}.yml: trigger on PR to master, gate on head_ref == 'develop'. Compares develop vs master; auto-bumps patch only if develop isn't already ahead (manual minor/major bumps set on develop pass through). - release-on-merge-to-{stable→master}.yml: trigger on merge to master, checkout master, tag vX.Y.Z + GitHub Release targeting master. - pr-lint-and-test.yml: trigger on [develop, master] (was [develop, stable, main, main/**]). - docs/branching-strategy.md: rewrite for the two-branch model. - pyproject.toml: 0.1.3 → 0.2.0 (next release is a minor bump). Follow-up (not in this PR): rename the stable branch → master via `gh api .../branches/stable/rename`. The existing ruleset is keyed on ~DEFAULT_BRANCH so it auto-covers master without reconfiguration. Orphaned asset: docs/assets/gitflow-vertical-branching.svg still depicts the old 5-branch model and is no longer referenced — safe to delete later. --- .github/workflows/branch-policy.yml | 20 ++---- ...e.yml => bump-version-on-pr-to-master.yml} | 30 ++++---- .github/workflows/pr-lint-and-test.yml | 2 +- ...ble.yml => release-on-merge-to-master.yml} | 10 +-- docs/branching-strategy.md | 70 +++++++++---------- pyproject.toml | 2 +- 6 files changed, 60 insertions(+), 74 deletions(-) rename .github/workflows/{bump-version-on-pr-to-stable.yml => bump-version-on-pr-to-master.yml} (67%) rename .github/workflows/{release-on-merge-to-stable.yml => release-on-merge-to-master.yml} (88%) diff --git a/.github/workflows/branch-policy.yml b/.github/workflows/branch-policy.yml index 8fda053..f58fd8e 100644 --- a/.github/workflows/branch-policy.yml +++ b/.github/workflows/branch-policy.yml @@ -2,9 +2,7 @@ name: Enforce branch flow on: pull_request: branches: - - stable - - main - - 'main/**' + - master jobs: check-branch-policy: @@ -17,19 +15,9 @@ jobs: echo "PR: $SOURCE → $TARGET" - # stable ← main, main/*, hotfix/* - # main ← develop, hotfix/* - # main/* ← develop, hotfix/* - if [[ "$TARGET" == "stable" ]]; then - PATTERN="^(main(/.*)?|hotfix/.+)$" - ALLOWED="main, main/*, hotfix/*" - elif [[ "$TARGET" == "main" || "$TARGET" == main/* ]]; then - PATTERN="^(develop|hotfix/.+)$" - ALLOWED="develop, hotfix/*" - else - echo "✅ No branch policy for target '$TARGET'" - exit 0 - fi + # master ← develop, hotfix/* + PATTERN="^(develop|hotfix/.+)$" + ALLOWED="develop, hotfix/*" if [[ "$SOURCE" =~ $PATTERN ]]; then echo "✅ '$SOURCE' → '$TARGET' is allowed" diff --git a/.github/workflows/bump-version-on-pr-to-stable.yml b/.github/workflows/bump-version-on-pr-to-master.yml similarity index 67% rename from .github/workflows/bump-version-on-pr-to-stable.yml rename to .github/workflows/bump-version-on-pr-to-master.yml index 3523409..7e2e5c2 100644 --- a/.github/workflows/bump-version-on-pr-to-stable.yml +++ b/.github/workflows/bump-version-on-pr-to-master.yml @@ -1,14 +1,15 @@ -name: Bump version on PR to stable +name: Bump version on PR to master on: pull_request: types: [opened, synchronize] - branches: [stable] + branches: [master] jobs: bump-version: - # Only run for main/* branches - if: startsWith(github.head_ref, 'main/') + # Only run for the develop → master release train. + # Hotfix branches bump their version manually before opening the PR. + if: github.head_ref == 'develop' runs-on: ubuntu-latest permissions: contents: write @@ -23,20 +24,21 @@ jobs: - name: Read versions and compare id: compare run: | - # Read version from source branch (main/*) + # Read version from source branch (develop) SOURCE_VERSION=$(grep -m1 '^version' pyproject.toml | sed 's/.*"\(.*\)"/\1/') echo "source=$SOURCE_VERSION" >> "$GITHUB_OUTPUT" - # Read version from stable - git fetch origin stable - STABLE_VERSION=$(git show origin/stable:pyproject.toml | grep -m1 '^version' | sed 's/.*"\(.*\)"/\1/') - echo "stable=$STABLE_VERSION" >> "$GITHUB_OUTPUT" + # Read version from master + git fetch origin master + MASTER_VERSION=$(git show origin/master:pyproject.toml | grep -m1 '^version' | sed 's/.*"\(.*\)"/\1/') + echo "master=$MASTER_VERSION" >> "$GITHUB_OUTPUT" - echo "Source: $SOURCE_VERSION | Stable: $STABLE_VERSION" + echo "Source: $SOURCE_VERSION | Master: $MASTER_VERSION" - # Compare using sort -V (version sort) - HIGHER=$(printf '%s\n%s' "$SOURCE_VERSION" "$STABLE_VERSION" | sort -V | tail -1) - if [ "$SOURCE_VERSION" != "$STABLE_VERSION" ] && [ "$SOURCE_VERSION" = "$HIGHER" ]; then + # Compare using sort -V (version sort). If develop is already ahead + # (e.g. a manual minor/major bump), no patch bump is needed. + HIGHER=$(printf '%s\n%s' "$SOURCE_VERSION" "$MASTER_VERSION" | sort -V | tail -1) + if [ "$SOURCE_VERSION" != "$MASTER_VERSION" ] && [ "$SOURCE_VERSION" = "$HIGHER" ]; then echo "needs_bump=false" >> "$GITHUB_OUTPUT" echo "Source is already ahead, no bump needed" else @@ -48,7 +50,7 @@ jobs: if: steps.compare.outputs.needs_bump == 'true' id: next run: | - IFS='.' read -r MAJOR MINOR PATCH <<< "${{ steps.compare.outputs.stable }}" + IFS='.' read -r MAJOR MINOR PATCH <<< "${{ steps.compare.outputs.master }}" PATCH=$((PATCH + 1)) echo "version=$MAJOR.$MINOR.$PATCH" >> "$GITHUB_OUTPUT" echo "Next version: $MAJOR.$MINOR.$PATCH" diff --git a/.github/workflows/pr-lint-and-test.yml b/.github/workflows/pr-lint-and-test.yml index 59f52bf..627f9dd 100644 --- a/.github/workflows/pr-lint-and-test.yml +++ b/.github/workflows/pr-lint-and-test.yml @@ -5,7 +5,7 @@ name: PR Lint & Test on: pull_request: - branches: [develop, stable, main, 'main/**'] + branches: [develop, master] workflow_dispatch: jobs: diff --git a/.github/workflows/release-on-merge-to-stable.yml b/.github/workflows/release-on-merge-to-master.yml similarity index 88% rename from .github/workflows/release-on-merge-to-stable.yml rename to .github/workflows/release-on-merge-to-master.yml index a60e1ea..b283571 100644 --- a/.github/workflows/release-on-merge-to-stable.yml +++ b/.github/workflows/release-on-merge-to-master.yml @@ -1,9 +1,9 @@ -name: Release on merge to stable +name: Release on merge to master on: pull_request: types: [closed] - branches: [stable] + branches: [master] jobs: release: @@ -13,10 +13,10 @@ jobs: contents: write steps: - - name: Checkout stable + - name: Checkout master uses: actions/checkout@v4 with: - ref: stable + ref: master fetch-depth: 0 - name: Read version from pyproject.toml @@ -37,4 +37,4 @@ jobs: fi git tag "$TAG" git push origin "$TAG" - gh release create "$TAG" --title "$TAG" --generate-notes --target stable + gh release create "$TAG" --title "$TAG" --generate-notes --target master diff --git a/docs/branching-strategy.md b/docs/branching-strategy.md index 165895e..2032241 100644 --- a/docs/branching-strategy.md +++ b/docs/branching-strategy.md @@ -1,26 +1,19 @@ # Branching Strategy -Dana Runtime uses a **Gitflow-based vertical branching** model with long-lived branches and short-lived branch types. +Dana Runtime uses a **simplified two-branch model**: one integration branch and one release branch. -![Branching Diagram](assets/gitflow-vertical-branching.svg) +``` +feature/* ──PR──> develop ──PR──> master + | + hotfix/* ────┘ (branched from master; merged back to master + develop) +``` ## Long-lived Branches -| Branch | Purpose | Accepts PRs from | -|-----------|--------------------------------------------------------------------------|----------------------| -| `stable` | Production-ready code. Every commit is tagged with a release version. | `main/*`, `hotfix/*` | -| `develop` | Integration branch. All feature work merges here first. | `feature/*` | - -## Release Branches (`main/*`) - -Each release gets its own branch under the `main/` prefix. - -- Naming: `main/` (e.g. `main/1.0`, `main/2.0`) -- Created from `develop` when a release is ready for stabilization -- **Only bugfixes** are allowed on release branches -- Bugfixes on `main/*` merge back into `develop` to stay in sync -- Once stable, merges into `stable` and a version tag is created -- Accepts PRs from: `develop`, `hotfix/*` +| Branch | Purpose | Accepts PRs from | +|-----------|----------------------------------------------------------------------|----------------------| +| `develop` | Integration branch. All feature work merges here first. **Default branch.** | `feature/*` | +| `master` | Release branch. Every merge produces a version tag + GitHub Release. | `develop`, `hotfix/*` | ## Short-lived Branches @@ -28,41 +21,44 @@ Each release gets its own branch under the `main/` prefix. - Branch from `develop` - Merge back into `develop` via PR -- Naming: `feature/` (e.g. `feature/login`, `feature/timeline-compression`) +- Naming: `feature/` (e.g. `feature/timeline-compression`) - Delete after merge ### Hotfix branches (`hotfix/*`) -- Branch from `stable` for critical production bugs -- Merge into **both** `stable` and `develop` (to keep develop in sync) -- Naming: `hotfix/` (e.g. `hotfix/0.1.1`, `hotfix/fix-crash`) -- A new tag is created on `stable` after merge +- Branch from `master` for critical production bugs +- Merge into **both** `master` and `develop` (keep develop in sync) +- Bump the version on the hotfix branch manually before merging into `master` +- Naming: `hotfix/` (e.g. `hotfix/fix-crash`) - Delete after merge ## Release Flow 1. `develop` accumulates features via merged feature branches -2. When ready for release, create `main/` from `develop` -3. Only bugfixes are committed on `main/` during stabilization -4. Bugfixes on `main/` merge back into `develop` to stay in sync -5. Once stable, `main/` merges into `stable` and a version tag is created -6. `main/` also merges back into `develop` to include final bugfixes +2. When ready for release, set the target version in `pyproject.toml` on `develop` +3. Open a PR `develop → master`. CI auto-bumps the patch version if `develop` is not already ahead +4. Merge the PR → [`release-on-merge-to-master`](../.github/workflows/release-on-merge-to-master.yml) tags `v` and creates a GitHub Release -## Branch Protection +## Versioning -Enforced by [`.github/workflows/branch-policy.yml`](../.github/workflows/branch-policy.yml): +- Source of truth: `version` in [`pyproject.toml`](../pyproject.toml) +- To ship a **minor/major** bump (e.g. `0.2.0`, `1.0.0`), set it on `develop` before opening the release PR — the auto-bumper detects `develop` is already ahead and skips +- Otherwise the auto-bumper raises the patch component (`0.1.3` → `0.1.4`) +- Tags follow `v` (e.g. `v0.2.0`) + +## Branch Protection -- **`stable`** only accepts PRs from `main/*` or `hotfix/*` -- **`main/*`** only accepts PRs from `develop` or `hotfix/*` +Enforced by [`.github/workflows/branch-policy.yml`](../.github/workflows/branch-policy.yml) plus repository rulesets: -Any PR violating these rules is automatically rejected by CI. +- **`master`** only accepts PRs from `develop` or `hotfix/*` +- Direct pushes to `master` are blocked (no non-fast-forward, no deletion); merges require review + signatures +- Any PR violating the source-branch rule is rejected by the `check-branch-policy` job ## Quick Reference ```text -feature/* ──PR──> develop ──PR──> main/ ──PR──> stable - ^ | - | hotfix/* ────────PR──> stable - +----------- hotfix/* (also merged back) - +----------- main/ bugfixes (merged back) +feature/* ──PR──> develop ──PR──> master ──> tag vX.Y.Z + GitHub Release + ^ | + | hotfix/* ──┘ (also merged back to develop) + +-------------------+ ``` diff --git a/pyproject.toml b/pyproject.toml index b4b0deb..30f71d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ build-backend = "setuptools.build_meta" [project] name = "dana" -version = "0.1.3" +version = "0.2.0" description = "Dana Agent - Domain-Aware Neurosymbolic Agents" readme = "README.md" requires-python = ">=3.12"