Skip to content

Commit b57d7e0

Browse files
Merge pull request #61 from contentstack/development
DX | 11-05-2026 | Release dev -> stg
2 parents a140a0a + 2f111e6 commit b57d7e0

16 files changed

Lines changed: 1750 additions & 71 deletions

File tree

.cursor/rules/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Cursor (optional)
2+
3+
**Cursor** users: start at **[`AGENTS.md`](../../AGENTS.md)** at the repository root. All conventions live in **`skills/*/SKILL.md`**.
4+
5+
This folder only points contributors to **`AGENTS.md`** so editor-specific configuration does not duplicate the canonical documentation.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Back-merge master to development
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
pull-requests: write
12+
13+
jobs:
14+
open-back-merge-pr:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Open back-merge PR if needed
23+
env:
24+
GH_TOKEN: ${{ github.token }}
25+
run: |
26+
set -euo pipefail
27+
BASE_BRANCH="development"
28+
SOURCE_BRANCH="master"
29+
30+
git fetch origin "$BASE_BRANCH" "$SOURCE_BRANCH"
31+
32+
if ! git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then
33+
echo "Base branch '$BASE_BRANCH' does not exist on origin; skipping."
34+
exit 0
35+
fi
36+
37+
SOURCE_SHA=$(git rev-parse "origin/$SOURCE_BRANCH")
38+
BASE_SHA=$(git rev-parse "origin/$BASE_BRANCH")
39+
40+
if [ "$SOURCE_SHA" = "$BASE_SHA" ]; then
41+
echo "$SOURCE_BRANCH and $BASE_BRANCH are at the same commit; nothing to back-merge."
42+
exit 0
43+
fi
44+
45+
EXISTING=$(gh pr list --repo "${{ github.repository }}" --base "$BASE_BRANCH" --head "$SOURCE_BRANCH" --state open --json number --jq 'length')
46+
47+
if [ "$EXISTING" -gt 0 ]; then
48+
echo "An open PR from $SOURCE_BRANCH to $BASE_BRANCH already exists; skipping."
49+
exit 0
50+
fi
51+
52+
gh pr create --repo "${{ github.repository }}" --base "$BASE_BRANCH" --head "$SOURCE_BRANCH" --title "chore: back-merge $SOURCE_BRANCH into $BASE_BRANCH" --body "Automated back-merge after changes landed on \\`$SOURCE_BRANCH\\`. Review and merge to keep \\`$BASE_BRANCH\\` in sync."
53+
54+
echo "Created back-merge PR $SOURCE_BRANCH -> $BASE_BRANCH."

