Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 1 addition & 93 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
test:
name: Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -47,95 +47,3 @@ jobs:
run: |
# Run tests using unittest (project uses unittest framework)
uv run python -m unittest discover -s tests -p "test_*.py" -v || echo "Tests completed with warnings or failures"

auto-version:
name: Auto Version Increment
runs-on: ubuntu-latest
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master')
permissions:
contents: write

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 2

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"

- name: Check for code changes
id: check-changes
run: |
# Get the previous commit (before the current push)
PREV_COMMIT=$(git rev-parse HEAD~1 2>/dev/null || echo "")

if [ -z "$PREV_COMMIT" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "First commit or unable to determine previous commit, will increment version"
exit 0
fi

# Check if there are any changes in code files (excluding version file, docs, and CI files)
CHANGED_FILES=$(git diff --name-only $PREV_COMMIT HEAD | grep -v -E '^(fastskills/__version__|\.github/workflows/|README\.md|README\.zh\.md|\.gitignore|\.gitattributes)' || true)

if [ -z "$CHANGED_FILES" ]; then
echo "changed=false" >> $GITHUB_OUTPUT
echo "No code changes detected, skipping version increment"
else
echo "changed=true" >> $GITHUB_OUTPUT
echo "Code changes detected in:"
echo "$CHANGED_FILES"
echo "Will increment patch version"
fi

- name: Get current version
if: steps.check-changes.outputs.changed == 'true'
id: current-version
run: |
CURRENT_VERSION=$(cat fastskills/__version__)
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT_VERSION"

- name: Increment patch version
if: steps.check-changes.outputs.changed == 'true'
id: new-version
run: |
python3 scripts/bump_version.py patch
NEW_VERSION=$(cat fastskills/__version__)
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"

- name: Commit and push version change
if: steps.check-changes.outputs.changed == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add fastskills/__version__

# Check if there are changes to commit
if git diff --staged --quiet; then
echo "No version changes to commit"
exit 0
fi

NEW_VERSION="${{ steps.new-version.outputs.version }}"
git commit -m "chore: auto-increment patch version to $NEW_VERSION [skip ci]"

# Push with retry logic
for i in 1 2 3; do
if git push; then
echo "Version update pushed successfully"
exit 0
else
echo "Push failed, attempt $i/3"
sleep 2
git pull --rebase || true
fi
done

echo "Failed to push version update after 3 attempts"
exit 1
16 changes: 15 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: mypy mypy-fix ruff ruff-fix ruff-fix-unsafe version patch-version-increment minor-version-increment major-version-increment version-set help
.PHONY: mypy mypy-fix ruff ruff-fix ruff-fix-unsafe version patch-version-increment minor-version-increment major-version-increment version-set install-hook help

help:
@echo "Available targets:"
Expand All @@ -12,6 +12,7 @@ help:
@echo " minor-version-increment - Increment minor version (0.1.0 -> 0.2.0)"
@echo " major-version-increment - Increment major version (0.1.0 -> 1.0.0)"
@echo " version-set - Set version to a specific value (usage: make version-set VERSION=1.2.3)"
@echo " install-hook - Install pre-commit hook for version checking"

mypy:
@echo "Running mypy type checking..."
Expand Down Expand Up @@ -61,3 +62,16 @@ version-set:
exit 1; \
fi
@python3 scripts/bump_version.py set $(VERSION)

install-hook:
@echo "Installing pre-commit hook for version checking..."
@if [ ! -d .git ]; then \
echo "Error: Not a git repository. Run this command from the project root."; \
exit 1; \
fi
@mkdir -p .git/hooks
@cp scripts/pre-commit-version-check.sh .git/hooks/pre-commit
@chmod +x .git/hooks/pre-commit
@echo "✓ Pre-commit hook installed successfully!"
@echo ""
@echo "The hook will now check that version numbers are updated when code changes are committed."
104 changes: 76 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,14 @@ Contributions are welcome! You can contribute by opening issues, submitting pull
pip install -e .
```

3. **Verify installation:**
4. **Install pre-commit hook (required):**

```bash
# Install the pre-commit hook using make
make install-hook
```

5. **Verify installation:**
```bash
python -c "import fastskills; print(fastskills.__version__)"
```
Expand Down Expand Up @@ -532,6 +539,12 @@ Before submitting a pull request, you **must** ensure your code passes all quali
- [ ] No hard-coded values (use constants)
- [ ] Proper error handling (no generic try-except)

- [ ] **Version Management:**
- [ ] Version number is updated if code changes were made
- [ ] Used appropriate version increment (patch/minor/major)
- [ ] Version file (`fastskills/__version__`) is included in the commit
- [ ] Pre-commit hook passes (automatically checks version updates)

- [ ] **Documentation:**
- [ ] Code is properly commented where necessary
- [ ] README is updated if needed (for user-facing changes)
Expand All @@ -553,13 +566,11 @@ The project includes GitHub Actions workflows that automatically run on every pu
- ✅ **Code Formatting** - Code must be properly formatted (checked by `ruff format`)
- ✅ **Tests** - Test suite runs automatically

**Auto Version Increment (main/master branch only):**
**Version Management:**

- ✅ **Patch versions are automatically incremented** when code changes are pushed to `main` or `master` branch
- The version increment is automatically committed back to the repository
- Only triggers when actual code files are changed (excludes documentation, CI config, and version file itself)
- **Note:** Contributors don't need to manually increment patch versions - this is handled automatically by CI/CD
- **For minor/major versions:** Use manual commands (`make minor-version-increment` or `make major-version-increment`) before merging
- ⚠️ **Version updates are required** - All code changes must include a version number update
- A pre-commit hook automatically checks that version is updated when code changes
- See [Version Management](#version-management) section below for details

**Available Make Targets:**

Expand All @@ -572,60 +583,97 @@ make ruff-fix # Auto-fix linting errors (safe fixes)
make ruff-fix-unsafe # Auto-fix linting errors (including unsafe fixes)
make version # Show current version
make patch-version-increment # Increment patch version
make minor-version-increment # Increment minor version
make minor-version-increment # Increment minor version
make major-version-increment # Increment major version
make version-set VERSION=x.y.z # Set version to a specific value
make install-hook # Install pre-commit hook for version checking
```

#### Version Management

FastSkills uses [Semantic Versioning](https://semver.org/) (MAJOR.MINOR.PATCH). The version is managed centrally in the `fastskills/__version__` file. The version is automatically read by `fastskills/__init__.py` (accessible via `fastskills.__version__`) and synchronized with `pyproject.toml` during package builds.

**Automatic Version Management (CI/CD):**

✅ **Patch Version** - **Automatically handled by CI/CD**
**⚠️ Important: Version Updates are Required**

- When code changes are pushed to `main` or `master` branch, the GitHub Actions workflow automatically increments the patch version
- Example: `0.1.0` → `0.1.1` (automatic on code changes)
- **No manual action required** - the CI/CD pipeline handles this automatically
- Only triggers when actual code files are changed (excludes documentation, CI config, and version file itself)
All code changes **must** include a version number update. A pre-commit hook automatically enforces this requirement - commits with code changes will be rejected if the version number is not updated.

**Manual Version Management:**
**Version Increment Guidelines:**

For **Minor** and **Major** version increments, use the manual commands:
- **Patch Version** (`make patch-version-increment`): Use for bug fixes and patches
- Example: `0.1.0` → `0.1.1`
- Use when: Fixing bugs, patching security issues, or making small improvements

- **Minor Version** (`make minor-version-increment`): Use for new features that don't break compatibility
- Example: `0.1.0` → `0.2.0`
- Use when: Adding new features, enhancements, or improvements that maintain backward compatibility
- **Manual action required** - run this command before merging to main/master

- **Major Version** (`make major-version-increment`): Use for breaking changes that may affect compatibility
- Example: `0.1.0` → `1.0.0`
- Use when: Making changes that break backward compatibility, significant API changes, or major architectural changes
- **Manual action required** - run this command before merging to main/master

**Version Management Commands:**

```bash
# Show current version
make version

# Manual version increments (for minor/major versions only)
# Note: Patch version is handled automatically by CI/CD
make minor-version-increment # 0.1.0 -> 0.2.0
make major-version-increment # 0.1.0 -> 1.0.0
# Increment version (choose based on your changes)
make patch-version-increment # 0.1.0 -> 0.1.1 (bug fixes)
make minor-version-increment # 0.1.0 -> 0.2.0 (new features)
make major-version-increment # 0.1.0 -> 1.0.0 (breaking changes)

# Set a specific version (for special cases)
make version-set VERSION=2.0.0
```

**Pre-Commit Hook:**

The project includes a pre-commit hook that automatically checks if the version number is updated when code changes are committed. This ensures version consistency across all commits.

**Installing the Pre-Commit Hook:**

```bash
# Install using make (recommended)
make install-hook

# Or manually
cp scripts/pre-commit-version-check.sh .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
```

**How It Works:**

1. When you commit code changes, the hook checks if any code files were modified (excluding docs, CI config, etc.)
2. If code changes are detected, it verifies that `fastskills/__version__` is also staged and updated
3. If version is not updated, the commit is rejected with instructions on how to fix it
4. If only documentation or CI files are changed, version update is not required

**Example Workflow:**

```bash
# 1. Make your code changes
vim fastskills/some_file.py

# 2. Stage your changes
git add fastskills/some_file.py

# 3. Update version (required!)
make patch-version-increment # or minor/major depending on changes

# 4. Stage the version file
git add fastskills/__version__

# 5. Commit (hook will verify version is updated)
git commit -m "fix: description of your changes"
```

**Version Management Summary:**

| Version Type | Increment Method | When to Use |
| ------------ | ------------------------ | ------------------------------------------------ |
| **Patch** | **Automatic (CI/CD)** | Bug fixes, patches (automatic on code changes) |
| **Minor** | 🔧 **Manual** | New features, enhancements (backward compatible) |
| **Major** | 🔧 **Manual** | Breaking changes, major API changes |
| Version Type | Increment Method | When to Use |
| ------------ | ---------------- | ------------------------------------------------ |
| **Patch** | 🔧 **Manual** | Bug fixes, patches, small improvements |
| **Minor** | 🔧 **Manual** | New features, enhancements (backward compatible) |
| **Major** | 🔧 **Manual** | Breaking changes, major API changes |

**Note:** If you're using `uv` (recommended), all commands will automatically use the project's virtual environment. If you're using `pip`, make sure to activate your virtual environment first.

Expand Down
2 changes: 1 addition & 1 deletion fastskills/__version__
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.1.1
93 changes: 93 additions & 0 deletions scripts/pre-commit-version-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/bash
# Pre-commit hook to check if version number is updated when code changes

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

VERSION_FILE="fastskills/__version__"

# Get the list of staged files
STAGED_FILES=$(git diff --cached --name-only)

# Check if version file is in the staged changes
VERSION_FILE_STAGED=$(echo "$STAGED_FILES" | grep -E "^$VERSION_FILE$" || true)

# Check if there are any code changes (excluding version file, docs, and CI files)
CODE_CHANGES=$(echo "$STAGED_FILES" | grep -v -E '^(fastskills/__version__|\.github/workflows/|README\.md|README\.zh\.md|\.gitignore|\.gitattributes|scripts/pre-commit-version-check\.sh)' || true)

# If no code changes, allow commit (version update not required)
if [ -z "$CODE_CHANGES" ]; then
echo -e "${GREEN}✓ No code changes detected, version update not required${NC}"
exit 0
fi

# If code changes exist but version file is not staged, reject commit
if [ -z "$VERSION_FILE_STAGED" ]; then
echo -e "${RED}✗ Error: Code changes detected but version number not updated!${NC}"
echo ""
echo -e "${YELLOW}You must update the version number when making code changes.${NC}"
echo ""
echo "To fix this, run one of the following commands:"
echo " make patch-version-increment # For bug fixes (0.1.0 -> 0.1.1)"
echo " make minor-version-increment # For new features (0.1.0 -> 0.2.0)"
echo " make major-version-increment # For breaking changes (0.1.0 -> 1.0.0)"
echo ""
echo "Then stage the version file:"
echo " git add $VERSION_FILE"
echo ""
echo "Or if you want to skip this check (not recommended):"
echo " git commit --no-verify"
exit 1
fi

# Check if version file actually changed
VERSION_DIFF=$(git diff --cached "$VERSION_FILE" 2>/dev/null || true)

if [ -z "$VERSION_DIFF" ]; then
echo -e "${RED}✗ Error: Version file is staged but no version change detected!${NC}"
echo ""
echo "The version file must be updated. Run one of:"
echo " make patch-version-increment"
echo " make minor-version-increment"
echo " make major-version-increment"
exit 1
fi

# Get old version from HEAD (what's currently committed)
OLD_VERSION=$(git show HEAD:"$VERSION_FILE" 2>/dev/null | head -n1 | tr -d '[:space:]' || echo "")

# Get new version from staged area (what will be committed)
NEW_VERSION=$(git show :"$VERSION_FILE" 2>/dev/null | head -n1 | tr -d '[:space:]' || echo "")

# Fallback: if git show fails, try reading from diff
if [ -z "$NEW_VERSION" ]; then
NEW_VERSION=$(echo "$VERSION_DIFF" | grep -E "^\+" | grep -v "^+++" | sed 's/^+//' | head -n1 | tr -d '[:space:]')
fi

if [ -z "$NEW_VERSION" ]; then
echo -e "${RED}✗ Error: Could not determine new version number!${NC}"
exit 1
fi

if [ -z "$OLD_VERSION" ]; then
# First commit, no old version in HEAD
echo -e "${GREEN}✓ Version file updated: $NEW_VERSION${NC}"
elif [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
echo -e "${RED}✗ Error: Version file staged but version number unchanged!${NC}"
echo ""
echo "Current version: $OLD_VERSION"
echo "Staged version: $NEW_VERSION"
echo ""
echo "The version number must be different. Run one of:"
echo " make patch-version-increment"
echo " make minor-version-increment"
echo " make major-version-increment"
exit 1
else
echo -e "${GREEN}✓ Version updated: $OLD_VERSION -> $NEW_VERSION${NC}"
fi

exit 0