Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
f7f7012
PEP 639 compliance
DimitriPapadopoulos Jul 31, 2025
2121cde
No need to explictly specify LICENSE file
DimitriPapadopoulos Jul 31, 2025
5d84c3e
Phase 1 & 2: Setup vcs_versioning package and move core functionality
RonnyPfannschmidt Oct 12, 2025
39d7d4d
Phase 5: Rebuild setuptools_scm as integration layer + workspace setup
RonnyPfannschmidt Oct 12, 2025
45587ba
Fix test imports to use vcs_versioning for private APIs
RonnyPfannschmidt Oct 12, 2025
8d45e0b
Update progress tracker with Phase 5 completion status
RonnyPfannschmidt Oct 12, 2025
7effcd4
Migrate vcs-versioning to src layout and move passing tests
RonnyPfannschmidt Oct 12, 2025
918d1a8
Update progress: src layout and test migration complete
RonnyPfannschmidt Oct 12, 2025
0241064
Move entry points from setuptools_scm to vcs-versioning
RonnyPfannschmidt Oct 12, 2025
bb5edd7
Fix test monkeypatching and get_version() positional argument
RonnyPfannschmidt Oct 12, 2025
3f55d14
Implement proper logging configuration with explicit entry points
RonnyPfannschmidt Oct 12, 2025
6e22672
Fix logging configuration, empty tag regex warning, and test patches
RonnyPfannschmidt Oct 12, 2025
012453f
Add missing re-exports and warning for setuptools.dynamic conflict
RonnyPfannschmidt Oct 12, 2025
cf34d49
Fix test mocks to patch actual module locations
RonnyPfannschmidt Oct 12, 2025
8c30e5a
Update progress: All migration phases complete
RonnyPfannschmidt Oct 12, 2025
d643e09
refactor: migrate test infrastructure to vcs_versioning.test_api
RonnyPfannschmidt Oct 12, 2025
16f2cc9
docs: update progress summary with test infrastructure migration details
RonnyPfannschmidt Oct 12, 2025
db199f7
fix: use Self return type for PyProjectData.for_testing
RonnyPfannschmidt Oct 12, 2025
3499d32
ci: migrate api-check workflow to use uv instead of pip
RonnyPfannschmidt Oct 12, 2025
fecf4ff
ci: migrate Read the Docs configuration to use uv
RonnyPfannschmidt Oct 12, 2025
58e1ec7
Merge PR #1166: PEP 639 compliance
RonnyPfannschmidt Oct 12, 2025
dfd8305
Drop Python 3.8 and 3.9 support
RonnyPfannschmidt Oct 12, 2025
d9886da
ci: use baipp to build both packages and test them together
RonnyPfannschmidt Oct 12, 2025
7968d36
fix: update code for Python 3.10+ minimum version
RonnyPfannschmidt Oct 12, 2025
c164c1b
fix: downgrade GitHub Actions artifact actions from v5 to v4
RonnyPfannschmidt Oct 12, 2025
37ef6a8
fix: add unique artifact name suffixes to prevent upload conflicts
RonnyPfannschmidt Oct 12, 2025
b060b51
fix: configure unique artifact names for dual-package build
RonnyPfannschmidt Oct 12, 2025
e3ec938
fix: clean up baipp artifacts between builds
RonnyPfannschmidt Oct 13, 2025
0afc5b9
refactor: use matrix strategy for package builds
RonnyPfannschmidt Oct 13, 2025
d6fea05
refactor: migrate integration code to vcs-versioning and remove priva…
RonnyPfannschmidt Oct 13, 2025
7e6003f
refactor: make config module private (_config.py)
RonnyPfannschmidt Oct 13, 2025
057c509
refactor: remove unused private shim modules
RonnyPfannschmidt Oct 13, 2025
97b8bdf
refactor: remove _get_version_impl.py shim
RonnyPfannschmidt Oct 13, 2025
e239bbe
docs: update .wip files with current migration state
RonnyPfannschmidt Oct 13, 2025
091feb8
docs: remove .wip directory
RonnyPfannschmidt Oct 13, 2025
df7939a
feat: configure version detection for vcs-versioning with tag prefix
RonnyPfannschmidt Oct 13, 2025
ffefa45
refactor: simplify API check workflow and add baseline comparison
RonnyPfannschmidt Oct 13, 2025
417d7c4
fix: add typing-extensions as build dependency for Python 3.10
RonnyPfannschmidt Oct 13, 2025
5968fba
fix: query PyPI version before building in API check
RonnyPfannschmidt Oct 13, 2025
1ac9328
fix: use git tag instead of package spec for griffe comparison
RonnyPfannschmidt Oct 13, 2025
9510d48
refactor: convert wildcard re-exports to explicit imports for griffe …
RonnyPfannschmidt Oct 13, 2025
a265596
refactor: remove AlwaysStdErrHandler and setuptools_scm._log module
RonnyPfannschmidt Oct 13, 2025
196a1c1
WIP: Restructure: Split into setuptools-scm/ and vcs-versioning/ work…
RonnyPfannschmidt Oct 13, 2025
0ebad7a
Fix workspace support and configure dependency groups
RonnyPfannschmidt Oct 13, 2025
d17de42
Add workspace-level tooling configuration
RonnyPfannschmidt Oct 13, 2025
18d78a8
Fix documentation references for split codebase
RonnyPfannschmidt Oct 13, 2025
77d98c3
Add site/ directory to .gitignore
RonnyPfannschmidt Oct 13, 2025
1820777
Update GitHub Actions to use uv sync --all-packages --all-groups
RonnyPfannschmidt Oct 13, 2025
162f7a8
correct check-api for branch differences between monorepo and legacy …
RonnyPfannschmidt Oct 13, 2025
ad61baf
drop missplaced strict=true from pytest config
RonnyPfannschmidt Oct 13, 2025
4b1feba
trim down workspace pyproject header
RonnyPfannschmidt Oct 13, 2025
716268b
Use uv run --no-sync in GitHub Actions
RonnyPfannschmidt Oct 13, 2025
91c5554
Remove test_next_semver_bad_tag test
RonnyPfannschmidt Oct 13, 2025
858e705
Move core version scheme tests to vcs-versioning
RonnyPfannschmidt Oct 13, 2025
7f905b4
Move test_expect_parse to vcs-versioning
RonnyPfannschmidt Oct 13, 2025
abc6f07
Move core configuration tests to vcs-versioning
RonnyPfannschmidt Oct 13, 2025
331a323
Move error handling tests to vcs-versioning
RonnyPfannschmidt Oct 13, 2025
78cda9c
Split regression tests by architectural layer
RonnyPfannschmidt Oct 13, 2025
5adb644
Remove obsolete testing_vcs README
RonnyPfannschmidt Oct 13, 2025
d6c911b
Document test organization structure
RonnyPfannschmidt Oct 13, 2025
c56cb24
feat: Implement towncrier-based release system with fragment-driven v…
RonnyPfannschmidt Oct 14, 2025
16dd557
refactor: Remove extract_version script, parse from PR title instead
RonnyPfannschmidt Oct 14, 2025
d936746
docs: Compact RELEASE_SYSTEM.md further
RonnyPfannschmidt Oct 14, 2025
d9d9604
feat: Auto-trigger release PRs with unified Python automation
RonnyPfannschmidt Oct 14, 2025
5ffbb5b
fix: Use Configuration.from_file and proper vcs_versioning APIs
RonnyPfannschmidt Oct 14, 2025
4e96b87
fix: Make PyGithub a non-Windows dependency
RonnyPfannschmidt Oct 14, 2025
d18c32e
sync uv lock
RonnyPfannschmidt Oct 14, 2025
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
6 changes: 4 additions & 2 deletions .cursor/rules/test-running.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ globs:
alwaysApply: true
---

