Skip to content

Commit 33ecc8b

Browse files
committed
ci: tag and release
1 parent b073588 commit 33ecc8b

File tree

6 files changed

+514
-28
lines changed

6 files changed

+514
-28
lines changed

.circleci/config.yml

Lines changed: 97 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -67,43 +67,113 @@ jobs:
6767
mode: auto
6868
iac-scan: disabled
6969

70+
determine-version:
71+
<<: *go_image
72+
steps:
73+
- checkout
74+
- run:
75+
name: Determine version bump and save to workspace
76+
command: |
77+
chmod +x ./script/version-bump.sh
78+
./script/version-bump.sh
79+
80+
# Source the environment to make variables available
81+
source $BASH_ENV
82+
83+
# Save to workspace
84+
mkdir -p /tmp/workspace
85+
echo "$BUMP_TYPE" > /tmp/workspace/bump_type
86+
echo "$NEW_VERSION" > /tmp/workspace/new_version
87+
echo "$NEW_TAG" > /tmp/workspace/new_tag
88+
echo "$PREVIOUS_TAG" > /tmp/workspace/previous_tag
89+
- persist_to_workspace:
90+
root: /tmp/workspace
91+
paths:
92+
- bump_type
93+
- new_version
94+
- new_tag
95+
- previous_tag
96+
97+
tag-release:
98+
<<: *go_image
99+
steps:
100+
- checkout
101+
- add_ssh_keys:
102+
fingerprints:
103+
- "SHA256:w5lYpE8DMWxUdasN8yMbbFdiz6s50PPBJMkV0a1iyZ8"
104+
- attach_workspace:
105+
at: /tmp/workspace
106+
- run:
107+
name: Configure git
108+
command: |
109+
git config user.email "[email protected]"
110+
git config user.name "Snyk CI"
111+
- run:
112+
name: Create and push tag
113+
command: |
114+
BUMP_TYPE=$(cat /tmp/workspace/bump_type)
115+
NEW_TAG=$(cat /tmp/workspace/new_tag)
116+
117+
if [ "$BUMP_TYPE" = "none" ]; then
118+
echo "Chore commit detected - skipping tag creation"
119+
circleci-agent step halt
120+
fi
121+
122+
echo "Creating tag: $NEW_TAG"
123+
git tag -a "$NEW_TAG" -m "Release $NEW_TAG"
124+
git push origin "$NEW_TAG"
125+
126+
# Filters for branches
127+
filters_pr_only: &filters_pr_only
128+
filters:
129+
branches:
130+
ignore:
131+
- main
132+
133+
filters_main_only: &filters_main_only
134+
filters:
135+
branches:
136+
only:
137+
- main
138+
70139
workflows:
71140
version: 2
72-
CI:
141+
test-and-tag:
73142
jobs:
143+
# PR-only jobs - all testing
144+
- lint:
145+
<<: *filters_pr_only
146+
147+
- unit_test:
148+
<<: *filters_pr_only
149+
74150
- prodsec/secrets-scan:
75151
name: Scan repository for secrets
76152
context:
77153
- snyk-bot-slack
78154
channel: snyk-vuln-alerts-unify
79-
filters:
80-
branches:
81-
ignore:
82-
- main
83-
- security-scans:
84-
name: Security Scans
85-
context:
86-
- analysis_unify
87-
- lint:
88-
name: Lint
89-
filters:
90-
branches:
91-
ignore:
92-
- main
93-
- unit_test:
94-
name: Unit tests
95-
filters:
96-
branches:
97-
ignore:
98-
- main
155+
<<: *filters_pr_only
156+
99157
- python_integration_test:
100-
name: Python << matrix.python_version >> integration tests
101158
requires:
102-
- Unit tests
159+
- unit_test
103160
matrix:
104161
parameters:
105162
python_version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
106-
filters:
107-
branches:
108-
ignore:
109-
- main
163+
<<: *filters_pr_only
164+
165+
# Main branch only - security scans and tagging (no test re-runs)
166+
- security-scans:
167+
context:
168+
- analysis_unify
169+
<<: *filters_main_only
170+
171+
- determine-version:
172+
requires:
173+
- security-scans
174+
<<: *filters_main_only
175+
176+
- tag-release:
177+
requires:
178+
- determine-version
179+
<<: *filters_main_only
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: PR Title Check
2+
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- edited
8+
- synchronize
9+
- reopened
10+
11+
jobs:
12+
validate-pr-title:
13+
name: Validate PR Title
14+
runs-on: ubuntu-latest
15+
permissions:
16+
pull-requests: write
17+
steps:
18+
- name: Validate PR Title Format
19+
uses: actions/github-script@v7
20+
with:
21+
script: |
22+
const prTitle = context.payload.pull_request.title;
23+
24+
// Define valid types and their version bump effect
25+
const types = {
26+
'fix': 'patch',
27+
'feat': 'minor',
28+
'feature': 'minor',
29+
'chore': 'none',
30+
'docs': 'none',
31+
'style': 'none',
32+
'refactor': 'none',
33+
'test': 'none',
34+
'ci': 'none',
35+
'perf': 'patch',
36+
'build': 'none',
37+
'revert': 'patch'
38+
};
39+
40+
// Regular expressions for validation
41+
const conventionalCommitPattern = /^(\w+)(\(\w+\))?:\s.{3,}$/;
42+
const majorPrefixPattern = /^\[major\]\s.{3,}$/i;
43+
const majorTypePattern = /^major:\s.{3,}$/i;
44+
45+
let isValid = false;
46+
let bumpType = 'none';
47+
let errorMessage = '';
48+
49+
// Check for major version indicators
50+
if (majorPrefixPattern.test(prTitle)) {
51+
isValid = true;
52+
bumpType = 'major';
53+
console.log('✓ Valid PR title with [major] prefix');
54+
} else if (majorTypePattern.test(prTitle)) {
55+
isValid = true;
56+
bumpType = 'major';
57+
console.log('✓ Valid PR title with major: prefix');
58+
} else if (conventionalCommitPattern.test(prTitle)) {
59+
// Extract type from conventional commit format
60+
const match = prTitle.match(/^(\w+)/);
61+
const type = match ? match[1].toLowerCase() : '';
62+
63+
if (types[type]) {
64+
isValid = true;
65+
bumpType = types[type];
66+
console.log(`✓ Valid PR title with type '${type}' (${bumpType} bump)`);
67+
} else {
68+
errorMessage = `Invalid commit type '${type}'. Valid types are: ${Object.keys(types).join(', ')}`;
69+
}
70+
} else {
71+
errorMessage = 'PR title does not follow conventional commit format';
72+
}
73+
74+
// Helper to post/update comment
75+
const marker = '<!-- pr-title-check -->';
76+
const postComment = async (body) => {
77+
const comments = await github.rest.issues.listComments({
78+
owner: context.repo.owner,
79+
repo: context.repo.repo,
80+
issue_number: context.payload.pull_request.number,
81+
});
82+
const existing = comments.data.find(c => c.body.includes(marker));
83+
84+
const payload = {
85+
owner: context.repo.owner,
86+
repo: context.repo.repo,
87+
body: `${marker}\n${body}`
88+
};
89+
90+
if (existing) {
91+
await github.rest.issues.updateComment({...payload, comment_id: existing.id});
92+
} else {
93+
await github.rest.issues.createComment({...payload, issue_number: context.payload.pull_request.number});
94+
}
95+
};
96+
97+
// Post result
98+
if (isValid) {
99+
const emoji = {'major': '🔴', 'minor': '🟡', 'patch': '🟢', 'none': '⚪'}[bumpType];
100+
await postComment(`✅ **Valid** — ${emoji} ${bumpType.toUpperCase()}${bumpType === 'none' ? ' (no release)' : ''}`);
101+
console.log(`✓ Valid: ${bumpType} bump`);
102+
} else {
103+
await postComment(`❌ **Invalid**
104+
105+
**Error:** ${errorMessage}
106+
107+
**Format:** \`type: description\` or \`[major] description\`
108+
109+
**Valid types:** fix, feat, major, chore, docs, style, refactor, test, ci, perf, build, revert
110+
111+
See [CONTRIBUTING.md](../CONTRIBUTING.md) for examples.`);
112+
core.setFailed(errorMessage);
113+
}

