Skip to content

Commit e2c3f15

Browse files
Adding versioning workflow [bump] (#8)
* [info] Update info.yaml version to 2.5.0 * adding versioning workflow --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent f4f9a1e commit e2c3f15

File tree

6 files changed

+350
-69
lines changed

6 files changed

+350
-69
lines changed

.githooks/README.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# CONTRIBUTING.md
2+
3+
## Introduction
4+
5+
Thank you for contributing to this project.
6+
7+
This repository uses Git hooks and structured commit messages to manage versioning metadata in `lib/info.yaml`. When making commits, your messages help automate version bumps and update commit metadata. Please follow the guidelines below.
8+
9+
---
10+
11+
## Setup (one-time)
12+
13+
This project uses project-scoped Git hooks stored in `.githooks/`.
14+
15+
To enable them in your local clone:
16+
17+
1. Set Git to use the project hooks directory:
18+
19+
```bash
20+
git config core.hooksPath .githooks
21+
```
22+
23+
2. Make sure all scripts are executable:
24+
25+
```bash
26+
chmod +x .githooks/*
27+
```
28+
29+
---
30+
31+
## Commit Message Tags
32+
33+
Your commit message controls how the version is updated. Tag your commits with one of:
34+
35+
| Tag | Action | Example |
36+
|--------------------|----------------------------------------|----------------------------------------|
37+
| `[major]` | Bump major version (X → X+1.0.0) | `Rewrite internals [major]` |
38+
| `[minor]` | Bump minor version (Y → Y+1) | `Add option for format [minor]` |
39+
| `[patch]` | Bump patch version (Z → Z+1) | `Fix typos and style [patch]` |
40+
| `[bump]` | Same as `[patch]`, for convenience | `Update citation link [bump]` |
41+
| `[vX.Y.Z]` | Set exact version (overrides bumps) | `Release new version [v2.5.0]` |
42+
| No tag or `[no v]` | Skip versioning; update timestamp only | `Adjust spacing [no v]` |
43+
44+
Multiple tags are allowed, but the most significant one will take effect:
45+
`[major] > [minor] > [patch]/[bump]`
46+
47+
Redundant tags will trigger a warning.
48+
49+
---
50+
51+
## What Happens Automatically
52+
53+
When you commit:
54+
55+
- The `commit-msg` hook:
56+
- Parses your message
57+
- Validates version changes
58+
- Updates `lib/info.yaml` fields:
59+
- `version`
60+
- `releasedate-*`
61+
- `latest-commit-msg`
62+
- `latest-commit-date`
63+
- Rejects duplicate or downgraded versions
64+
- Prints warnings for large version jumps
65+
66+
- The `post-commit` hook:
67+
- If `info.yaml` was modified, creates a second commit:
68+
69+
```
70+
[info]
71+
```
72+
73+
- This ensures metadata is added reliably without interfering with your working commit
74+
75+
---
76+
77+
## Examples
78+
79+
```bash
80+
git commit -m "Add option [minor]"
81+
git commit -m "Adjust wording [bump]"
82+
git commit -m "Release 3.0 final [v3.0.0]"
83+
git commit -m "Improve formatting"
84+
```
85+
86+
After each commit, you can check that the hooks ran and updated the info file with:
87+
88+
```bash
89+
git log --oneline -n 2
90+
git diff HEAD~1 lib/info.yaml
91+
```
92+
93+
---
94+
95+
## Notes
96+
97+
- Be sure to `git add` the files you want in the commit before running `git commit`
98+
- You do not need to stage or edit `lib/info.yaml` — it is handled automatically
99+
- Do not squash or remove `[info]` commits — they are part of the versioning log
100+
101+
---
102+
103+
## Troubleshooting
104+
105+
- **Hook not firing?**
106+
- Check that `.githooks/commit-msg` and `.githooks/post-commit` are executable
107+
- Ensure `git config core.hooksPath` is set properly
108+
109+
- **Version not updating?**
110+
- Make sure you included a bump tag in your commit (like `[patch]` or `[v2.3.0]`)
111+
112+
- **Accidentally repeated a version?**
113+
- Add `[allow same version]` to override
114+
115+
---
116+
117+
## Thank You
118+
119+
We appreciate your contributions. Reliable versioning ensures reproducibility and clear project history.
120+
121+
Need help? Open an issue or contact the maintainers directly.
File renamed without changes.
File renamed without changes.

.github/scripts/update_version.sh

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/bin/bash
2+
set -e
3+
4+
YAML_FILE="lib/info.yaml"
5+
COMMIT_MSG="$(git log -1 --pretty=%B)"
6+
DATE=$(date +'%Y-%m-%d')
7+
8+
if [ ! -f "$YAML_FILE" ]; then
9+
echo "YAML file not found: $YAML_FILE"
10+
exit 0
11+
fi
12+
13+
# [info] auto-commit check
14+
if [ "$COMMIT_MSG" == "[info]" ]; then
15+
exit 0
16+
fi
17+
18+
ESCAPED_COMMIT_MSG=$(printf '%s' "$COMMIT_MSG" | sed 's/"/\\"/g')
19+
20+
# Update latest-commit-msg
21+
if grep -q "^latest-commit-msg:" "$YAML_FILE"; then
22+
sed -i "s/^latest-commit-msg:.*/latest-commit-msg: \"$ESCAPED_COMMIT_MSG\"/" "$YAML_FILE"
23+
else
24+
echo "latest-commit-msg: \"$ESCAPED_COMMIT_MSG\"" >> "$YAML_FILE"
25+
fi
26+
27+
# [no v] — only update latest-commit-date
28+
if echo "$COMMIT_MSG" | grep -q '\[no v\]'; then
29+
sed -i "s/^latest-commit-date:.*/latest-commit-date: ${DATE}/" "$YAML_FILE"
30+
exit 0
31+
fi
32+
33+
CURRENT_VERSION=$(grep '^version:' "$YAML_FILE" | awk '{print $2}')
34+
IFS='.' read -r OLD_MAJOR OLD_MINOR OLD_PATCH <<< "$CURRENT_VERSION"
35+
36+
NEW_MAJOR="$OLD_MAJOR"
37+
NEW_MINOR="$OLD_MINOR"
38+
NEW_PATCH="$OLD_PATCH"
39+
NEW_VERSION=""
40+
USED_OVERRIDE=0
41+
42+
# Process [vX.Y.Z] version override
43+
VERSION_OVERRIDE=$(echo "$COMMIT_MSG" | grep -o '\[v[0-9]\+\.[0-9]\+\.[0-9]\+\]' | tr -d '[]v')
44+
45+
if [ -n "$VERSION_OVERRIDE" ]; then
46+
USED_OVERRIDE=1
47+
if ! echo "$VERSION_OVERRIDE" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
48+
echo "Error: Invalid version string: [v$VERSION_OVERRIDE]"
49+
exit 1
50+
fi
51+
52+
IFS='.' read -r NEW_MAJOR NEW_MINOR NEW_PATCH <<< "$VERSION_OVERRIDE"
53+
54+
# Reject same version unless [allow same version]
55+
if [ "$NEW_MAJOR" -eq "$OLD_MAJOR" ] && [ "$NEW_MINOR" -eq "$OLD_MINOR" ] && [ "$NEW_PATCH" -eq "$OLD_PATCH" ]; then
56+
if echo "$COMMIT_MSG" | grep -q '\[allow same version\]'; then
57+
echo "Warning: Same version used again [$VERSION_OVERRIDE] (allowed by tag)."
58+
else
59+
echo "Error: Version $VERSION_OVERRIDE is already current. Use [allow same version] to bypass."
60+
exit 1
61+
fi
62+
fi
63+
64+
# Reject downgrades
65+
if [ "$NEW_MAJOR" -lt "$OLD_MAJOR" ] || \
66+
{ [ "$NEW_MAJOR" -eq "$OLD_MAJOR" ] && [ "$NEW_MINOR" -lt "$OLD_MINOR" ]; } || \
67+
{ [ "$NEW_MAJOR" -eq "$OLD_MAJOR" ] && [ "$NEW_MINOR" -eq "$OLD_MINOR" ] && [ "$NEW_PATCH" -lt "$OLD_PATCH" ]; }
68+
then
69+
echo "Error: Version downgrade is not allowed."
70+
echo "Old: $CURRENT_VERSION, New: $VERSION_OVERRIDE"
71+
exit 1
72+
fi
73+
74+
# Warn on large jumps
75+
MAJOR_DIFF=$((NEW_MAJOR - OLD_MAJOR))
76+
MINOR_DIFF=$((NEW_MINOR - OLD_MINOR))
77+
PATCH_DIFF=$((NEW_PATCH - OLD_PATCH))
78+
79+
if [ "$MAJOR_DIFF" -gt 1 ] || [ "$MINOR_DIFF" -gt 1 ] || [ "$PATCH_DIFF" -gt 1 ]; then
80+
echo "Warning: Version increase greater than 1:"
81+
[ "$MAJOR_DIFF" -gt 1 ] && echo " Major: $OLD_MAJOR$NEW_MAJOR"
82+
[ "$MINOR_DIFF" -gt 1 ] && echo " Minor: $OLD_MINOR$NEW_MINOR"
83+
[ "$PATCH_DIFF" -gt 1 ] && echo " Patch: $OLD_PATCH$NEW_PATCH"
84+
fi
85+
86+
NEW_VERSION="$NEW_MAJOR.$NEW_MINOR.$NEW_PATCH"
87+
88+
else
89+
# Auto semantic bump if tagged
90+
BUMP_TAG_COUNT=$(echo "$COMMIT_MSG" | grep -o '\[\(major\|minor\|patch\|bump\)\]' | wc -l)
91+
92+
if [ "$BUMP_TAG_COUNT" -gt 1 ]; then
93+
echo "Warning: Multiple bump tags found. Using highest priority (major > minor > patch > bump)."
94+
fi
95+
96+
if echo "$COMMIT_MSG" | grep -qE '\[major\]|\[bump-major\]'; then
97+
NEW_MAJOR=$((OLD_MAJOR+1)); NEW_MINOR=0; NEW_PATCH=0
98+
elif echo "$COMMIT_MSG" | grep -qE '\[minor\]|\[bump-minor\]'; then
99+
NEW_MINOR=$((OLD_MINOR+1)); NEW_PATCH=0
100+
elif echo "$COMMIT_MSG" | grep -qE '\[patch\]|\[bump-patch\]|\[bump\]'; then
101+
NEW_PATCH=$((OLD_PATCH+1))
102+
else
103+
sed -i "s/^latest-commit-date:.*/latest-commit-date: ${DATE}/" "$YAML_FILE"
104+
exit 0
105+
fi
106+
NEW_VERSION="$NEW_MAJOR.$NEW_MINOR.$NEW_PATCH"
107+
fi
108+
109+
# Apply version update
110+
sed -i "s/^version:.*/version: $NEW_VERSION/" "$YAML_FILE"
111+
112+
# Update release dates as needed
113+
if [ "$NEW_MAJOR" != "$OLD_MAJOR" ]; then
114+
sed -i "s/^releasedate-major:.*/releasedate-major: $DATE/" "$YAML_FILE"
115+
fi
116+
if [ "$NEW_MINOR" != "$OLD_MINOR" ]; then
117+
sed -i "s/^releasedate-minor:.*/releasedate-minor: $DATE/" "$YAML_FILE"
118+
fi
119+
if [ "$NEW_PATCH" != "$OLD_PATCH" ]; then
120+
sed -i "s/^releasedate-patch:.*/releasedate-patch: $DATE/" "$YAML_FILE"
121+
fi
122+
123+
# Always update latest-commit-date
124+
sed -i "s/^latest-commit-date:.*/latest-commit-date: ${DATE}/" "$YAML_FILE"
125+
126+
# Stage and commit if changed
127+
git config --global user.name "github-actions[bot]"
128+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
129+
git add "$YAML_FILE"
130+
if ! git diff --cached --quiet; then
131+
git commit -m "[info] Update info.yaml version to $NEW_VERSION"
132+
git push
133+
fi
134+
135+
# Tagging
136+
TAG="v${NEW_VERSION}"
137+
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
138+
git tag "$TAG"
139+
git push origin "$TAG"
140+
else
141+
echo "Tag $TAG already exists."
142+
fi
143+
144+
echo "NEW_VERSION=$NEW_VERSION" >> "$GITHUB_ENV"

.github/workflows/versioning.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Custom Versioning and Tagging
2+
3+
on:
4+
push:
5+
branches:
6+
- main # or your working branch
7+
8+
jobs:
9+
version:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: write # needed for tag creation
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Update version and tag if needed
19+
run: .github/scripts/update-version.sh

0 commit comments

Comments
 (0)