| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d7ac93b commit 0711683
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,30 @@ | |||
| 1 | + extends: | ||
| 2 | + - '@commitlint/config-conventional' | ||
| 3 | + | ||
| 4 | + rules: | ||
| 5 | + type-enum: | ||
| 6 | + - 2 | ||
| 7 | + - always | ||
| 8 | + - - build | ||
| 9 | + - chore | ||
| 10 | + - ci | ||
| 11 | + - docs | ||
| 12 | + - feat | ||
| 13 | + - fix | ||
| 14 | + - perf | ||
| 15 | + - refactor | ||
| 16 | + - revert | ||
| 17 | + - style | ||
| 18 | + - test | ||
| 19 | + scope-case: | ||
| 20 | + - 0 | ||
| 21 | + subject-case: | ||
| 22 | + - 0 | ||
| 23 | + header-max-length: | ||
| 24 | + - 1 | ||
| 25 | + - always | ||
| 26 | + - 100 | ||
| 27 | + body-max-line-length: | ||
| 28 | + - 0 | ||
| 29 | + footer-max-line-length: | ||
| 30 | + - 0 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,46 @@ | |||
| 1 | + name: PR Lint | ||
| 2 | + | ||
| 3 | + on: | ||
| 4 | + pull_request: | ||
| 5 | + types: [opened, edited, synchronize, reopened] | ||
| 6 | + | ||
| 7 | + permissions: | ||
| 8 | + pull-requests: read | ||
| 9 | + | ||
| 10 | + jobs: | ||
| 11 | + pr-title: | ||
| 12 | + name: PR title (Conventional Commits) | ||
| 13 | + runs-on: ubuntu-latest | ||
| 14 | + steps: | ||
| 15 | + - name: Validate PR title | ||
| 16 | + uses: amannn/action-semantic-pull-request@v5 | ||
| 17 | + env: | ||
| 18 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| 19 | + with: | ||
| 20 | + types: | | ||
| 21 | + build | ||
| 22 | + chore | ||
| 23 | + ci | ||
| 24 | + docs | ||
| 25 | + feat | ||
| 26 | + fix | ||
| 27 | + perf | ||
| 28 | + refactor | ||
| 29 | + revert | ||
| 30 | + style | ||
| 31 | + test | ||
| 32 | + requireScope: false | ||
| 33 | + subjectPattern: ^[a-z].+[^.]$ | ||
| 34 | + subjectPatternError: | | ||
| 35 | + Subject "{subject}" must start with a lowercase letter and must not | ||
| 36 | + end with a period. | ||
| 37 | + Example: "feat(cli): add init subcommand" | ||
| 38 | + | ||
| 39 | + commits: | ||
| 40 | + name: Commit messages | ||
| 41 | + runs-on: ubuntu-latest | ||
| 42 | + steps: | ||
| 43 | + - uses: actions/checkout@v4 | ||
| 44 | + with: | ||
| 45 | + fetch-depth: 0 | ||
| 46 | + - uses: wagoid/commitlint-github-action@v6 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,31 +1,77 @@ | |||
| 1 | - name: Release to PyPI | ||
| 1 | + name: Release | ||
| 2 | 2 | ||
| 3 | 3 | on: | |
| 4 | 4 | push: | |
| 5 | - tags: | ||
| 6 | - - 'v*.*.*' | ||
| 5 | + branches: [main] | ||
| 6 | + workflow_dispatch: | ||
| 7 | + | ||
| 8 | + # ┌─────────────────────────────────────────────────────────────────┐ | ||
| 9 | + # │ DRAFT_RELEASE │ | ||
| 10 | + # │ │ | ||
| 11 | + # │ "true" → GitHub Releases are created as drafts and PyPI │ | ||
| 12 | + # │ publishing is skipped (burn-in / review period). │ | ||
| 13 | + # │ "false" → GitHub Releases are published immediately and the │ | ||
| 14 | + # │ package is uploaded to PyPI. │ | ||
| 15 | + # │ │ | ||
| 16 | + # │ Flip to "false" once you have verified the release output. │ | ||
| 17 | + # └─────────────────────────────────────────────────────────────────┘ | ||
| 18 | + env: | ||
| 19 | + DRAFT_RELEASE: "true" | ||
| 7 | 20 | ||
| 8 | 21 | jobs: | |
| 9 | - build-and-publish: | ||
| 22 | + release: | ||
| 23 | + name: Semantic Release | ||
| 10 | 24 | runs-on: ubuntu-latest | |
| 25 | + if: >- | ||
| 26 | + github.event_name == 'workflow_dispatch' || | ||
| 27 | + !startsWith(github.event.head_commit.message, 'chore(release):') | ||
| 28 | + concurrency: | ||
| 29 | + group: release | ||
| 30 | + cancel-in-progress: false | ||
| 11 | 31 | permissions: | |
| 12 | - contents: read | ||
| 32 | + contents: write | ||
| 13 | 33 | id-token: write | |
| 34 | + | ||
| 14 | 35 | steps: | |
| 15 | 36 | - name: Checkout | |
| 16 | 37 | uses: actions/checkout@v4 | |
| 38 | + with: | ||
| 39 | + fetch-depth: 0 | ||
| 17 | 40 | ||
| 18 | 41 | - name: Set up Python | |
| 19 | 42 | uses: actions/setup-python@v5 | |
| 20 | 43 | with: | |
| 21 | - python-version: '3.9' | ||
| 44 | + python-version: '3.12' | ||
| 45 | + | ||
| 46 | + - name: Install build tools | ||
| 47 | + run: python -m pip install -U pip build | ||
| 48 | + | ||
| 49 | + - name: Python Semantic Release | ||
| 50 | + id: release | ||
| 51 | + uses: python-semantic-release/python-semantic-release@v9 | ||
| 52 | + with: | ||
| 53 | + github_token: ${{ secrets.GITHUB_TOKEN }} | ||
| 54 | + | ||
| 55 | + - name: Build package | ||
| 56 | + if: steps.release.outputs.released == 'true' | ||
| 57 | + run: python -m build | ||
| 22 | 58 | ||
| 23 | - - name: Build sdist and wheel | ||
| 59 | + - name: Create GitHub Release | ||
| 60 | + if: steps.release.outputs.released == 'true' | ||
| 61 | + env: | ||
| 62 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| 24 | 63 | run: | | |
| 25 | - python -m pip install -U pip build | ||
| 26 | - python -m build | ||
| 64 | + if [ "$DRAFT_RELEASE" = "true" ]; then | ||
| 65 | + DRAFT_FLAG="--draft" | ||
| 66 | + fi | ||
| 67 | + gh release create "${{ steps.release.outputs.tag }}" \ | ||
| 68 | + ${DRAFT_FLAG:-} \ | ||
| 69 | + --title "${{ steps.release.outputs.tag }}" \ | ||
| 70 | + --generate-notes \ | ||
| 71 | + dist/* | ||
| 27 | 72 | ||
| 28 | - - name: Publish package to PyPI | ||
| 73 | + - name: Publish to PyPI | ||
| 74 | + if: steps.release.outputs.released == 'true' && env.DRAFT_RELEASE != 'true' | ||
| 29 | 75 | uses: pypa/gh-action-pypi-publish@release/v1 | |
| 30 | 76 | with: | |
| 31 | 77 | skip-existing: true | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -205,19 +205,26 @@ Co-authored-by: Name <email> | |||
| 205 | 205 | ||
| 206 | 206 | ## Pull request checklist | |
| 207 | 207 | ||
| 208 | + - PR title: Conventional Commits format (CI-enforced by `pr-lint.yml`). | ||
| 208 | 209 | - Tests: added/updated; `pytest` passes. | |
| 209 | 210 | - Lint/format: `ruff check .`, `black` pass. | |
| 210 | - - Docs: update `README.md` and any Django docs pages if behavior changes. | ||
| 211 | + - Docs: update `README.md` if behavior changes. | ||
| 211 | 212 | - Templates: update `templates/` if generator output changes. | |
| 212 | 213 | - No generated artifacts committed. | |
| 213 | 214 | ||
| 214 | 215 | ## Versioning and releases | |
| 215 | 216 | ||
| 216 | - - The library version is tracked in `pyproject.toml` (`project.version`). Use SemVer. | ||
| 217 | - - Workflow: | ||
| 218 | - - Contributors: branch off `main` (or `dev` if used) and open PRs. | ||
| 219 | - - Maintainer (release): bump version, tag, and publish to PyPI. | ||
| 220 | - - Tag on `main`: `git tag -a vX.Y.Z -m "Release vX.Y.Z" && git push --tags`. | ||
| 217 | + - The version is tracked in `pyproject.toml` (`project.version`) and mirrored in `src/pythonnative/__init__.py` as `__version__`. Both files are updated automatically by [python-semantic-release](https://python-semantic-release.readthedocs.io/). | ||
| 218 | + - **Automated release pipeline** (on every merge to `main`): | ||
| 219 | + 1. `python-semantic-release` scans Conventional Commit messages since the last tag. | ||
| 220 | + 2. It determines the next SemVer bump: `feat` → **minor**, `fix`/`perf` → **patch**, `BREAKING CHANGE` → **major** (minor while version < 1.0). | ||
| 221 | + 3. Version files are updated, `CHANGELOG.md` is generated, and a tagged release commit (`chore(release): vX.Y.Z`) is pushed. | ||
| 222 | + 4. A GitHub Release is created with auto-generated release notes and the built sdist/wheel attached. | ||
| 223 | + 5. When drafts are disabled, the package is also published to PyPI via Trusted Publishing. | ||
| 224 | + - **Draft / published toggle**: the `DRAFT_RELEASE` variable at the top of `.github/workflows/release.yml` controls release mode. Set to `"true"` (the default) for draft GitHub Releases with PyPI publishing skipped; flip to `"false"` to publish releases and upload to PyPI immediately. | ||
| 225 | + - Commit types that trigger a release: `feat` (minor), `fix` and `perf` (patch), `BREAKING CHANGE` (major). All other types (`build`, `chore`, `ci`, `docs`, `refactor`, `revert`, `style`, `test`) are recorded in the changelog but do **not** trigger a release on their own. | ||
| 226 | + - Tag format: `v`-prefixed (e.g., `v0.4.0`). | ||
| 227 | + - Manual version bumps are no longer needed — just merge PRs with valid Conventional Commit titles. For ad-hoc runs, use the workflow's **Run workflow** button (`workflow_dispatch`). | ||
| 221 | 228 | ||
| 222 | 229 | ### Branch naming (suggested) | |
| 223 | 230 | ||
@@ -249,6 +256,13 @@ release/v0.2.0 | |||
| 249 | 256 | hotfix/cli-regression | |
| 250 | 257 | ``` | |
| 251 | 258 | ||
| 259 | + ### CI | ||
| 260 | + | ||
| 261 | + - **CI** (`ci.yml`): runs formatter, linter, type checker, and tests on every push and PR. | ||
| 262 | + - **PR Lint** (`pr-lint.yml`): validates the PR title against Conventional Commits format (protects squash merges) and checks individual commit messages via commitlint (protects rebase merges). Recommended: add the **PR title** job as a required status check in branch-protection settings. | ||
| 263 | + - **Release** (`release.yml`): runs on merge to `main`; computes version, generates changelog, tags, creates GitHub Release, and (when `DRAFT_RELEASE` is `"false"`) publishes to PyPI. | ||
| 264 | + - **Docs** (`docs.yml`): deploys documentation to GitHub Pages on push to `main`. | ||
| 265 | + | ||
| 252 | 266 | ## Security and provenance | |
| 253 | 267 | ||
| 254 | 268 | - Avoid bundling secrets or credentials in templates or code. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -88,3 +88,30 @@ ignore = [] | |||
| 88 | 88 | [tool.black] | |
| 89 | 89 | line-length = 120 | |
| 90 | 90 | target-version = ['py39'] | |
| 91 | + | ||
| 92 | + # ── Semantic Release ──────────────────────────────────────────────── | ||
| 93 | + | ||
| 94 | + [tool.semantic_release] | ||
| 95 | + version_toml = ["pyproject.toml:project.version"] | ||
| 96 | + version_variables = ["src/pythonnative/__init__.py:__version__"] | ||
| 97 | + commit_message = "chore(release): v{version}" | ||
| 98 | + tag_format = "v{version}" | ||
| 99 | + major_on_zero = false | ||
| 100 | + | ||
| 101 | + [tool.semantic_release.branches.main] | ||
| 102 | + match = "main" | ||
| 103 | + prerelease = false | ||
| 104 | + | ||
| 105 | + [tool.semantic_release.changelog] | ||
| 106 | + changelog_file = "CHANGELOG.md" | ||
| 107 | + exclude_commit_patterns = [ | ||
| 108 | + "^chore\\(release\\):", | ||
| 109 | + ] | ||
| 110 | + | ||
| 111 | + [tool.semantic_release.commit_parser_options] | ||
| 112 | + allowed_tags = [ | ||
| 113 | + "build", "chore", "ci", "docs", "feat", "fix", | ||
| 114 | + "perf", "refactor", "revert", "style", "test", | ||
| 115 | + ] | ||
| 116 | + minor_tags = ["feat"] | ||
| 117 | + patch_tags = ["fix", "perf"] | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments