Skip to content

Commit 2c76615

Browse files
Gbahdeybohclaude
andcommitted
docs: add comprehensive Postman Native Git cookbook
Add complete cookbook demonstrating how to integrate Postman collections into existing development workflows using Native Git capabilities. Documentation added: - README.md: Main cookbook with quick start and workflow overview - docs/SETUP.md: Step-by-step setup guide for all platforms - docs/SPECTRAL.md: Spectral linting guide with security rules - docs/CI_CD.md: CI/CD integration (GitHub Actions, GitLab, CircleCI) - docs/COMMIT_HOOKS.md: Git hooks setup and configuration - docs/TESTING.md: Testing guide for the example API - docs/QUICK_REFERENCE.md: Quick command reference GitHub Actions workflows: - spectral-lint.yaml: Lint collections on changes - run-collections.yaml: Run collections on PRs with matrix testing - secret-scan.yaml: Scan for exposed credentials - scheduled-health-check.yaml: Automated API health monitoring - postman.yaml: Publish to Postman workspace Git hooks and configuration: - .husky/pre-commit: Run linting, tests, and collections - .husky/pre-commit-examples.sh: 10 hook pattern examples - .spectral.yaml: Collection linting rules with security checks - .spectral/lint-with-names.js: Enhanced linting script Example implementation: - Express.js banking API (src/) - Jest unit and integration tests (tests/) - Postman collections with test scripts (postman/collections/) - OpenAPI specification (openapi/) - Environment files and globals (postman/environments/) Workflows covered: 1. Pre-commit/pre-push hooks with Postman collections 2. CI/CD pipeline integration with automated testing 3. Spectral linting for enforcing collection best practices 4. Secret detection to prevent credential exposure Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent bac4439 commit 2c76615

File tree

133 files changed

+19318
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+19318
-1
lines changed

.eslintignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules/
2+
coverage/
3+
dist/
4+
build/
5+
*.min.js
6+
.postman/
7+
openapi/.openapi-generator-ignore
8+

.eslintrc.json

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"env": {
3+
"node": true,
4+
"es2021": true,
5+
"jest": true
6+
},
7+
"extends": [
8+
"eslint:recommended",
9+
"plugin:node/recommended"
10+
],
11+
"plugins": [
12+
"jest"
13+
],
14+
"parserOptions": {
15+
"ecmaVersion": "latest",
16+
"sourceType": "module"
17+
},
18+
"rules": {
19+
"indent": ["error", 2],
20+
"linebreak-style": ["error", "unix"],
21+
"quotes": ["error", "single"],
22+
"semi": ["error", "always"],
23+
"no-console": "off",
24+
"no-unused-vars": ["error", {
25+
"argsIgnorePattern": "^_",
26+
"varsIgnorePattern": "^_"
27+
}],
28+
"no-var": "error",
29+
"prefer-const": "error",
30+
"prefer-arrow-callback": "warn",
31+
"arrow-spacing": ["error", { "before": true, "after": true }],
32+
"comma-dangle": ["error", "never"],
33+
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
34+
"eol-last": ["error", "always"],
35+
"object-curly-spacing": ["error", "always"],
36+
"array-bracket-spacing": ["error", "never"],
37+
"keyword-spacing": ["error", { "before": true, "after": true }],
38+
"space-before-function-paren": ["error", {
39+
"anonymous": "always",
40+
"named": "never",
41+
"asyncArrow": "always"
42+
}],
43+
"space-before-blocks": "error",
44+
"node/no-unpublished-require": "off",
45+
"node/no-missing-require": "off",
46+
"node/no-unsupported-features/es-syntax": ["error", {
47+
"ignores": ["modules"]
48+
}]
49+
},
50+
"overrides": [
51+
{
52+
"files": ["tests/**/*.js", "**/*.test.js", "**/*.spec.js"],
53+
"env": {
54+
"jest": true
55+
},
56+
"rules": {
57+
"jest/no-disabled-tests": "warn",
58+
"jest/no-focused-tests": "error",
59+
"jest/no-identical-title": "error",
60+
"jest/prefer-to-have-length": "warn",
61+
"jest/valid-expect": "error"
62+
}
63+
}
64+
]
65+
}
66+