use `uv run pytest` to run tests
use `uv run pytest -n12` to run tests
use uv to manage dependencies

follow preexisting conventions in the project

- use the fixtures
- use the fixtures

to test the next gen project use `uv run pytest nextgen -n12`
150 changes: 150 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Reusable Workflows for Towncrier-based Releases

This directory contains reusable GitHub Actions workflows that other projects can use to implement the same towncrier-based release process.

## Available Reusable Workflows

### `reusable-towncrier-release.yml`

Determines the next version using the `towncrier-fragments` version scheme and builds the changelog.

**Inputs:**
- `project_name` (required): Name of the project (used for labeling and tag prefix)
- `project_directory` (required): Directory containing the project (relative to repository root)

**Outputs:**
- `version`: The determined next version
- `has_fragments`: Whether fragments were found

**Behavior:**
- ✅ Strict validation - workflow fails if changelog fragments or version data is missing
- ✅ No fallback values - ensures data integrity for releases
- ✅ Clear error messages to guide troubleshooting

**Example usage:**

```yaml
jobs:
determine-version:
uses: pypa/setuptools-scm/.github/workflows/reusable-towncrier-release.yml@main
with:
project_name: my-project
project_directory: ./
```

## Using These Workflows in Your Project

### Prerequisites

1. **Add vcs-versioning dependency** to your project
2. **Configure towncrier** in your `pyproject.toml`:

