Skip to content

Commit d3c17c6

Browse files
authored
Merge pull request #7 from DecOperations/claude/semantic-versioning-automation-at5XF
Implement semantic versioning and automated release workflow
2 parents ed6eb3e + 3d80555 commit d3c17c6

15 files changed

Lines changed: 3052 additions & 135 deletions

File tree

.github/workflows/ci.yml

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,55 @@ on:
66
pull_request:
77
branches: [main]
88

9+
concurrency:
10+
group: ci-${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions:
14+
contents: read
15+
916
jobs:
10-
build:
17+
commitlint:
18+
name: Commitlint
1119
runs-on: ubuntu-latest
20+
if: github.event_name == 'pull_request'
1221
steps:
1322
- uses: actions/checkout@v4
14-
23+
with:
24+
fetch-depth: 0
1525
- uses: pnpm/action-setup@v4
26+
- uses: actions/setup-node@v4
27+
with:
28+
node-version: '22'
29+
cache: 'pnpm'
30+
- run: pnpm install --frozen-lockfile
31+
- name: Validate PR commits
32+
run: |
33+
npx commitlint \
34+
--from "${{ github.event.pull_request.base.sha }}" \
35+
--to "${{ github.event.pull_request.head.sha }}" \
36+
--verbose
1637
38+
quality:
39+
name: Quality Gates
40+
runs-on: ubuntu-latest
41+
steps:
42+
- uses: actions/checkout@v4
43+
- uses: pnpm/action-setup@v4
1744
- uses: actions/setup-node@v4
1845
with:
1946
node-version: '22'
2047
cache: 'pnpm'
2148

2249
- run: pnpm install --frozen-lockfile
23-
- run: pnpm build
24-
- run: pnpm lint
50+
- name: Lint
51+
run: pnpm lint
52+
- name: Typecheck
53+
run: pnpm typecheck
54+
- name: Test
55+
run: pnpm test
56+
- name: Build
57+
run: pnpm build
2558

2659
- name: Self-scan
2760
run: node packages/cli/dist/index.js . --severity high --format json --output scan-results.json

.github/workflows/release-cli.yml

Lines changed: 0 additions & 75 deletions
This file was deleted.

.github/workflows/release.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
branches: [main, beta, alpha]
6+
workflow_dispatch:
7+
8+
concurrency:
9+
group: release-${{ github.ref }}
10+
cancel-in-progress: false
11+
12+
permissions:
13+
contents: write
14+
issues: write
15+
pull-requests: write
16+
packages: write
17+
id-token: write
18+
19+
jobs:
20+
release:
21+
name: Semantic Release
22+
runs-on: ubuntu-latest
23+
outputs:
24+
new_release_published: ${{ steps.semrel.outputs.new_release_published }}
25+
new_release_version: ${{ steps.semrel.outputs.new_release_version }}
26+
new_release_git_tag: ${{ steps.semrel.outputs.new_release_git_tag }}
27+
steps:
28+
- uses: actions/checkout@v4
29+
with:
30+
fetch-depth: 0
31+
persist-credentials: true
32+
token: ${{ secrets.GITHUB_TOKEN }}
33+
34+
- uses: pnpm/action-setup@v4
35+
- uses: actions/setup-node@v4
36+
with:
37+
node-version: '22'
38+
cache: 'pnpm'
39+
registry-url: 'https://npm.pkg.github.com'
40+
scope: '@decoperations'
41+
42+
- run: pnpm install --frozen-lockfile
43+
44+
- name: Lint
45+
run: pnpm lint
46+
- name: Typecheck
47+
run: pnpm typecheck
48+
- name: Test
49+
run: pnpm test
50+
- name: Build
51+
run: pnpm build
52+
53+
- name: Semantic Release
54+
id: semrel
55+
env:
56+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
run: |
58+
# Run semantic-release; capture whether it published a new version.
59+
if pnpm exec semantic-release; then
60+
if [ -f packages/cli/package.json ]; then
61+
VERSION=$(node -p "require('./packages/cli/package.json').version")
62+
echo "new_release_published=true" >> "$GITHUB_OUTPUT"
63+
echo "new_release_version=$VERSION" >> "$GITHUB_OUTPUT"
64+
echo "new_release_git_tag=v$VERSION" >> "$GITHUB_OUTPUT"
65+
fi
66+
else
67+
echo "new_release_published=false" >> "$GITHUB_OUTPUT"
68+
exit 1
69+
fi
70+
71+
publish:
72+
name: Publish CLI to GitHub Packages
73+
needs: release
74+
if: needs.release.outputs.new_release_published == 'true'
75+
runs-on: ubuntu-latest
76+
steps:
77+
- uses: actions/checkout@v4
78+
with:
79+
ref: ${{ needs.release.outputs.new_release_git_tag }}
80+
fetch-depth: 0
81+
82+
- uses: pnpm/action-setup@v4
83+
- uses: actions/setup-node@v4
84+
with:
85+
node-version: '22'
86+
cache: 'pnpm'
87+
registry-url: 'https://npm.pkg.github.com'
88+
scope: '@decoperations'
89+
90+
- run: pnpm install --frozen-lockfile
91+
92+
- name: Build CLI with release metadata
93+
env:
94+
RELEASE_VERSION: ${{ needs.release.outputs.new_release_version }}
95+
RELEASE_COMMIT: ${{ github.sha }}
96+
RELEASE_BUILD_DATE: ${{ github.event.repository.updated_at }}
97+
run: pnpm build --filter @decoperations/owasp-wtf
98+
99+
- name: Publish to GitHub Packages
100+
env:
101+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
102+
run: pnpm --filter @decoperations/owasp-wtf publish --no-git-checks --access public
103+
104+
- name: Smoke test installed package
105+
env:
106+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
107+
run: |
108+
mkdir -p /tmp/smoke && cd /tmp/smoke
109+
echo "@decoperations:registry=https://npm.pkg.github.com" > .npmrc
110+
echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" >> .npmrc
111+
npm init -y >/dev/null
112+
npm install @decoperations/owasp-wtf@${{ needs.release.outputs.new_release_version }}
113+
npx owasp-wtf --version

.husky/commit-msg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
npx --no-install commitlint --edit "$1"

.releaserc.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"branches": [
3+
"main",
4+
{ "name": "beta", "prerelease": true },
5+
{ "name": "alpha", "prerelease": true }
6+
],
7+
"tagFormat": "v${version}",
8+
"plugins": [
9+
[
10+
"@semantic-release/commit-analyzer",
11+
{
12+
"preset": "conventionalcommits",
13+
"releaseRules": [
14+
{ "type": "security", "release": "patch" },
15+
{ "type": "perf", "release": "patch" },
16+
{ "type": "refactor", "release": "patch" },
17+
{ "type": "build", "release": "patch" },
18+
{ "type": "revert", "release": "patch" },
19+
{ "type": "docs", "release": false },
20+
{ "type": "test", "release": false },
21+
{ "type": "ci", "release": false },
22+
{ "type": "chore", "release": false }
23+
],
24+
"parserOpts": {
25+
"noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES", "BREAKING"]
26+
}
27+
}
28+
],
29+
[
30+
"@semantic-release/release-notes-generator",
31+
{
32+
"preset": "conventionalcommits",
33+
"presetConfig": {
34+
"types": [
35+
{ "type": "feat", "section": "Features" },
36+
{ "type": "fix", "section": "Bug Fixes" },
37+
{ "type": "security", "section": "Security" },
38+
{ "type": "perf", "section": "Performance" },
39+
{ "type": "refactor", "section": "Refactoring" },
40+
{ "type": "build", "section": "Build" },
41+
{ "type": "revert", "section": "Reverts" },
42+
{ "type": "docs", "section": "Documentation", "hidden": true },
43+
{ "type": "test", "section": "Tests", "hidden": true },
44+
{ "type": "ci", "section": "CI", "hidden": true },
45+
{ "type": "chore", "section": "Chores", "hidden": true }
46+
]
47+
}
48+
}
49+
],
50+
"@semantic-release/changelog",
51+
[
52+
"@semantic-release/npm",
53+
{
54+
"pkgRoot": "packages/cli",
55+
"npmPublish": false
56+
}
57+
],
58+
[
59+
"@semantic-release/git",
60+
{
61+
"assets": [
62+
"CHANGELOG.md",
63+
"packages/cli/package.json"
64+
],
65+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
66+
}
67+
],
68+
[
69+
"@semantic-release/github",
70+
{
71+
"successComment": false,
72+
"failComment": false
73+
}
74+
]
75+
]
76+
}

0 commit comments

Comments
 (0)