.github/workflows/check-branch.yml

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
name: Check Version Bump
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
version-bump:
8+
name: Version & Changelog bump
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 0
15+
16+
- name: Detect changed files and version bump
17+
id: detect
18+
run: |
19+
if git rev-parse HEAD^2 >/dev/null 2>&1; then
20+
FILES=$(git diff --name-only HEAD^1 HEAD^2)
21+
else
22+
FILES=$(git diff --name-only HEAD~1 HEAD)
23+
fi
24+
VERSION_FILES_CHANGED=false
25+
echo "$FILES" | grep -qx 'package.json' && VERSION_FILES_CHANGED=true
26+
echo "$FILES" | grep -qx 'CHANGELOG.md' && VERSION_FILES_CHANGED=true
27+
echo "version_files_changed=$VERSION_FILES_CHANGED" >> $GITHUB_OUTPUT
28+
# Only lib/, webpack/, dist/, package.json count as release-affecting; .github/ and test/ do not
29+
CODE_CHANGED=false
30+
echo "$FILES" | grep -qE '^lib/|^webpack/|^dist/' && CODE_CHANGED=true
31+
echo "$FILES" | grep -qx 'package.json' && CODE_CHANGED=true
32+
echo "code_changed=$CODE_CHANGED" >> $GITHUB_OUTPUT
33+
34+
- name: Skip when only test/docs/.github changed
35+
if: steps.detect.outputs.code_changed != 'true'
36+
run: |
37+
echo "No release-affecting files changed (e.g. only test/docs/.github). Skipping version-bump check."
38+
exit 0
39+
40+
- name: Fail when version bump was missed
41+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed != 'true'
42+
run: |
43+
echo "::error::This PR has code changes but no version bump. Please bump the version in package.json and add an entry in CHANGELOG.md."
44+
exit 1
45+
46+
- name: Setup Node
47+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
48+
uses: actions/setup-node@v4
49+
with:
50+
node-version: '22.x'
51+
52+
- name: Check version bump
53+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
54+
run: |
55+
set -e
56+
PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')")
57+
if [ -z "$PKG_VERSION" ]; then
58+
echo "::error::Could not read version from package.json"
59+
exit 1
60+
fi
61+
git fetch --tags --force 2>/dev/null || true
62+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
63+
if [ -z "$LATEST_TAG" ]; then
64+
echo "No existing tags found. Skipping version-bump check (first release)."
65+
exit 0
66+
fi
67+
LATEST_VERSION="${LATEST_TAG#v}"
68+
LATEST_VERSION="${LATEST_VERSION%%-*}"
69+
if [ "$(printf '%s\n' "$LATEST_VERSION" "$PKG_VERSION" | sort -V | tail -1)" != "$PKG_VERSION" ]; then
70+
echo "::error::Version bump required: package.json version ($PKG_VERSION) is not greater than latest tag ($LATEST_TAG). Please bump the version in package.json."
71+
exit 1
72+
fi
73+
if [ "$PKG_VERSION" = "$LATEST_VERSION" ]; then
74+
echo "::error::Version bump required: package.json version ($PKG_VERSION) equals latest tag ($LATEST_TAG). Please bump the version in package.json."
75+
exit 1
76+
fi
77+
CHANGELOG_VERSION=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CHANGELOG.md | head -1)
78+
if [ -z "$CHANGELOG_VERSION" ]; then
79+
echo "::error::Could not find a version entry in CHANGELOG.md (expected line like '## [v1.0.0](...)')."
80+
exit 1
81+
fi
82+
if [ "$CHANGELOG_VERSION" != "$PKG_VERSION" ]; then
83+
echo "::error::CHANGELOG version mismatch: CHANGELOG.md top version ($CHANGELOG_VERSION) does not match package.json version ($PKG_VERSION). Please add or update the CHANGELOG entry for $PKG_VERSION."
84+
exit 1
85+
fi
86+
echo "Version bump check passed: package.json and CHANGELOG.md are at $PKG_VERSION (latest tag: $LATEST_TAG)."

