Skip to content

Commit 2c7793f

Browse files
Merge pull request #106 from contentstack/feat/dx-5396-cursor-skills-rules
snyk fix and cursor rules
2 parents 11f0ed4 + afae0c3 commit 2c7793f

File tree

14 files changed

+887
-592
lines changed

14 files changed

+887
-592
lines changed

.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)*. All conventions live in **skills/*/SKILL.md**.
4+
5+
This folder only points contributors to *AGENTS.md* so editor-specific config does not duplicate the canonical docs.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Catches when developers forget to bump package.json for release-affecting changes.
2+
# App code changes (app.js, bin/, config/, routes/, views/, etc.) require a version bump vs latest tag.
3+
# Skips for: test-only, docs, .github (workflows/config), dependency-only bumps without app edits.
4+
name: Check Version Bump
5+
6+
on:
7+
pull_request:
8+
9+
jobs:
10+
version-bump:
11+
name: Version 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 and version bump
20+
id: detect
21+
run: |
22+
if git rev-parse HEAD^2 >/dev/null 2>&1; then
23+
FILES=$(git diff --name-only HEAD^1 HEAD^2)
24+
else
25+
FILES=$(git diff --name-only HEAD~1 HEAD)
26+
fi
27+
VERSION_FILES_CHANGED=false
28+
echo "$FILES" | grep -qx 'package.json' && VERSION_FILES_CHANGED=true
29+
echo "version_files_changed=$VERSION_FILES_CHANGED" >> $GITHUB_OUTPUT
30+
# App source paths for this boilerplate (no lib/webpack/dist); .github/ and test/ do not count
31+
CODE_CHANGED=false
32+
echo "$FILES" | grep -qE '^app\.js$|^bin/|^config/|^middlewares/|^models/|^public/|^routes/|^views/|^schemaNentries/' && CODE_CHANGED=true
33+
echo "$FILES" | grep -qx 'package.json' && CODE_CHANGED=true
34+
echo "code_changed=$CODE_CHANGED" >> $GITHUB_OUTPUT
35+
36+
- name: Skip when only test/docs/.github changed
37+
if: steps.detect.outputs.code_changed != 'true'
38+
run: |
39+
echo "No release-affecting files changed (e.g. only test/docs/.github). Skipping version-bump check."
40+
exit 0
41+
42+
- name: Fail when version bump was missed
43+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed != 'true'
44+
run: |
45+
echo "::error::This PR has code changes but no version bump. Please bump the version in package.json."
46+
exit 1
47+
48+
- name: Setup Node
49+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
50+
uses: actions/setup-node@v4
51+
with:
52+
node-version: '22.x'
53+
54+
- name: Check version bump
55+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
56+
run: |
57+
set -e
58+
PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')")
59+
if [ -z "$PKG_VERSION" ]; then
60+
echo "::error::Could not read version from package.json"
61+
exit 1
62+
fi
63+
git fetch --tags --force 2>/dev/null || true
64+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
65+
if [ -z "$LATEST_TAG" ]; then
66+
echo "No existing tags found. Skipping version-bump check (first release)."
67+
exit 0
68+
fi
69+
LATEST_VERSION="${LATEST_TAG#v}"
70+
LATEST_VERSION="${LATEST_VERSION%%-*}"
71+
if [ "$(printf '%s\n' "$LATEST_VERSION" "$PKG_VERSION" | sort -V | tail -1)" != "$PKG_VERSION" ]; then
72+
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."
73+
exit 1
74+
fi
75+
if [ "$PKG_VERSION" = "$LATEST_VERSION" ]; then
76+
echo "::error::Version bump required: package.json version ($PKG_VERSION) equals latest tag ($LATEST_TAG). Please bump the version in package.json."
77+
exit 1
78+
fi
79+
echo "Version bump check passed: package.json is at $PKG_VERSION (latest tag: $LATEST_TAG)."

.github/workflows/release.yml

Lines changed: 42 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,57 @@
1-
name: Release datasync manager
1+
name: Release
2+
23
on:
3-
push:
4-
branches: [master]
4+
release:
5+
types: [created]
6+
57
jobs:
68
build:
79
runs-on: ubuntu-latest
10+
permissions:
11+
contents: write
812
steps:
9-
- uses: actions/checkout@v4
10-
- uses: actions/setup-node@v4
13+
# Checkout the repository
14+
- name: Checkout repository
15+
uses: actions/checkout@v4
16+
17+
# Setup Node.js environment
18+
- name: Setup Node.js
19+
uses: actions/setup-node@v4
1120
with:
1221
node-version: "22.x"
13-
# The below action will see the existing tags and will bump the current ones and this is only used to check whether the given tag already exists or not
14-
# We will be using the previous tag to compare with the current tag in the package.json
15-
# If both match then no new release would be triggered
16-
# Else New release will be created
17-
- name: Bump version and push tag
18-
id: tag_version
19-
uses: mathieudutour/[email protected]
20-
with:
21-
github_token: ${{ secrets.GITHUB_TOKEN }}
22-
default_bump: false
23-
# Getting the version info from package.json
24-
- name: get-npm-version
25-
id: package-version
26-
uses: martinbeentjes/[email protected]
27-
# Here we are checking whether this is the first release or not and then checking if it is release or not
28-
- name: check-first-release
29-
env:
30-
First_Release: ${{steps.tag_version.outputs.previous_tag=='v0.0.0'}}
31-
run: |
32-
if ${First_Release} == true; then
33-
echo "fr=true" >> $GITHUB_ENV
34-
echo "flag set to true"
35-
else
36-
echo "fr=false" >> $GITHUB_ENV
37-
echo "flag set to false"
38-
fi
39-
- name: check-release-version
40-
if: ${{env.fr=='false'}}
41-
env:
42-
old_version: ${{steps.tag_version.outputs.previous_tag}}
43-
new_version: v${{steps.package-version.outputs.current-version}}
44-
run: |
45-
echo ${old_version}
46-
echo ${new_version}
47-
echo ${{env.old_version==env.new_version}}
48-
if ${{env.old_version!=env.new_version}}; then
49-
echo "fr=true" >> $GITHUB_ENV
50-
echo "flag set to true"
51-
else
52-
echo "fr=false" >> $GITHUB_ENV
53-
echo "flag set to false"
54-
fi
55-
- name: Installing dependencies
22+
23+
# Install dependencies
24+
- name: Install dependencies
5625
run: npm install
26+
27+
# Build (dist/ is published per package.json "files")
5728
- name: Build
5829
run: npm run build-ts
59-
- name: Publishing datasync manager
60-
id: publish-core
30+
31+
# Fetch package details (name and version)
32+
- name: Get package details
33+
id: package
34+
uses: codex-team/[email protected]
35+
36+
# Pack the package into a .tgz archive (@contentstack/datasync-manager → contentstack-datasync-manager-<version>.tgz)
37+
- name: Pack the npm package
38+
run: npm pack
39+
40+
# Publish the package to npm
41+
- name: Publish to npm
42+
id: publish_npm
6143
uses: JS-DevTools/npm-publish@v3
62-
if: ${{env.fr=='true'}}
6344
with:
6445
token: ${{ secrets.NPM_TOKEN }}
65-
- name: Create Release
66-
id: create_release
67-
if: ${{env.fr=='true'}}
46+
# access: public # Uncomment if you need to publish a scoped package as public for the first time
47+
48+
# Upload the packaged .tgz to the release that triggered this workflow
49+
- name: Upload Release Asset
50+
uses: actions/upload-release-asset@v1
6851
env:
6952
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70-
run: gh release create v${{ steps.publish-core.outputs.version }} --title "Release ${{ steps.publish-core.outputs.version }}" --generate-notes
53+
with:
54+
upload_url: ${{ github.event.release.upload_url }}
55+
asset_path: "./contentstack-datasync-manager-${{ steps.package.outputs.version }}.tgz"
56+
asset_name: "contentstack-datasync-manager-${{ steps.package.outputs.version }}.tgz"
57+
asset_content_type: application/tgz

.husky/post-checkout

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env sh
2+
# When switching to a branch that doesn't exist on remote (e.g. newly created),
3+
# pull and merge origin/main or origin/master into current branch. Does not push.
4+
5+
# Only run on branch checkout (not file checkout)
6+
if [ "$3" != "1" ]; then
7+
exit 0
8+
fi
9+
10+
# Skip if we don't have a remote
11+
if ! git rev-parse --verify origin 2>/dev/null; then
12+
exit 0
13+
fi
14+
15+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
16+
17+
# Skip main/master - no need to merge base into these
18+
case "$CURRENT_BRANCH" in
19+
main|master) exit 0 ;;
20+
esac
21+
22+
# Only run when current branch does not exist on origin (treat as new local branch)
23+
if git ls-remote --heads origin "$CURRENT_BRANCH" 2>/dev/null | grep -q .; then
24+
echo "post-checkout: $CURRENT_BRANCH exists on origin, skipping merge."
25+
exit 0
26+
fi
27+
28+
# Prefer main, fallback to master
29+
if git rev-parse --verify origin/main 2>/dev/null; then
30+
BASE=origin/main
31+
elif git rev-parse --verify origin/master 2>/dev/null; then
32+
BASE=origin/master
33+
else
34+
exit 0
35+
fi
36+
37+
echo "New branch detected: merging latest $BASE into $CURRENT_BRANCH (local only, not pushing)..."
38+
git fetch origin
39+
git merge "$BASE" --no-edit --no-ff
40+
echo "Done. Merge is local only; push when ready."

.talismanrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ fileignoreconfig:
22
- filename: .github/workflows/secrets-scan.yml
33
ignore_detectors:
44
- filecontent
5+
- filename: .github/workflows/check-version-bump.yml
6+
ignore_detectors:
7+
- filecontent
58
- filename: package-lock.json
6-
checksum: 516d3f836eb5f260a662acd8ba3f144849e45f3fb44c9b94701275d4fd2e29a5
9+
checksum: 1525b038bc7500db7a4b489db28529cd0b2ada15afc7110d818fe13657303612
710
- filename: .husky/pre-commit
811
checksum: 1b9367d219802de2e3a8af9c5c698e0c255c00af89339d73bdbb8acf5275079f
912
version: ""

AGENTS.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# @contentstack/datasync-manager – 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/datasync-manager`](https://github.com/contentstack/datasync-manager) |
10+
| *Purpose:* | Primary Node.js module for [Contentstack DataSync](https://www.contentstack.com/docs/guide/synchronization/contentstack-datasync): coordinates content stores, asset stores, and a listener (webhooks), and pulls stack changes via the **Contentstack Sync API** with a **delivery token**. |
11+
| *Out of scope (if any):* | Not the standalone CDA or CMA client SDKs; not a generic HTTP client library—sync orchestration and Node **`https`** to the Sync API only. Say **DataSync** / **Sync API**, not “CMA”, for this package’s main behavior. |
12+
13+
## Tech stack (at a glance)
14+
15+
| Area | Details |
16+
|------|---------|
17+
| Language | TypeScript **4.9.x** → ES6, CommonJS (`tsconfig.json`); Node **>= 8** (`package.json` `engines`) |
18+
| Build | `tsc``dist/`; `types``typings` (`package.json`) |
19+
| Tests | **Jest** **29** + **ts-jest**; patterns in `jest.config.js`; tests under `test/**/*.ts` |
20+
| Lint / coverage | **ESLint** (`npm run lint`); legacy **TSLint** (`tslint.json`, `npm run tslint`); Jest coverage to `coverage/` |
21+
| Other | HTTP via Node **`https`**; logging via **`debug`** + `src/util/logger`; pre-commit **Talisman** + **Snyk** (`.husky/pre-commit`) |
22+
23+
## Commands (quick reference)
24+
25+
| Command type | Command |
26+
|--------------|---------|
27+
| Build | `npm run compile` or `npm run build-ts` (`clean` + `tsc`) |
28+
| Test | `npm test` (`PLUGIN_PATH=./test/dummy` + Jest, coverage, verbose) |
29+
| Lint | `npm run lint` / `npm run tslint` |
30+
31+
CI: [.github/workflows/check-version-bump.yml](.github/workflows/check-version-bump.yml) (version bump checks on PRs when applicable).
32+
33+
## Where the documentation lives: skills
34+
35+
| Skill | Path | What it covers |
36+
|-------|------|----------------|
37+
| Development workflow | [skills/dev-workflow/SKILL.md](skills/dev-workflow/SKILL.md) | Branches (`development` / `master`), release flow, build/test/lint, PR expectations, versioning |
38+
| TypeScript conventions | [skills/typescript/SKILL.md](skills/typescript/SKILL.md) | `src/` layout, compiler settings, logging, lint |
39+
| DataSync & Sync API | [skills/contentstack-datasync/SKILL.md](skills/contentstack-datasync/SKILL.md) | Public API, config, HTTP client, retries, tokens, core sync—**not** CMA |
40+
| Testing | [skills/testing/SKILL.md](skills/testing/SKILL.md) | Jest, nock, `PLUGIN_PATH`, fixtures, credentials policy |
41+
| Code review | [skills/code-review/SKILL.md](skills/code-review/SKILL.md) | PR checklist, severity (Blocker / Major / Minor) |
42+
43+
An index with “when to use” hints is in [skills/README.md](skills/README.md).
44+
45+
## Using Cursor (optional)
46+
47+
If you use *Cursor*, [.cursor/rules/README.md](.cursor/rules/README.md) only points to *AGENTS.md*—same docs as everyone else.

0 commit comments

Comments
 (0)