```toml
[tool.towncrier]
directory = "changelog.d"
filename = "CHANGELOG.md"
start_string = "<!-- towncrier release notes start -->\n"
template = "changelog.d/template.md"
title_format = "## {version} ({project_date})"

[[tool.towncrier.type]]
directory = "removal"
name = "Removed"
showcontent = true

[[tool.towncrier.type]]
directory = "feature"
name = "Added"
showcontent = true

[[tool.towncrier.type]]
directory = "bugfix"
name = "Fixed"
showcontent = true
```

3. **Create changelog structure**:
- `changelog.d/` directory
- `changelog.d/template.md` (towncrier template)
- `CHANGELOG.md` with the start marker

4. **Add the version scheme entry point** (if using vcs-versioning):

The `towncrier-fragments` version scheme is provided by vcs-versioning 0.2.0+.

### Complete Example Workflow

```yaml
name: Create Release

on:
workflow_dispatch:
inputs:
create_release:
description: 'Create release'
required: true
type: boolean
default: false

permissions:
contents: write
pull-requests: write

jobs:
determine-version:
uses: pypa/setuptools-scm/.github/workflows/reusable-towncrier-release.yml@main
with:
project_name: my-project
project_directory: ./

create-release-pr:
needs: determine-version
if: needs.determine-version.outputs.has_fragments == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Download changelog artifacts
uses: actions/download-artifact@v4
with:
name: changelog-my-project

- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
commit-message: "Release v${{ needs.determine-version.outputs.version }}"
branch: release-${{ needs.determine-version.outputs.version }}
title: "Release v${{ needs.determine-version.outputs.version }}"
labels: release:my-project
body: |
Automated release PR for version ${{ needs.determine-version.outputs.version }}
```

## Architecture

The workflow system is designed with these principles:

1. **Version scheme is single source of truth** - No version calculation in scripts
2. **Reusable components** - Other projects can use the same workflows
3. **Manual approval** - Release PRs must be reviewed and merged
4. **Project-prefixed tags** - Enable monorepo releases (`project-vX.Y.Z`)
5. **Automated but controlled** - Automation with human approval gates
6. **Fail fast** - No fallback values; workflows fail explicitly if required data is missing
7. **No custom scripts** - Uses PR title parsing and built-in tools only

## Version Bump Logic

The `towncrier-fragments` version scheme determines bumps based on fragment types:

