Skip to content

Commit c0024e7

Browse files
authored
Merge pull request #1 from GremlinLTD/feature/project-scaffolding
chore: add project scaffolding and CI/CD workflows
2 parents a076dbf + 44bd12e commit c0024e7

File tree

14 files changed

+796
-51
lines changed

14 files changed

+796
-51
lines changed

.github/pull_request_template.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## Summary
2+
3+
<!-- Brief description of what this PR does and why -->
4+
5+
## Changes
6+
7+
-
8+
9+
## Type of change
10+
11+
- [ ] feat: new feature
12+
- [ ] fix: bug fix
13+
- [ ] docs: documentation update
14+
- [ ] refactor: code restructuring
15+
- [ ] test: test additions or updates
16+
- [ ] chore: maintenance or dependency update
17+
18+
## Testing
19+
20+
- [ ] Tests added/updated
21+
- [ ] All existing tests pass (`uv run pytest`)
22+
- [ ] Linting passes (`uv run ruff check .`)
23+
24+
## Breaking changes
25+
26+
<!-- Describe any breaking changes, or write "None" -->
27+
28+
None
29+
30+
## Related issues
31+
32+
<!-- Link related issues: Fixes #123, Relates to #456 -->
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v[0-9]+.[0-9]+.[0-9]+"
7+
workflow_dispatch:
8+
inputs:
9+
bump:
10+
description: "Version bump type (leave empty to auto-detect from commits)"
11+
required: false
12+
type: choice
13+
options:
14+
- auto
15+
- major
16+
- minor
17+
- patch
18+
default: auto
19+
20+
permissions:
21+
contents: write
22+
23+
jobs:
24+
release:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Checkout
28+
uses: actions/checkout@v4
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Determine version
33+
id: version
34+
run: |
35+
if [ "${{ github.event_name }}" = "push" ]; then
36+
TAG="${GITHUB_REF#refs/tags/}"
37+
VERSION="${TAG#v}"
38+
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
39+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
40+
exit 0
41+
fi
42+
43+
LATEST_STABLE=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
44+
BUMP="${{ inputs.bump }}"
45+
46+
if [ "$BUMP" = "auto" ] || [ -z "$BUMP" ]; then
47+
if [ -z "$LATEST_STABLE" ]; then
48+
COMMITS=$(git log --pretty=format:"%s%n%b" HEAD)
49+
else
50+
COMMITS=$(git log --pretty=format:"%s%n%b" "${LATEST_STABLE}..HEAD")
51+
fi
52+
53+
BUMP="patch"
54+
if echo "$COMMITS" | grep -qE '^feat(\(.+\))?!:|^fix(\(.+\))?!:|^refactor(\(.+\))?!:|^[a-z]+(\(.+\))?!:|BREAKING CHANGE:'; then
55+
BUMP="major"
56+
elif echo "$COMMITS" | grep -qE '^feat(\(.+\))?:'; then
57+
BUMP="minor"
58+
fi
59+
fi
60+
61+
if [ -z "$LATEST_STABLE" ]; then
62+
MAJOR=0; MINOR=1; PATCH=0
63+
else
64+
VERSION="${LATEST_STABLE#v}"
65+
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
66+
fi
67+
68+
case "$BUMP" in
69+
major)
70+
MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0
71+
;;
72+
minor)
73+
MINOR=$((MINOR + 1)); PATCH=0
74+
;;
75+
patch)
76+
PATCH=$((PATCH + 1))
77+
;;
78+
esac
79+
80+
NEXT_VERSION="${MAJOR}.${MINOR}.${PATCH}"
81+
TAG="v${NEXT_VERSION}"
82+
83+
echo "version=${NEXT_VERSION}" >> "$GITHUB_OUTPUT"
84+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
85+
86+
- name: Create and push tag (manual dispatch)
87+
if: github.event_name == 'workflow_dispatch'
88+
run: |
89+
git tag "${{ steps.version.outputs.tag }}"
90+
git push origin "${{ steps.version.outputs.tag }}"
91+
echo "Tag pushed. The release will be created by the tag-push trigger."
92+
93+
- name: Generate changelog
94+
if: github.event_name == 'push'
95+
id: changelog
96+
run: |
97+
PREVIOUS_TAG=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -2 | tail -1)
98+
if [ -z "$PREVIOUS_TAG" ]; then
99+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" HEAD)
100+
else
101+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" "${PREVIOUS_TAG}..HEAD")
102+
fi
103+
{
104+
echo "changelog<<EOF"
105+
echo "$CHANGELOG"
106+
echo "EOF"
107+
} >> "$GITHUB_OUTPUT"
108+
109+
- name: Create GitHub release
110+
if: github.event_name == 'push'
111+
uses: softprops/action-gh-release@v2
112+
with:
113+
tag_name: ${{ steps.version.outputs.tag }}
114+
name: ${{ steps.version.outputs.tag }}
115+
body: |
116+
## What's Changed
117+
118+
${{ steps.changelog.outputs.changelog }}
119+
draft: false
120+
prerelease: false
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: Release Candidate
2+
3+
on:
4+
push:
5+
branches: [main]
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
rc-release:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
19+
- name: Determine version bump from commits
20+
id: bump
21+
run: |
22+
LATEST_STABLE=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
23+
24+
if [ -z "$LATEST_STABLE" ]; then
25+
COMMITS=$(git log --pretty=format:"%s%n%b" HEAD)
26+
else
27+
COMMITS=$(git log --pretty=format:"%s%n%b" "${LATEST_STABLE}..HEAD")
28+
fi
29+
30+
BUMP="patch"
31+
32+
if echo "$COMMITS" | grep -qE '^feat(\(.+\))?!:|^fix(\(.+\))?!:|^refactor(\(.+\))?!:|^[a-z]+(\(.+\))?!:|BREAKING CHANGE:'; then
33+
BUMP="major"
34+
elif echo "$COMMITS" | grep -qE '^feat(\(.+\))?:'; then
35+
BUMP="minor"
36+
fi
37+
38+
echo "bump=${BUMP}" >> "$GITHUB_OUTPUT"
39+
40+
- name: Calculate next version
41+
id: version
42+
run: |
43+
LATEST_STABLE=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
44+
BUMP="${{ steps.bump.outputs.bump }}"
45+
46+
if [ -z "$LATEST_STABLE" ]; then
47+
MAJOR=0; MINOR=1; PATCH=0
48+
else
49+
VERSION="${LATEST_STABLE#v}"
50+
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
51+
fi
52+
53+
case "$BUMP" in
54+
major)
55+
MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0
56+
;;
57+
minor)
58+
MINOR=$((MINOR + 1)); PATCH=0
59+
;;
60+
patch)
61+
PATCH=$((PATCH + 1))
62+
;;
63+
esac
64+
65+
NEXT_VERSION="${MAJOR}.${MINOR}.${PATCH}"
66+
RC_COUNT=$(git tag --sort=-v:refname | grep -cE "^v${NEXT_VERSION}-rc\." || true)
67+
RC_NUM=$((RC_COUNT + 1))
68+
RC_TAG="v${NEXT_VERSION}-rc.${RC_NUM}"
69+
70+
echo "tag=${RC_TAG}" >> "$GITHUB_OUTPUT"
71+
echo "version=${NEXT_VERSION}-rc.${RC_NUM}" >> "$GITHUB_OUTPUT"
72+
echo "bump=${BUMP}" >> "$GITHUB_OUTPUT"
73+
74+
- name: Generate changelog
75+
id: changelog
76+
run: |
77+
LATEST_TAG=$(git tag --sort=-v:refname | head -1)
78+
if [ -z "$LATEST_TAG" ]; then
79+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" HEAD)
80+
else
81+
CHANGELOG=$(git log --pretty=format:"- %s (%h)" "${LATEST_TAG}..HEAD")
82+
fi
83+
{
84+
echo "changelog<<EOF"
85+
echo "$CHANGELOG"
86+
echo "EOF"
87+
} >> "$GITHUB_OUTPUT"
88+
89+
- name: Create RC tag
90+
run: |
91+
git tag "${{ steps.version.outputs.tag }}"
92+
git push origin "${{ steps.version.outputs.tag }}"
93+
94+
- name: Create GitHub pre-release
95+
uses: softprops/action-gh-release@v2
96+
with:
97+
tag_name: ${{ steps.version.outputs.tag }}
98+
name: ${{ steps.version.outputs.tag }}
99+
body: |
100+
## Pre-release: ${{ steps.version.outputs.tag }}
101+
102+
**Version bump**: `${{ steps.version.outputs.bump }}` (determined from conventional commits)
103+
104+
${{ steps.changelog.outputs.changelog }}
105+
draft: false
106+
prerelease: true
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Lint & Security Scan
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: read
10+
security-events: write
11+
12+
jobs:
13+
lint:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
19+
- name: Install uv
20+
uses: astral-sh/setup-uv@v5
21+
22+
- name: Set up Python
23+
run: uv python install 3.13
24+
25+
- name: Install dependencies
26+
run: uv sync --all-extras
27+
28+
- name: Ruff lint
29+
run: uv run ruff check .
30+
31+
- name: Ruff format check
32+
run: uv run ruff format --check .
33+
34+
security:
35+
runs-on: ubuntu-latest
36+
steps:
37+
- name: Checkout
38+
uses: actions/checkout@v4
39+
with:
40+
fetch-depth: 0
41+
42+
- name: Gitleaks secret scan
43+
uses: gitleaks/gitleaks-action@v2
44+
env:
45+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46+
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
47+
48+
- name: Install uv
49+
uses: astral-sh/setup-uv@v5
50+
51+
- name: Set up Python
52+
run: uv python install 3.13
53+
54+
- name: Install dependencies
55+
run: uv sync --all-extras
56+
57+
- name: Pip audit
58+
run: uv run pip-audit