.github/workflows/postman.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Publish to Postman Workspace
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
jobs:
11+
postman:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- uses: actions/setup-node@v4
17+
with:
18+
node-version: "20"
19+
cache: "yarn"
20+
21+
- run: curl -o- "https://dl-cli.pstmn.io/install/unix.sh" | sh
22+
23+
- name: Validate and sync
24+
env:
25+
POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }}
26+
run: |
27+
postman login --with-api-key "$POSTMAN_API_KEY"
28+
yarn install --frozen-lockfile
29+
yarn start &
30+
sleep 3
31+
yarn test:api
32+
postman workspace push -y
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: Run Postman Collections
2+
3+
on:
4+
pull_request:
5+
branches: [main, develop]
6+
push:
7+
branches: [main, develop]
8+
workflow_dispatch: # Allow manual trigger
9+
10+
jobs:
11+
test-collections:
12+
name: Test Collections
13+
runs-on: ubuntu-latest
14+
15+
strategy:
16+
matrix:
17+
node-version: [18, 20]
18+
fail-fast: false
19+
20+
steps:
21+
- name: Checkout code
22+
uses: actions/checkout@v4
23+
24+
- name: Setup Node.js ${{ matrix.node-version }}
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: ${{ matrix.node-version }}
28+
cache: 'npm'
29+
30+
- name: Install dependencies
31+
run: npm ci
32+
33+
- name: Install Postman CLI
34+
run: curl -o- "https://dl-cli.pstmn.io/install/unix.sh" | sh
35+
36+
- name: Run unit and integration tests
37+
run: npm test
38+
39+
- name: Start API server
40+
run: |
41+
npm start &
42+
SERVER_PID=$!
43+
echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV
44+
45+
- name: Wait for server to be ready
46+
run: |
47+
timeout 60 bash -c '
48+
until curl -f -s http://localhost:3000/health > /dev/null 2>&1; do
49+
echo "Waiting for server to start..."
50+
sleep 2
51+
done
52+
'
53+
echo "✅ Server is ready!"
54+
55+
- name: Authenticate with Postman
56+
env:
57+
POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }}
58+
run: postman login --with-api-key "$POSTMAN_API_KEY"
59+
60+
- name: Run Postman collections
61+
run: |
62+
for collection in postman/collections/*.postman_collection.json; do
63+
if [ -f "$collection" ]; then
64+
echo "📬 Running collection: $(basename "$collection")"
65+
postman collection run "$collection" \
66+
--reporter cli,json \
67+
--reporter-json-export "results-$(basename "$collection" .json).json"
68+
69+
if [ $? -ne 0 ]; then
70+
echo "❌ Collection failed: $collection"
71+
exit 1
72+
fi
73+
fi
74+
done
75+
echo "✅ All collections passed!"
76+
77+
- name: Upload test results
78+
if: always()
79+
uses: actions/upload-artifact@v3
80+
with:
81+
name: postman-results-node-${{ matrix.node-version }}
82+
path: results-*.json
83+
retention-days: 7
84+
85+
- name: Stop server
86+
if: always()
87+
run: |
88+
if [ -n "$SERVER_PID" ]; then
89+
kill $SERVER_PID 2>/dev/null || true
90+
fi
91+
92+
- name: Comment on PR with results
93+
if: always() && github.event_name == 'pull_request'
94+
uses: actions/github-script@v6
95+
with:
96+
script: |
97+
const fs = require('fs');
98+
const results = fs.readdirSync('.')
99+
.filter(file => file.startsWith('results-') && file.endsWith('.json'));
100+
101+
let passed = 0;
102+
let failed = 0;
103+
104+
results.forEach(file => {
105+
try {
106+
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
107+
if (data.run && data.run.stats) {
108+
passed += data.run.stats.tests.passed || 0;
109+
failed += data.run.stats.tests.failed || 0;
110+
}
111+
} catch (e) {
112+
console.error(`Error reading ${file}:`, e);
113+
}
114+
});
115+
116+
const status = failed === 0 ? '✅' : '❌';
117+
const message = `${status} **Postman Collections Test Results (Node ${{ matrix.node-version }})**
118+
119+
- ✅ Passed: ${passed}
120+
- ❌ Failed: ${failed}
121+
- 📊 Total: ${passed + failed}
122+
`;
123+
124+
github.rest.issues.createComment({
125+
issue_number: context.issue.number,
126+
owner: context.repo.owner,
127+
repo: context.repo.repo,
128+
body: message
129+
});

0 commit comments

Comments
 (0)