| Fragment Type | Version Bump | Example |
|---------------|--------------|---------|
| `removal` | Major (X.0.0) | Breaking changes |
| `feature`, `deprecation` | Minor (0.X.0) | New features |
| `bugfix`, `doc`, `misc` | Patch (0.0.X) | Bug fixes |

## Support

For issues or questions about these workflows:
- Open an issue at https://github.com/pypa/setuptools-scm/issues
- See full documentation in [CONTRIBUTING.md](../../CONTRIBUTING.md)

60 changes: 15 additions & 45 deletions .github/workflows/api-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,52 +28,22 @@ jobs:
with:
python-version: '3.11'

- name: Install dependencies
run: |
pip install -U pip setuptools
pip install -e .[test]
pip install griffe
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v6

- name: Run griffe API check
id: griffe-check
continue-on-error: true
- name: Get latest release tag
id: latest-tag
run: |
echo "Running griffe API stability check..."
if griffe check setuptools_scm -ssrc -f github; then
echo "api_check_result=success" >> $GITHUB_OUTPUT
echo "exit_code=0" >> $GITHUB_OUTPUT
else
exit_code=$?
echo "api_check_result=warning" >> $GITHUB_OUTPUT
echo "exit_code=$exit_code" >> $GITHUB_OUTPUT
exit $exit_code
fi
# Get the latest git tag (griffe needs a git ref)
LATEST_TAG=$(git describe --tags --abbrev=0 origin/main 2>/dev/null || echo "v9.2.1")
echo "Latest release tag: $LATEST_TAG"
echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT

- name: Report API check result
if: always()
uses: actions/github-script@v8
with:
script: |
const result = '${{ steps.griffe-check.outputs.api_check_result }}'
const exitCode = '${{ steps.griffe-check.outputs.exit_code }}'
- name: Install dependencies
run: uv sync --all-packages --all-groups

if (result === 'success') {
core.notice('API stability check passed - no breaking changes detected')
await core.summary
.addHeading('✅ API Stability Check: Passed', 2)
.addRaw('No breaking changes detected in the public API')
.write()
} else if (result === 'warning') {
core.warning(`API stability check detected breaking changes (exit code: ${exitCode}). Please review the API changes above.`)
await core.summary
.addHeading('⚠️ API Stability Warning', 2)
.addRaw('Breaking changes detected in the public API. Please review the changes reported above.')
.addRaw(`\n\nExit code: ${exitCode}`)
.write()
} else {
core.error('API stability check failed to run properly')
await core.summary
.addHeading('❌ API Stability Check: Failed', 2)
.addRaw('The griffe check failed to execute. This may indicate griffe is not installed or there was an error.')
.write()
}
- name: Check API stability against latest release
run: |
echo "Comparing current code against tag: ${{ steps.latest-tag.outputs.tag }}"
# Use local check_api.py script which includes griffe-public-wildcard-imports extension
uv run --no-sync python setuptools-scm/check_api.py --against ${{ steps.latest-tag.outputs.tag }}
145 changes: 145 additions & 0 deletions .github/workflows/create-release-tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
name: Create Release Tags

on:
pull_request:
types: [closed]
branches:
- main

permissions:
contents: write

jobs:
create-tags:
# Only run if PR was merged and has release labels
if: |
github.event.pull_request.merged == true &&
(contains(github.event.pull_request.labels.*.name, 'release:setuptools-scm') ||
contains(github.event.pull_request.labels.*.name, 'release:vcs-versioning'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.merge_commit_sha }}

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.11'

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Create tags
id: create-tags
run: |
set -e

TAGS_CREATED=""
PR_TITLE="${{ github.event.pull_request.title }}"

# Check if we should release setuptools-scm
if echo "${{ toJson(github.event.pull_request.labels.*.name) }}" | grep -q "release:setuptools-scm"; then
# Extract version from PR title: "Release: setuptools-scm v9.3.0, ..."
VERSION=$(echo "$PR_TITLE" | grep -oP 'setuptools-scm v\K[0-9]+\.[0-9]+\.[0-9]+')

