From 96722e55527e6cf612e2df64f2b7cf8f7d304385 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Wed, 29 Apr 2026 16:05:52 +0530 Subject: [PATCH 1/9] =?UTF-8?q?chore:=20migrate=20java=20repo=20to=20GitHu?= =?UTF-8?q?b=20Release=E2=80=93based=20publish=20flow=20with=20strict=20ve?= =?UTF-8?q?rsion=20gating?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/back-merge-pr.yml | 59 ++++++++++++++++ .github/workflows/check-branch.yml | 20 ------ .github/workflows/check-version-bump.yml | 86 ++++++++++++++++++++++++ .github/workflows/maven-publish.yml | 10 ++- AGENTS.md | 2 +- Changelog.md | 9 ++- skills/code-review/SKILL.md | 2 +- skills/dev-workflow/SKILL.md | 4 +- 8 files changed, 161 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/back-merge-pr.yml delete mode 100644 .github/workflows/check-branch.yml create mode 100644 .github/workflows/check-version-bump.yml diff --git a/.github/workflows/back-merge-pr.yml b/.github/workflows/back-merge-pr.yml new file mode 100644 index 0000000..cec0f26 --- /dev/null +++ b/.github/workflows/back-merge-pr.yml @@ -0,0 +1,59 @@ +# Opens a PR from master → development after changes land on master (back-merge). +# +# Org/repo Settings → Actions → General → Workflow permissions: read and write +# (so GITHUB_TOKEN can create pull requests). Or use a PAT in secret GH_TOKEN. + +name: Back-merge master to development + +on: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: read + pull-requests: write + +jobs: + open-back-merge-pr: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Open back-merge PR if needed + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + git fetch origin development master + + MASTER_SHA=$(git rev-parse origin/master) + DEV_SHA=$(git rev-parse origin/development) + + if [ "$MASTER_SHA" = "$DEV_SHA" ]; then + echo "master and development are at the same commit; nothing to back-merge." + exit 0 + fi + + EXISTING=$(gh pr list --repo "${{ github.repository }}" \ + --base development \ + --head master \ + --state open \ + --json number \ + --jq 'length') + + if [ "$EXISTING" -gt 0 ]; then + echo "An open PR from master to development already exists; skipping." + exit 0 + fi + + gh pr create --repo "${{ github.repository }}" \ + --base development \ + --head master \ + --title "chore: back-merge master into development" \ + --body "Automated back-merge after changes landed on \`master\`. Review and merge to keep \`development\` in sync." + + echo "Created back-merge PR master → development." diff --git a/.github/workflows/check-branch.yml b/.github/workflows/check-branch.yml deleted file mode 100644 index 5a6b9c8..0000000 --- a/.github/workflows/check-branch.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: 'Check Branch' - -on: - pull_request: - -jobs: - check_branch: - runs-on: ubuntu-latest - steps: - - name: Comment PR - if: github.base_ref == 'master' && github.head_ref != 'staging' - uses: thollander/actions-comment-pull-request@v2 - with: - message: | - We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch. - - name: Check branch - if: github.base_ref == 'master' && github.head_ref != 'staging' - run: | - echo "ERROR: We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch." - exit 1 diff --git a/.github/workflows/check-version-bump.yml b/.github/workflows/check-version-bump.yml new file mode 100644 index 0000000..1747388 --- /dev/null +++ b/.github/workflows/check-version-bump.yml @@ -0,0 +1,86 @@ +name: Check Version Bump + +on: + pull_request: + branches: [main, master] + +jobs: + check-version-bump: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Validate version and changelog updates + shell: bash + run: | + set -euo pipefail + + VERSION_FILE="pom.xml" + CHANGELOG_FILE="CHANGELOG.md" + BASE_SHA="${{ github.event.pull_request.base.sha }}" + HEAD_SHA="${{ github.event.pull_request.head.sha }}" + + mapfile -t CHANGED_FILES < <(git diff --name-only "$BASE_SHA" "$HEAD_SHA") + if [ "${#CHANGED_FILES[@]}" -eq 0 ]; then + echo "No changed files detected." + exit 0 + fi + + is_ignored_change() { + local f="$1" + [[ "$f" =~ ^docs/ ]] && return 0 + [[ "$f" =~ ^\.github/ ]] && return 0 + [[ "$f" =~ (^|/)tests?/ ]] && return 0 + [[ "$f" =~ (^|/)src/test/ ]] && return 0 + [[ "$f" =~ \.md$ ]] && [[ ! "$f" =~ (^|/)CHANGELOG\.md$ ]] && return 0 + return 1 + } + + has_release_impact=false + for file in "${CHANGED_FILES[@]}"; do + if ! is_ignored_change "$file"; then + has_release_impact=true + break + fi + done + + if [ "$has_release_impact" = false ]; then + echo "Skipping docs/test-only PR." + exit 0 + fi + + changed_file() { + local target="$1" + for file in "${CHANGED_FILES[@]}"; do + if [ "$file" = "$target" ]; then + return 0 + fi + done + return 1 + } + + changed_file "$VERSION_FILE" || { echo "Version bump required in $VERSION_FILE."; exit 1; } + changed_file "$CHANGELOG_FILE" || { echo "Matching changelog update required in $CHANGELOG_FILE."; exit 1; } + + extract_version() { + python3 -c 'import sys,xml.etree.ElementTree as ET;r=ET.fromstring(sys.stdin.read());ns={"m":r.tag.split("}")[0].strip("{")} if r.tag.startswith("{") else None;n=(r.find("m:version",ns) if ns else r.find("version"));print((n.text or "").strip() if n is not None else "")' + } + + head_version=$(extract_version < "$VERSION_FILE") + CHANGELOG_HEAD=$(sed -nE 's/^## v?([^[:space:]]+).*/\1/p' "$CHANGELOG_FILE" | head -1) + + [ -n "$CHANGELOG_HEAD" ] || { echo "::error::Could not find a top changelog heading like '## vX.Y.Z' in $CHANGELOG_FILE."; exit 1; } + [ "$CHANGELOG_HEAD" = "$head_version" ] || { echo "::error::$CHANGELOG_FILE top version ($CHANGELOG_HEAD) does not match project version ($head_version)."; exit 1; } + + base_version=$(git show "$BASE_SHA:$VERSION_FILE" | extract_version) + latest_tag=$(git tag --list 'v*' --sort=-version:refname | sed -n '1p') + latest_version="${latest_tag#v}" + [ -n "$latest_version" ] || latest_version="0.0.0" + + version_gt() { + python3 -c 'import sys;v=lambda s:[int(x) if x.isdigit() else 0 for x in (s.strip().lstrip("v").split("-",1)[0].split("+",1)[0].split(".")+["0","0","0"])[:3]];print("true" if v(sys.argv[1])>v(sys.argv[2]) else "false")' "$1" "$2" + } + + [ "$(version_gt "$head_version" "$base_version")" = "true" ] || { echo "Version must be greater than base version ($base_version). Found $head_version."; exit 1; } + [ "$(version_gt "$head_version" "$latest_version")" = "true" ] || { echo "Version must be greater than latest tag version ($latest_version). Found $head_version."; exit 1; } diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index e7e1b76..c2fec1e 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -4,12 +4,15 @@ on: types: [created] jobs: publish-maven: + if: ${{ startsWith(github.event.release.tag_name, 'v') && !github.event.release.draft }} runs-on: ubuntu-latest permissions: contents: read packages: write steps: - uses: actions/checkout@v3 + with: + ref: ${{ github.event.release.tag_name }} - name: Set up Maven Central Repository uses: actions/setup-java@v3 with: @@ -27,9 +30,12 @@ jobs: MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} publish-github: + if: ${{ startsWith(github.event.release.tag_name, 'v') && !github.event.release.draft }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + with: + ref: ${{ github.event.release.tag_name }} - name: Set up Java for publishing to GitHub Packages uses: actions/setup-java@v3 with: @@ -37,7 +43,7 @@ jobs: distribution: 'adopt' server-id: github gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} + gpg-passphrase: GPG_PASSPHRASE - name: Set up Maven settings for Central and GitHub run: | mkdir -p $HOME/.m2 @@ -58,4 +64,4 @@ jobs: - name: Publish to GitHub Packages run: mvn --batch-mode -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} deploy env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index 95bc73e..44e0d9e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ | Single test class | `mvn test -Dtest=UtilTests` | | Javadoc | `mvn javadoc:javadoc` | | Sample (after `mvn install` with skips if needed) | `mvn -f sample/pom.xml compile` | -| **CI** | Java **17** publish: `.github/workflows/maven-publish.yml` · SCA: `.github/workflows/sca-scan.yml` · branch rules: `.github/workflows/check-branch.yml` | +| **CI** | Java **17** publish: `.github/workflows/maven-publish.yml` (GitHub **Release** for tag `v*`, draft releases skipped) · SCA: `.github/workflows/sca-scan.yml` · back-merge automation: `.github/workflows/back-merge-pr.yml` | ## Where the documentation lives: skills diff --git a/Changelog.md b/Changelog.md index ae598d0..9244220 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,4 @@ -# Changelog +# CHANGELOG A brief description of what changes project contains @@ -6,7 +6,7 @@ A brief description of what changes project contains #### v1.5.0 -- Enhancement: Live Preview Editable tags +- Enhancement: Live Preview Editable tags ## Mar 23, 2026 @@ -36,7 +36,7 @@ A brief description of what changes project contains #### v1.2.11 -- Fix: ignore td/th in case of attrs has void:true +- Fix: ignore td/th in case of attrs has void:true ## May 14, 2024 @@ -48,7 +48,7 @@ A brief description of what changes project contains #### v1.2.9 -- Fixed vulnerability issue related to strAttrs and children. +- Fixed vulnerability issue related to strAttrs and children. ## April 23, 2024 @@ -136,4 +136,3 @@ A brief description of what changes project contains ## Support - For support, email fake@fake.com or join our Slack channel. - diff --git a/skills/code-review/SKILL.md b/skills/code-review/SKILL.md index 8f3e938..806e4bd 100644 --- a/skills/code-review/SKILL.md +++ b/skills/code-review/SKILL.md @@ -16,7 +16,7 @@ description: PR checklist and optional Blocker/Major/Minor — use when reviewin ### API design and stability - [ ] **Public API:** New or changed methods on `Utils`, `GQL`, `DefaultOption`, or `interfaces` are necessary, Javadoc’d, and safe for `com.contentstack.sdk:utils` consumers. -- [ ] **Backward compatibility:** Breaking changes only with major version / **`Changelog.md`** plan. +- [ ] **Backward compatibility:** Breaking changes only with major version / **`CHANGELOG.md`** plan. - [ ] **Naming:** Consistent with existing Utils and RTE/embedded terminology. ### Error handling and robustness diff --git a/skills/dev-workflow/SKILL.md b/skills/dev-workflow/SKILL.md index 3a988df..a44abd0 100644 --- a/skills/dev-workflow/SKILL.md +++ b/skills/dev-workflow/SKILL.md @@ -15,7 +15,7 @@ description: Branches, CI, build and test commands, PR expectations, optional TD ### Branches -- Default integration for PRs is often **`staging`**; merging into **`master`** may be restricted (see `.github/workflows/check-branch.yml`). +- Feature/fix PRs should target **`development`**. Release PRs are raised directly from **`development`** to **`master`**. - Feature/fix branches often use ticket-style names (e.g. `fix/DX-5734`). ### Running tests and builds @@ -28,7 +28,7 @@ description: Branches, CI, build and test commands, PR expectations, optional TD ### Pull requests - Describe the change; link issues/tickets when applicable. -- Keep public API backward-compatible unless releasing a breaking version; update **`Changelog.md`** for user-visible behavior. +- Keep public API backward-compatible unless releasing a breaking version; update **`CHANGELOG.md`** for user-visible behavior. - Use **`skills/code-review/SKILL.md`** as the review checklist. ### Optional: TDD From 0589fabee01040ffa024878fa3f87236cbd3106c Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 11:59:06 +0530 Subject: [PATCH 2/9] fix: check-version bump triggered for all the PR --- .github/workflows/check-version-bump.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/check-version-bump.yml b/.github/workflows/check-version-bump.yml index 1747388..63b5f1d 100644 --- a/.github/workflows/check-version-bump.yml +++ b/.github/workflows/check-version-bump.yml @@ -2,7 +2,6 @@ name: Check Version Bump on: pull_request: - branches: [main, master] jobs: check-version-bump: From fa3165af7f41e80f09ffcd9e7f445ca8f66ea444 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 12:29:42 +0530 Subject: [PATCH 3/9] fix: updated spring-web-version --- pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c643cf7..6329a67 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ 2.5.3 2.0.1.Final 20251224 - 7.0.6 + 7.0.7 1.15.0 @@ -212,8 +212,7 @@ false 17 - http://docs.oracle.com/javase/8/docs/api/ - http://docs.oracle.com/javase/8/docs/api/ + https://docs.oracle.com/en/java/javase/17/docs/api/ none From 4e27f12557a97063a4cc513e383171666e246086 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 13:51:12 +0530 Subject: [PATCH 4/9] chore: version bump --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6329a67..aead79d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.contentstack.sdk utils - 1.5.0 + 1.5.1 jar Contentstack-utils Java Utils SDK for Contentstack Content Delivery API, Contentstack is a headless CMS From 83a445cc7b78ec0a6655c671438461fd8c6ec9c9 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 13:53:44 +0530 Subject: [PATCH 5/9] chore: changelog update --- Changelog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Changelog.md b/Changelog.md index 9244220..fcd242a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,13 @@ A brief description of what changes project contains +## Apr 30, 2026 + +#### v1.5.1 + +- Fix: Upgraded `org.springframework:spring-web` to 7.0.7 to address Snyk-reported vulnerabilities in Spring Framework (including transitive `spring-core`) +- Chore: Javadoc external `links` updated to Java 17 API documentation for successful builds on modern JDKs + ## Apr 20, 2026 #### v1.5.0 From bf69caf8945b82c66f6243f809b14a37956984a7 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 13:53:57 +0530 Subject: [PATCH 6/9] chore: changelog update --- Changelog.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index fcd242a..163bdc8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,7 +7,6 @@ A brief description of what changes project contains #### v1.5.1 - Fix: Upgraded `org.springframework:spring-web` to 7.0.7 to address Snyk-reported vulnerabilities in Spring Framework (including transitive `spring-core`) -- Chore: Javadoc external `links` updated to Java 17 API documentation for successful builds on modern JDKs ## Apr 20, 2026 From cf947a7fa88b45f4802081ece1da6c34d78dd5da Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 14:28:18 +0530 Subject: [PATCH 7/9] fix: reading version bump from changelog --- .github/workflows/check-version-bump.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check-version-bump.yml b/.github/workflows/check-version-bump.yml index 63b5f1d..a7f4445 100644 --- a/.github/workflows/check-version-bump.yml +++ b/.github/workflows/check-version-bump.yml @@ -67,10 +67,16 @@ jobs: } head_version=$(extract_version < "$VERSION_FILE") - CHANGELOG_HEAD=$(sed -nE 's/^## v?([^[:space:]]+).*/\1/p' "$CHANGELOG_FILE" | head -1) + # Changelog uses "## Date" sections with versions on "#### vX.Y.Z" lines; support that and legacy "## vX.Y.Z". + CHANGELOG_HEAD=$( + sed -nE 's/^####[[:space:]]+v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' "$CHANGELOG_FILE" | head -1 + ) + if [ -z "$CHANGELOG_HEAD" ]; then + CHANGELOG_HEAD=$(sed -nE 's/^##[[:space:]]+v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' "$CHANGELOG_FILE" | head -1) + fi - [ -n "$CHANGELOG_HEAD" ] || { echo "::error::Could not find a top changelog heading like '## vX.Y.Z' in $CHANGELOG_FILE."; exit 1; } - [ "$CHANGELOG_HEAD" = "$head_version" ] || { echo "::error::$CHANGELOG_FILE top version ($CHANGELOG_HEAD) does not match project version ($head_version)."; exit 1; } + [ -n "$CHANGELOG_HEAD" ] || { echo "::error::Could not find a version in $CHANGELOG_FILE (expected '#### vX.Y.Z' under a date section or legacy '## vX.Y.Z')."; exit 1; } + [ "$CHANGELOG_HEAD" = "$head_version" ] || { echo "::error::$CHANGELOG_FILE top release version ($CHANGELOG_HEAD) does not match project version ($head_version)."; exit 1; } base_version=$(git show "$BASE_SHA:$VERSION_FILE" | extract_version) latest_tag=$(git tag --list 'v*' --sort=-version:refname | sed -n '1p') From 779f922bfc3c0d41990fc00b829dc679f61949eb Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 14:31:40 +0530 Subject: [PATCH 8/9] chore: update changelog --- Changelog.md => CHANGELOG.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Changelog.md => CHANGELOG.md (100%) diff --git a/Changelog.md b/CHANGELOG.md similarity index 100% rename from Changelog.md rename to CHANGELOG.md From 03d988913bf820e0e6cf9636ee32392f51e71bf2 Mon Sep 17 00:00:00 2001 From: raj pandey Date: Thu, 30 Apr 2026 15:10:43 +0530 Subject: [PATCH 9/9] ci: gate version-bump on src paths; validate semver vs latest tag only --- .github/workflows/check-version-bump.yml | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/check-version-bump.yml b/.github/workflows/check-version-bump.yml index a7f4445..73b871a 100644 --- a/.github/workflows/check-version-bump.yml +++ b/.github/workflows/check-version-bump.yml @@ -1,3 +1,6 @@ +# Runs only when production code under src/main/ changes. Version must be > latest v* tag +# (not compared to the base branch, so rebases onto an already-bumped main still pass when tag requires a new release). + name: Check Version Bump on: @@ -26,26 +29,21 @@ jobs: exit 0 fi - is_ignored_change() { + is_production_source_change() { local f="$1" - [[ "$f" =~ ^docs/ ]] && return 0 - [[ "$f" =~ ^\.github/ ]] && return 0 - [[ "$f" =~ (^|/)tests?/ ]] && return 0 - [[ "$f" =~ (^|/)src/test/ ]] && return 0 - [[ "$f" =~ \.md$ ]] && [[ ! "$f" =~ (^|/)CHANGELOG\.md$ ]] && return 0 - return 1 + [[ "$f" == src/main/* ]] } - has_release_impact=false + has_source_changes=false for file in "${CHANGED_FILES[@]}"; do - if ! is_ignored_change "$file"; then - has_release_impact=true + if is_production_source_change "$file"; then + has_source_changes=true break fi done - if [ "$has_release_impact" = false ]; then - echo "Skipping docs/test-only PR." + if [ "$has_source_changes" = false ]; then + echo "Skipping: no src/main/ production code changes." exit 0 fi @@ -78,7 +76,6 @@ jobs: [ -n "$CHANGELOG_HEAD" ] || { echo "::error::Could not find a version in $CHANGELOG_FILE (expected '#### vX.Y.Z' under a date section or legacy '## vX.Y.Z')."; exit 1; } [ "$CHANGELOG_HEAD" = "$head_version" ] || { echo "::error::$CHANGELOG_FILE top release version ($CHANGELOG_HEAD) does not match project version ($head_version)."; exit 1; } - base_version=$(git show "$BASE_SHA:$VERSION_FILE" | extract_version) latest_tag=$(git tag --list 'v*' --sort=-version:refname | sed -n '1p') latest_version="${latest_tag#v}" [ -n "$latest_version" ] || latest_version="0.0.0" @@ -87,5 +84,4 @@ jobs: python3 -c 'import sys;v=lambda s:[int(x) if x.isdigit() else 0 for x in (s.strip().lstrip("v").split("-",1)[0].split("+",1)[0].split(".")+["0","0","0"])[:3]];print("true" if v(sys.argv[1])>v(sys.argv[2]) else "false")' "$1" "$2" } - [ "$(version_gt "$head_version" "$base_version")" = "true" ] || { echo "Version must be greater than base version ($base_version). Found $head_version."; exit 1; } [ "$(version_gt "$head_version" "$latest_version")" = "true" ] || { echo "Version must be greater than latest tag version ($latest_version). Found $head_version."; exit 1; }