CONTRIBUTING.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,56 @@
33
This repo is intended for internal (Snyk) contributions only at this time.
44

55
Please [reach our support](SUPPORT.md) to give any feedback.
6+
7+
## Commit Message Convention
8+
9+
This project uses **Conventional Commits** for automated versioning and releases. Please follow this format when committing or creating pull requests:
10+
11+
### Format
12+
```
13+
<type>[optional scope]: <description>
14+
15+
[optional body]
16+
17+
[optional footer(s)]
18+
```
19+
20+
### Types and Their Effect on Versioning
21+
22+
- **`fix:`** - Bug fixes (bumps **PATCH** version: 1.0.0 → 1.0.1)
23+
- **`feat:`** - New features (bumps **MINOR** version: 1.0.0 → 1.1.0)
24+
- **`[major]`** or **`major:`** - Breaking changes (bumps **MAJOR** version: 1.0.0 → 2.0.0)
25+
- **`chore:`**, **`docs:`**, **`style:`**, **`refactor:`**, **`test:`**, **`ci:`** - No release created
26+
27+
### Examples
28+
29+
```bash
30+
# Patch release
31+
fix: resolve memory leak in dependency parser
32+
33+
# Minor release
34+
feat: add support for Python 3.13
35+
36+
# Major release (option 1)
37+
[major] redesign API interface
38+
39+
# Major release (option 2)
40+
major: remove deprecated functions
41+
42+
# No release
43+
chore: update CI configuration
44+
```
45+
46+
### Pull Request Guidelines
47+
48+
When creating a pull request:
49+
1. **Use a descriptive title** following the conventional commit format (examples above)
50+
2. **Check the GitHub Action** - A bot will automatically validate your PR title and post a comment showing:
51+
- Whether the title is valid ✅ or invalid ❌
52+
- The version bump type (MAJOR, MINOR, PATCH, or NO RELEASE)
53+
3. **Edit the title if needed** - If validation fails or shows the wrong version bump, edit your PR title
54+
4. **Use "Squash and merge"** - The PR title will become the commit message
55+
5. **Ensure all tests pass** before merging
56+
6. **Releases are automatic** - When merged to `main`, CircleCI will automatically create a release
57+
58+
For more details, see the [Release Process Documentation](docs/RELEASE.md).

0 commit comments

Comments
 (0)