if [ -z "$VERSION" ]; then
echo "ERROR: Failed to extract setuptools-scm version from PR title"
echo "PR title: $PR_TITLE"
echo "Expected format: 'Release: setuptools-scm vX.Y.Z'"
exit 1
fi

TAG="setuptools-scm-v$VERSION"
echo "Creating tag: $TAG"

git tag -a "$TAG" -m "Release setuptools-scm v$VERSION"
git push origin "$TAG"

TAGS_CREATED="$TAGS_CREATED $TAG"
echo "setuptools_scm_tag=$TAG" >> $GITHUB_OUTPUT
echo "setuptools_scm_version=$VERSION" >> $GITHUB_OUTPUT
fi

# Check if we should release vcs-versioning
if echo "${{ toJson(github.event.pull_request.labels.*.name) }}" | grep -q "release:vcs-versioning"; then
# Extract version from PR title: "Release: ..., vcs-versioning v0.2.0"
VERSION=$(echo "$PR_TITLE" | grep -oP 'vcs-versioning v\K[0-9]+\.[0-9]+\.[0-9]+')

if [ -z "$VERSION" ]; then
echo "ERROR: Failed to extract vcs-versioning version from PR title"
echo "PR title: $PR_TITLE"
echo "Expected format: 'Release: vcs-versioning vX.Y.Z'"
exit 1
fi

TAG="vcs-versioning-v$VERSION"
echo "Creating tag: $TAG"

git tag -a "$TAG" -m "Release vcs-versioning v$VERSION"
git push origin "$TAG"

TAGS_CREATED="$TAGS_CREATED $TAG"
echo "vcs_versioning_tag=$TAG" >> $GITHUB_OUTPUT
echo "vcs_versioning_version=$VERSION" >> $GITHUB_OUTPUT
fi

echo "tags_created=$TAGS_CREATED" >> $GITHUB_OUTPUT

- name: Extract changelog for setuptools-scm
if: steps.create-tags.outputs.setuptools_scm_version
id: changelog-setuptools-scm
run: |
VERSION="${{ steps.create-tags.outputs.setuptools_scm_version }}"
cd setuptools-scm

# Extract the changelog section for this version
# Read from version heading until next version heading or EOF
CHANGELOG=$(awk "/^## $VERSION/,/^## [0-9]/" CHANGELOG.md | sed '1d;$d')

# Save to file for GitHub release
echo "$CHANGELOG" > /tmp/changelog-setuptools-scm.md

- name: Extract changelog for vcs-versioning
if: steps.create-tags.outputs.vcs_versioning_version
id: changelog-vcs-versioning
run: |
VERSION="${{ steps.create-tags.outputs.vcs_versioning_version }}"
cd vcs-versioning

# Extract the changelog section for this version
CHANGELOG=$(awk "/^## $VERSION/,/^## [0-9]/" CHANGELOG.md | sed '1d;$d')

# Save to file for GitHub release
echo "$CHANGELOG" > /tmp/changelog-vcs-versioning.md

- name: Create GitHub Release for setuptools-scm
if: steps.create-tags.outputs.setuptools_scm_tag
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.create-tags.outputs.setuptools_scm_tag }}
name: setuptools-scm v${{ steps.create-tags.outputs.setuptools_scm_version }}
body_path: /tmp/changelog-setuptools-scm.md
draft: false
prerelease: false

- name: Create GitHub Release for vcs-versioning
if: steps.create-tags.outputs.vcs_versioning_tag
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.create-tags.outputs.vcs_versioning_tag }}
name: vcs-versioning v${{ steps.create-tags.outputs.vcs_versioning_version }}
body_path: /tmp/changelog-vcs-versioning.md
draft: false
prerelease: false

- name: Summary
run: |
echo "## Tags Created" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.create-tags.outputs.tags_created }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "PyPI upload will be triggered automatically by tag push." >> $GITHUB_STEP_SUMMARY

Loading