.github/workflows/pull_request.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Pull Request
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
python-version: ["3.9", "3.12", "3.13"]
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Install uv
21+
uses: astral-sh/setup-uv@v5
22+
23+
- name: Set up Python ${{ matrix.python-version }}
24+
run: uv python install ${{ matrix.python-version }}
25+
26+
- name: Install dependencies
27+
run: uv sync --all-extras
28+
29+
- name: Run tests
30+
run: uv run pytest --tb=short -q

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ venv/
1010
.pytest_cache/
1111
.coverage
1212
htmlcov/
13+
*.so
14+
.mypy_cache/
15+
.ruff_cache/
16+
.env
17+
.env.*
18+
!.env.example
19+
*.lock
20+
Pulumi.*.yaml
21+
!Pulumi.yaml

.pre-commit-config.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v5.0.0
4+
hooks:
5+
- id: trailing-whitespace
6+
- id: end-of-file-fixer
7+
- id: check-yaml
8+
- id: check-added-large-files
9+
- id: check-merge-conflict
10+
- id: detect-private-key
11+
12+
- repo: https://github.com/astral-sh/ruff-pre-commit
13+
rev: v0.9.10
14+
hooks:
15+
- id: ruff
16+
args: [--fix]
17+
- id: ruff-format
18+
19+
- repo: https://github.com/gitleaks/gitleaks
20+
rev: v8.22.1
21+
hooks:
22+
- id: gitleaks

0 commit comments

Comments
 (0)