Skip to content

Commit 195faa5

Browse files
enh: adopt development→main release flow, back-merge, and version checks
1 parent c29fca3 commit 195faa5

3 files changed

Lines changed: 171 additions & 0 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Opens a PR from main → development after changes land on main (back-merge).
2+
3+
name: Back-merge main to development
4+
5+
on:
6+
push:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
pull-requests: write
13+
14+
jobs:
15+
open-back-merge-pr:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 0
22+
23+
- name: Open back-merge PR if needed
24+
env:
25+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26+
run: |
27+
set -euo pipefail
28+
git fetch origin development main
29+
30+
MAIN_SHA=$(git rev-parse origin/main)
31+
DEV_SHA=$(git rev-parse origin/development)
32+
33+
if [ "$MAIN_SHA" = "$DEV_SHA" ]; then
34+
echo "main and development are at the same commit; nothing to back-merge."
35+
exit 0
36+
fi
37+
38+
EXISTING=$(gh pr list --repo "${{ github.repository }}" \
39+
--base development \
40+
--head main \
41+
--state open \
42+
--json number \
43+
--jq 'length')
44+
45+
if [ "$EXISTING" -gt 0 ]; then
46+
echo "An open PR from main to development already exists; skipping."
47+
exit 0
48+
fi
49+
50+
gh pr create --repo "${{ github.repository }}" \
51+
--base development \
52+
--head main \
53+
--title "chore: back-merge main into development" \
54+
--body "Automated back-merge after changes landed on \`main\`. Review and merge to keep \`development\` in sync."
55+
56+
echo "Created back-merge PR main → development."
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Release-affecting changes under contentstack_management/ or setup.py require
2+
# __version__ + CHANGELOG.md updates aligned with the latest tag.
3+
4+
name: Check Version Bump
5+
6+
on:
7+
pull_request:
8+
9+
jobs:
10+
version-bump:
11+
name: Version & changelog bump
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
19+
- name: Detect changed files
20+
id: detect
21+
run: |
22+
FILES=$(git diff --name-only "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}")
23+
echo "Changed files:"
24+
echo "$FILES"
25+
26+
CODE_CHANGED=false
27+
while IFS= read -r f; do
28+
[ -z "$f" ] && continue
29+
if [[ "$f" == contentstack_management/* ]] || [[ "$f" == "setup.py" ]]; then
30+
CODE_CHANGED=true
31+
break
32+
fi
33+
done <<< "$FILES"
34+
35+
INIT_CHANGED=false
36+
CHANGELOG_CHANGED=false
37+
echo "$FILES" | grep -qx 'contentstack_management/__init__.py' && INIT_CHANGED=true
38+
echo "$FILES" | grep -qx 'CHANGELOG.md' && CHANGELOG_CHANGED=true
39+
40+
VERSION_FILES_OK=false
41+
if [ "$INIT_CHANGED" = true ] && [ "$CHANGELOG_CHANGED" = true ]; then
42+
VERSION_FILES_OK=true
43+
fi
44+
45+
echo "code_changed=$CODE_CHANGED" >> "$GITHUB_OUTPUT"
46+
echo "version_files_ok=$VERSION_FILES_OK" >> "$GITHUB_OUTPUT"
47+
48+
- name: Skip when no release-affecting code changed
49+
if: steps.detect.outputs.code_changed != 'true'
50+
run: |
51+
echo "No contentstack_management or setup.py changes. Skipping version-bump check."
52+
exit 0
53+
54+
- name: Fail when version files were not both updated
55+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_ok != 'true'
56+
run: |
57+
echo "::error::Bump __version__ in contentstack_management/__init__.py and add a ## vX.Y.Z section in CHANGELOG.md."
58+
exit 1
59+
60+
- name: Validate version vs latest tag and changelog header
61+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_ok == 'true'
62+
run: |
63+
set -euo pipefail
64+
PKG_VERSION=$(python3 <<'PY'
65+
import re
66+
text = open("contentstack_management/__init__.py").read()
67+
m = re.search(r"^__version__\s*=\s*['\"]([^'\"]+)['\"]", text, re.MULTILINE)
68+
if not m:
69+
raise SystemExit("Could not read __version__ from contentstack_management/__init__.py")
70+
print(m.group(1).strip())
71+
PY
72+
)
73+
74+
git fetch --tags --force 2>/dev/null || true
75+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
76+
if [ -z "$LATEST_TAG" ]; then
77+
echo "No existing tags found. Skipping semver vs tag check."
78+
CHANGELOG_HEAD=$(sed -nE 's/^## v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CHANGELOG.md | head -1)
79+
if [ -z "$CHANGELOG_HEAD" ]; then
80+
echo "::error::Could not find a ## vX.Y.Z entry at the top of CHANGELOG.md."
81+
exit 1
82+
fi
83+
if [ "$CHANGELOG_HEAD" != "$PKG_VERSION" ]; then
84+
echo "::error::CHANGELOG top version ($CHANGELOG_HEAD) does not match __version__ ($PKG_VERSION)."
85+
exit 1
86+
fi
87+
exit 0
88+
fi
89+
90+
LATEST_VERSION="${LATEST_TAG#v}"
91+
LATEST_VERSION="${LATEST_VERSION%%-*}"
92+
if [ "$(printf '%s\n' "$LATEST_VERSION" "$PKG_VERSION" | sort -V | tail -1)" != "$PKG_VERSION" ]; then
93+
echo "::error::__version__ ($PKG_VERSION) must be greater than latest tag ($LATEST_TAG)."
94+
exit 1
95+
fi
96+
if [ "$PKG_VERSION" = "$LATEST_VERSION" ]; then
97+
echo "::error::__version__ ($PKG_VERSION) must be strictly greater than latest tag version ($LATEST_VERSION)."
98+
exit 1
99+
fi
100+
101+
CHANGELOG_HEAD=$(sed -nE 's/^## v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CHANGELOG.md | head -1)
102+
if [ -z "$CHANGELOG_HEAD" ]; then
103+
echo "::error::Could not find a ## vX.Y.Z entry at the top of CHANGELOG.md."
104+
exit 1
105+
fi
106+
if [ "$CHANGELOG_HEAD" != "$PKG_VERSION" ]; then
107+
echo "::error::CHANGELOG top version ($CHANGELOG_HEAD) does not match __version__ ($PKG_VERSION)."
108+
exit 1
109+
fi
110+
echo "Version bump check passed: __version__ and CHANGELOG at $PKG_VERSION (latest tag: $LATEST_TAG)."

skills/dev-workflow/SKILL.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ description: Install, pytest unit/API/mock, versioning, pylint, hooks—standard
1010
- Setting up locally, opening a PR, or matching CI expectations.
1111
- Answering “how do we run tests?” or “what runs in CI?”
1212

13+
## Branches & releases
14+
15+
- **Flow:** merge work to **`development`**; **release PRs** are **`development``main`**. After **`main`** moves, [`.github/workflows/back-merge-pr.yml`](../../.github/workflows/back-merge-pr.yml) can open **`main``development`** to resync.
16+
- **PyPI:** publish a **GitHub Release** (`release: published`) to run [`.github/workflows/release.yml`](../../.github/workflows/release.yml). PRs that touch **`contentstack_management/`** or **`setup.py`** must bump **`__version__`** and **`CHANGELOG.md`** per [`.github/workflows/check-version-bump.yml`](../../.github/workflows/check-version-bump.yml).
17+
1318
## Before a PR
1419

1520
1. **Install**`pip install -e ".[dev]"` or install **`requirements.txt`** plus **pytest** / **pytest-cov** as needed.

0 commit comments

Comments
 (0)