AGENTS.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Contentstack Utils .NET – Agent guide
2+
3+
**Universal entry point** for contributors and AI agents. Detailed conventions live in **`skills/*/SKILL.md`**.
4+
5+
## What this repo is
6+
7+
| Field | Detail |
8+
|-------|--------|
9+
| **Name:** | [contentstack-utils-dotnet](https://github.com/contentstack/contentstack-utils-dotnet) |
10+
| **Purpose:** | NuGet library **`contentstack.utils`**: JSON RTE → HTML rendering, embedded entry/asset rendering, GQL-oriented helpers, variant metadata (`GetVariantMetadataTags` / `GetVariantAliases`), Live Preview–style editable tags (`addEditableTags`). This is **not** a full Contentstack Delivery or Management HTTP SDK. |
11+
| **Out of scope (if any):** | No built-in HTTP client to Contentstack APIs; consumers use the Contentstack .NET Delivery SDK or other clients. This package focuses on parsing, rendering, and JSON helpers. |
12+
13+
## Tech stack (at a glance)
14+
15+
| Area | Details |
16+
|------|---------|
17+
| **Language** | C#; library multi-targets **netstandard2.0**, **net47**, **net472** ([`Contentstack.Utils/Contentstack.Utils.csproj`](Contentstack.Utils/Contentstack.Utils.csproj)); test project **net7.0** ([`Contentstack.Utils.Tests/Contentstack.Utils.Tests.csproj`](Contentstack.Utils.Tests/Contentstack.Utils.Tests.csproj)). |
18+
| **Build** | **dotnet** + solution [`Contentstack.Utils.sln`](Contentstack.Utils.sln); shared package version in [`Directory.Build.props`](Directory.Build.props) (e.g. `Version` **1.2.0**). |
19+
| **Tests** | **xUnit**, **Microsoft.NET.Test.Sdk**, **coverlet.collector**; JSON fixtures under [`Contentstack.Utils.Tests/Resources/`](Contentstack.Utils.Tests/Resources/). |
20+
| **Lint / coverage** | No repo-level `.editorconfig` or format workflow; tests use **Coverlet** (`XPlat code coverage`) via the shell scripts. |
21+
| **Key dependencies** | **HtmlAgilityPack**, **Newtonsoft.Json** in the library; tests reference compatible Newtonsoft.Json. |
22+
23+
## Commands (quick reference)
24+
25+
| Command type | Command |
26+
|--------------|---------|
27+
| **Build** | `dotnet build Contentstack.Utils.sln` (add `-c Release` for release configuration). |
28+
| **Test (quick, local)** | `dotnet test Contentstack.Utils.sln` — from repo root; no TRX/coverage (fastest feedback). |
29+
| **Test (CI parity)** | `sh ./Scripts/run-unit-test-case.sh` — clears `Contentstack.Utils.Tests/TestResults`, runs `dotnet test` on the test project with TRX logging and coverage. |
30+
| **Test + HTML coverage report** | `bash ./Scripts/run-test-case.sh` — tests the **solution**, then runs `python3 Scripts/generate_test_report.py` to emit HTML under `Contentstack.Utils.Tests/TestResults/Coverage-.../index.html`. |
31+
| **Pack (release)** | `dotnet pack -c Release -o out` (see [`.github/workflows/nuget-publish.yml`](.github/workflows/nuget-publish.yml)). |
32+
| **SCA (local parity with CI)** | `dotnet restore ./Contentstack.Utils.sln`, then from `Contentstack.Utils`: `snyk test` (requires Snyk CLI and `SNYK_TOKEN`; see [`sca-scan.yml`](.github/workflows/sca-scan.yml)). |
33+
34+
**CI:** [`.github/workflows/unit-test.yml`](.github/workflows/unit-test.yml) runs `run-unit-test-case.sh` on Windows for `pull_request` and `push`.
35+
36+
## CI and automation (workflows)
37+
38+
| Workflow | Trigger | Role |
39+
|----------|---------|------|
40+
| [`unit-test.yml`](.github/workflows/unit-test.yml) | `pull_request`, `push` | Windows: unit tests via `Scripts/run-unit-test-case.sh`. |
41+
| [`back-merge-pr.yml`](.github/workflows/back-merge-pr.yml) | `push` on `master`, manual dispatch | Opens automated back-merge PRs from `master` to `development` to keep branches aligned. |
42+
| [`nuget-publish.yml`](.github/workflows/nuget-publish.yml) | `release` (created) | `dotnet pack -c Release -o out`; push package to NuGet.org and GitHub Packages. |
43+
| [`sca-scan.yml`](.github/workflows/sca-scan.yml) | PR (opened, synchronize, reopened) | Ubuntu: `dotnet restore`, **Snyk** `snyk test` under `Contentstack.Utils`. |
44+
| [`policy-scan.yml`](.github/workflows/policy-scan.yml) | PR (public repos) | Requires `SECURITY.md` and a license file containing the current year. |
45+
| [`codeql-analysis.yml`](.github/workflows/codeql-analysis.yml) | `pull_request` (branches `*`) | CodeQL analysis for **csharp** (autobuild). |
46+
| [`issues-jira.yml`](.github/workflows/issues-jira.yml) | `issues` (opened) | Creates Jira tickets from GitHub issues (secrets). |
47+
48+
## Where the documentation lives: skills
49+
50+
| Skill | Path | What it covers |
51+
|-------|------|----------------|
52+
| Dev workflow | [`skills/dev-workflow/SKILL.md`](skills/dev-workflow/SKILL.md) | Branches, build/test/pack, CI, security workflows, CODEOWNERS, Talisman. |
53+
| Testing | [`skills/testing/SKILL.md`](skills/testing/SKILL.md) | xUnit layout, fixtures, mocks, coverage scripts, alignment with CI. |
54+
| Code review | [`skills/code-review/SKILL.md`](skills/code-review/SKILL.md) | PR expectations, checklist, security notes. |
55+
| Contentstack Utils (API) | [`skills/contentstack-utils/SKILL.md`](skills/contentstack-utils/SKILL.md) | Public API, package boundaries, `Utils` / GQL / variants, dependencies. |
56+
| C# style (this repo) | [`skills/csharp-style/SKILL.md`](skills/csharp-style/SKILL.md) | Folder layout, namespaces, naming consistency, TFMs. |

0 commit comments

Comments
 (0)