mcp-github-crunchtools 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. mcp_github_crunchtools-1.0.1/.gatehouse-ignore +3 -0
  2. mcp_github_crunchtools-1.0.1/.github/ISSUE_TEMPLATE/bug_report.yml +79 -0
  3. mcp_github_crunchtools-1.0.1/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. mcp_github_crunchtools-1.0.1/.github/ISSUE_TEMPLATE/feature_request.yml +73 -0
  5. mcp_github_crunchtools-1.0.1/.github/dependabot.yml +30 -0
  6. mcp_github_crunchtools-1.0.1/.github/workflows/ci.yml +57 -0
  7. mcp_github_crunchtools-1.0.1/.github/workflows/constitution.yml +21 -0
  8. mcp_github_crunchtools-1.0.1/.github/workflows/container.yml +112 -0
  9. mcp_github_crunchtools-1.0.1/.github/workflows/dependabot-automerge.yml +18 -0
  10. mcp_github_crunchtools-1.0.1/.github/workflows/gatehouse-retriage.yml +23 -0
  11. mcp_github_crunchtools-1.0.1/.github/workflows/gatehouse.yml +110 -0
  12. mcp_github_crunchtools-1.0.1/.github/workflows/publish.yml +29 -0
  13. mcp_github_crunchtools-1.0.1/.github/workflows/security.yml +140 -0
  14. mcp_github_crunchtools-1.0.1/.gitignore +95 -0
  15. mcp_github_crunchtools-1.0.1/.pre-commit-config.yaml +41 -0
  16. mcp_github_crunchtools-1.0.1/.specify/memory/constitution.md +64 -0
  17. mcp_github_crunchtools-1.0.1/.specify/specs/000-baseline/spec.md +144 -0
  18. mcp_github_crunchtools-1.0.1/.specify/templates/plan-template.md +117 -0
  19. mcp_github_crunchtools-1.0.1/.specify/templates/spec-template.md +91 -0
  20. mcp_github_crunchtools-1.0.1/CHANGELOG.md +28 -0
  21. mcp_github_crunchtools-1.0.1/CLAUDE.md +86 -0
  22. mcp_github_crunchtools-1.0.1/Containerfile +52 -0
  23. mcp_github_crunchtools-1.0.1/LICENSE +661 -0
  24. mcp_github_crunchtools-1.0.1/PKG-INFO +263 -0
  25. mcp_github_crunchtools-1.0.1/README.md +237 -0
  26. mcp_github_crunchtools-1.0.1/SECURITY.md +219 -0
  27. mcp_github_crunchtools-1.0.1/gourmand-exceptions.toml +37 -0
  28. mcp_github_crunchtools-1.0.1/gourmand.toml +14 -0
  29. mcp_github_crunchtools-1.0.1/pyproject.toml +78 -0
  30. mcp_github_crunchtools-1.0.1/server.json +21 -0
  31. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/__init__.py +58 -0
  32. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/__main__.py +6 -0
  33. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/client.py +271 -0
  34. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/config.py +140 -0
  35. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/errors.py +65 -0
  36. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/models.py +215 -0
  37. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/server.py +496 -0
  38. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/__init__.py +48 -0
  39. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/actions.py +187 -0
  40. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/files.py +124 -0
  41. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/issues.py +224 -0
  42. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/pull_requests.py +287 -0
  43. mcp_github_crunchtools-1.0.1/src/mcp_github_crunchtools/tools/search.py +81 -0
  44. mcp_github_crunchtools-1.0.1/tests/__init__.py +1 -0
  45. mcp_github_crunchtools-1.0.1/tests/conftest.py +80 -0
  46. mcp_github_crunchtools-1.0.1/tests/test_tools.py +861 -0
  47. mcp_github_crunchtools-1.0.1/tests/test_validation.py +175 -0
  48. mcp_github_crunchtools-1.0.1/uv.lock +2170 -0
@@ -0,0 +1,3 @@
1
+ # Paths Gatehouse never reviews (gitignore syntax). Read from the base branch in CI.
2
+ uv.lock
3
+ .specify/templates/
@@ -0,0 +1,79 @@
1
+ name: Bug Report
2
+ description: Report a bug or unexpected behavior
3
+ title: "[Bug]: "
4
+ labels: ["bug", "triage"]
5
+ body:
6
+ - type: textarea
7
+ id: description
8
+ attributes:
9
+ label: Bug Description
10
+ description: A clear description of the bug
11
+ placeholder: What happened?
12
+ validations:
13
+ required: true
14
+
15
+ - type: textarea
16
+ id: steps
17
+ attributes:
18
+ label: Steps to Reproduce
19
+ description: How can we reproduce this bug?
20
+ placeholder: |
21
+ 1. Call tool '...' with args '...'
22
+ 2. Observe error '...'
23
+ validations:
24
+ required: true
25
+
26
+ - type: textarea
27
+ id: expected
28
+ attributes:
29
+ label: Expected Behavior
30
+ description: What did you expect to happen?
31
+ validations:
32
+ required: true
33
+
34
+ - type: textarea
35
+ id: actual
36
+ attributes:
37
+ label: Actual Behavior
38
+ description: What actually happened? Include error messages if available.
39
+ validations:
40
+ required: true
41
+
42
+ - type: dropdown
43
+ id: transport
44
+ attributes:
45
+ label: Transport
46
+ description: How are you running the MCP server?
47
+ options:
48
+ - stdio (uvx / pip)
49
+ - streamable-http (container / systemd)
50
+ - SSE
51
+ validations:
52
+ required: true
53
+
54
+ - type: dropdown
55
+ id: github_instance
56
+ attributes:
57
+ label: GitHub Instance Type
58
+ options:
59
+ - github.com
60
+ - Self-hosted (corporate/private)
61
+ - GitHub Community Edition
62
+ - GitHub Enterprise Edition
63
+ validations:
64
+ required: true
65
+
66
+ - type: input
67
+ id: version
68
+ attributes:
69
+ label: Server Version
70
+ description: Output of `mcp-github-crunchtools --version` or pip show
71
+ placeholder: "0.3.2"
72
+ validations:
73
+ required: true
74
+
75
+ - type: textarea
76
+ id: additional
77
+ attributes:
78
+ label: Additional Context
79
+ description: Any other relevant information (logs, config, environment)
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: GitHub API Documentation
4
+ url: https://docs.github.com/api/rest/
5
+ about: Check the GitHub REST API docs for endpoint behavior questions
@@ -0,0 +1,73 @@
1
+ name: Feature Request
2
+ description: Suggest a new tool or enhancement
3
+ title: "[Feature]: "
4
+ labels: ["enhancement", "triage"]
5
+ body:
6
+ - type: textarea
7
+ id: problem
8
+ attributes:
9
+ label: Problem Statement
10
+ description: What problem does this feature solve?
11
+ placeholder: I need to...
12
+ validations:
13
+ required: true
14
+
15
+ - type: textarea
16
+ id: solution
17
+ attributes:
18
+ label: Proposed Solution
19
+ description: Describe the tool or change you'd like
20
+ placeholder: |
21
+ Tool name: `do_something`
22
+ GitHub API endpoint: `POST /projects/:id/...`
23
+ Parameters: ...
24
+ validations:
25
+ required: true
26
+
27
+ - type: textarea
28
+ id: alternatives
29
+ attributes:
30
+ label: Alternatives Considered
31
+ description: What alternatives have you considered?
32
+
33
+ - type: dropdown
34
+ id: scope
35
+ attributes:
36
+ label: Tool Category
37
+ description: Which area does this feature belong to?
38
+ options:
39
+ - Projects / Groups
40
+ - Merge Requests
41
+ - Issues
42
+ - Pipelines / Jobs
43
+ - Files / Repository
44
+ - Branches
45
+ - Labels
46
+ - Users
47
+ - Releases
48
+ - Milestones
49
+ - Wiki
50
+ - Snippets
51
+ - Search
52
+ - Security / Config
53
+ - New Category
54
+ validations:
55
+ required: true
56
+
57
+ - type: dropdown
58
+ id: github_api
59
+ attributes:
60
+ label: GitHub API Reference
61
+ description: Does this correspond to an existing GitHub REST API endpoint?
62
+ options:
63
+ - "Yes - documented in GitHub API docs"
64
+ - "No - new behavior / aggregation"
65
+ - "Not sure"
66
+ validations:
67
+ required: true
68
+
69
+ - type: textarea
70
+ id: additional
71
+ attributes:
72
+ label: Additional Context
73
+ description: Any other relevant information, API docs links, or examples
@@ -0,0 +1,30 @@
1
+ # Canonical Dependabot config for crunchtools Python projects using uv.
2
+ # Drop in as .github/dependabot.yml. See constitution.md Section XV.
3
+ #
4
+ # Covers both ecosystems that go stale silently if left unpinned:
5
+ # - uv: uv.lock (must be committed, never gitignored)
6
+ # - github-actions: `uses: some-action@vX.Y.Z` pins in .github/workflows/
7
+
8
+ version: 2
9
+ updates:
10
+ - package-ecosystem: "uv"
11
+ directory: "/"
12
+ schedule:
13
+ interval: "weekly"
14
+ groups:
15
+ minor-and-patch:
16
+ update-types:
17
+ - "minor"
18
+ - "patch"
19
+
20
+ - package-ecosystem: "github-actions"
21
+ directory: "/"
22
+ schedule:
23
+ interval: "weekly"
24
+ groups:
25
+ minor-and-patch:
26
+ update-types:
27
+ - "minor"
28
+ - "patch"
29
+ ignore:
30
+ - dependency-name: "crunchtools/constitution*"
@@ -0,0 +1,57 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v7
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v7
21
+ with:
22
+ version: "latest"
23
+
24
+ - name: Set up Python ${{ matrix.python-version }}
25
+ run: uv python install ${{ matrix.python-version }}
26
+
27
+ - name: Install dependencies
28
+ run: uv sync --all-extras
29
+
30
+ - name: Run linter
31
+ run: uv run ruff check src tests
32
+
33
+ - name: Run type checker
34
+ run: uv run mypy src
35
+
36
+ - name: Run tests
37
+ run: uv run pytest -v
38
+ env:
39
+ GITHUB_TOKEN: "test_token_for_ci"
40
+
41
+ gourmand:
42
+ name: Code Quality (Gourmand)
43
+ uses: crunchtools/gatehouse/.github/workflows/gourmand.yml@v0.15.2
44
+
45
+ build-container:
46
+ runs-on: ubuntu-latest
47
+ steps:
48
+ - uses: actions/checkout@v7
49
+
50
+ - name: Build container image
51
+ run: |
52
+ docker build -f Containerfile -t mcp-github:test .
53
+
54
+ - name: Verify container
55
+ run: |
56
+ # Just verify it starts (will fail due to no token, but should start)
57
+ timeout 5 docker run --rm mcp-github:test || true
@@ -0,0 +1,21 @@
1
+ # Drop in as .github/workflows/constitution.yml. See constitution.md VII.
2
+ #
3
+ # The tag below is the constitution version this repo is judged by. It moves
4
+ # together with `Inherits:` in .specify/memory/constitution.md (scripts/fleet-bump.py
5
+ # opens that PR); Dependabot is told to ignore it, see examples/dependabot.yml.
6
+ # Required check: `Constitution / Validate constitution`.
7
+
8
+ name: Constitution
9
+
10
+ on:
11
+ pull_request:
12
+ push:
13
+ branches: [main, master]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ constitution:
20
+ name: Constitution
21
+ uses: crunchtools/constitution/.github/workflows/validate.yml@v1.18.0
@@ -0,0 +1,112 @@
1
+ name: Container Build & Push
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ pull_request:
8
+ branches: [main]
9
+ workflow_dispatch:
10
+
11
+ env:
12
+ QUAY_IMAGE: quay.io/crunchtools/mcp-github
13
+ GHCR_IMAGE: ghcr.io/crunchtools/mcp-github
14
+
15
+ jobs:
16
+ build-and-push-quay:
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ contents: read
20
+
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@v7
24
+
25
+ - name: Set up Docker Buildx
26
+ uses: docker/setup-buildx-action@v4
27
+
28
+ - name: Log in to Quay.io
29
+ if: github.event_name != 'pull_request'
30
+ uses: docker/login-action@v4
31
+ with:
32
+ registry: quay.io
33
+ username: ${{ secrets.QUAY_USERNAME }}
34
+ password: ${{ secrets.QUAY_PASSWORD }}
35
+
36
+ - name: Extract metadata
37
+ id: meta
38
+ uses: docker/metadata-action@v6
39
+ with:
40
+ images: ${{ env.QUAY_IMAGE }}
41
+ tags: |
42
+ type=ref,event=branch
43
+ type=ref,event=pr
44
+ type=semver,pattern={{version}}
45
+ type=semver,pattern={{major}}.{{minor}}
46
+ type=raw,value=latest,enable={{is_default_branch}}
47
+
48
+ - name: Build and push
49
+ uses: docker/build-push-action@v7
50
+ with:
51
+ context: .
52
+ file: ./Containerfile
53
+ push: ${{ github.event_name != 'pull_request' }}
54
+ tags: ${{ steps.meta.outputs.tags }}
55
+ labels: ${{ steps.meta.outputs.labels }}
56
+ cache-from: type=gha
57
+ cache-to: type=gha,mode=max
58
+
59
+ - name: Run Trivy vulnerability scanner
60
+ continue-on-error: true
61
+ if: github.event_name != 'pull_request'
62
+ uses: aquasecurity/trivy-action@v0.36.0
63
+ with:
64
+ image-ref: ${{ env.QUAY_IMAGE }}:latest
65
+ format: "table"
66
+ exit-code: "0"
67
+ severity: "CRITICAL,HIGH"
68
+ version: "v0.68.2"
69
+
70
+ build-and-push-ghcr:
71
+ runs-on: ubuntu-latest
72
+ needs: build-and-push-quay
73
+ if: github.event_name != 'pull_request'
74
+ permissions:
75
+ contents: read
76
+ packages: write
77
+
78
+ steps:
79
+ - name: Checkout repository
80
+ uses: actions/checkout@v7
81
+
82
+ - name: Set up Docker Buildx
83
+ uses: docker/setup-buildx-action@v4
84
+
85
+ - name: Log in to GitHub Container Registry
86
+ uses: docker/login-action@v4
87
+ with:
88
+ registry: ghcr.io
89
+ username: ${{ github.repository_owner }}
90
+ password: ${{ github.token }}
91
+
92
+ - name: Extract metadata
93
+ id: meta
94
+ uses: docker/metadata-action@v6
95
+ with:
96
+ images: ${{ env.GHCR_IMAGE }}
97
+ tags: |
98
+ type=ref,event=branch
99
+ type=ref,event=pr
100
+ type=semver,pattern={{version}}
101
+ type=semver,pattern={{major}}.{{minor}}
102
+ type=raw,value=latest,enable={{is_default_branch}}
103
+
104
+ - name: Build and push
105
+ uses: docker/build-push-action@v7
106
+ with:
107
+ context: .
108
+ file: ./Containerfile
109
+ push: true
110
+ tags: ${{ steps.meta.outputs.tags }}
111
+ labels: ${{ steps.meta.outputs.labels }}
112
+ cache-from: type=gha
@@ -0,0 +1,18 @@
1
+ # Drop in as .github/workflows/dependabot-automerge.yml. See constitution.md XV.
2
+ #
3
+ # Queues green GitHub Actions minor/patch bumps for auto-merge. Needs the repo
4
+ # setting `allow_auto_merge`; the required checks still decide the merge.
5
+
6
+ name: Dependabot auto-merge
7
+
8
+ on:
9
+ pull_request:
10
+
11
+ permissions:
12
+ contents: write
13
+ pull-requests: write
14
+
15
+ jobs:
16
+ automerge:
17
+ name: Dependabot
18
+ uses: crunchtools/constitution/.github/workflows/dependabot-automerge.yml@v1.18.0
@@ -0,0 +1,23 @@
1
+ # Gatehouse retriage — makes a reply to a finding clear the triage check.
2
+ #
3
+ # Drop this next to examples/gatehouse.yml. A reply re-runs the `Gatehouse`
4
+ # workflow, but that run's checks do not count toward branch rules; only the
5
+ # pull_request_target run's do. When the reply run finishes, this re-runs
6
+ # triage inside the pull_request_target run. `workflow_run` always executes
7
+ # the default-branch copy of this file, so a fork cannot alter it.
8
+
9
+ name: Gatehouse retriage
10
+
11
+ on:
12
+ workflow_run:
13
+ workflows: [Gatehouse] # the `name:` of your gatehouse.yml
14
+ types: [completed]
15
+
16
+ permissions: {} # default-deny
17
+
18
+ jobs:
19
+ retriage:
20
+ if: github.event.workflow_run.event == 'pull_request_review_comment'
21
+ permissions:
22
+ actions: write # re-run the triage job; nothing else
23
+ uses: crunchtools/gatehouse/.github/workflows/retriage.yml@v0.15.2
@@ -0,0 +1,110 @@
1
+ # Gatehouse — fork-safe code review + workflow protection, in ONE file.
2
+ #
3
+ # Drop this in your repo at .github/workflows/gatehouse.yml, add a OPENROUTER_API_KEY
4
+ # secret, and you get:
5
+ # • AI review of every PR (including from forks) — posted as a PR review
6
+ # • rejection of untrusted PRs that try to modify your workflow files
7
+ #
8
+ # Nothing is ever checked out from the PR. The fork's change is only ever read as
9
+ # a diff (data); the reviewer logic lives in the pinned gatehouse container; the
10
+ # rules (your styleguide/constitution) are fetched from YOUR base branch, not the
11
+ # PR. The one thing you don't trust — the proposed change — is only ever read.
12
+ #
13
+ # Three jobs with DIFFERENT authority:
14
+ # • guard — a real blocking gate. Mark it a REQUIRED status check so a PR
15
+ # that tampers with your workflow files is rejected.
16
+ # • review — ADVISORY. It posts findings as PR comments and always passes;
17
+ # do NOT mark it required. An LLM reviewer is non-deterministic,
18
+ # so it must never hold merge authority. (Opt into blocking with
19
+ # `blocking: true` below only if you accept that tradeoff — and
20
+ # even then, keep it out of branch protection.)
21
+ # • triage — deterministic. Fails while any finding has no reply
22
+ # (`fixed in <sha>` or `not a bug: <reason>`). Safe to mark
23
+ # REQUIRED: it never judges code, only whether a human answered.
24
+
25
+ name: Gatehouse
26
+
27
+ on:
28
+ pull_request_target:
29
+ types: [opened, synchronize, reopened]
30
+ # A reply rings the doorbell: this run's own checks do not count toward
31
+ # branch rules, so examples/gatehouse-retriage.yml answers it by re-running
32
+ # triage inside the pull_request_target run. Add that file too.
33
+ pull_request_review_comment:
34
+ types: [created, edited, deleted]
35
+
36
+ permissions: {} # default-deny; each job grants only what it needs
37
+
38
+ jobs:
39
+ # ── 1) Protect the workflow files themselves ────────────────────────────────
40
+ # Rejects PRs from forks that touch .github/workflows/. Safe under
41
+ # pull_request_target because it only reads the changed-file LIST via the
42
+ # API — it never checks out or runs your code. And because pull_request_target
43
+ # runs the BASE version of this file, a PR can't edit this job to disable it.
44
+ guard:
45
+ name: Protect workflows
46
+ # Runs on replies too. A job skipped on the reply event reports
47
+ # "skipped", which a required check counts as passing: skipping the
48
+ # guard there would let any comment on a rejected fork PR clear it.
49
+ runs-on: ubuntu-latest
50
+ permissions:
51
+ contents: read
52
+ pull-requests: write
53
+ steps:
54
+ - name: Reject workflow changes from untrusted PRs
55
+ env:
56
+ GH_TOKEN: ${{ github.token }}
57
+ EVENT: ${{ github.event_name }}
58
+ PR: ${{ github.event.pull_request.number }}
59
+ HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
60
+ run: |
61
+ set -euo pipefail
62
+ # Gate on where the branch lives, not on the author's role: a branch
63
+ # pushed into this repo already required write access, and a fork is
64
+ # what pull_request_target actually guards against.
65
+ if [ "$HEAD_REPO" = "$GITHUB_REPOSITORY" ]; then
66
+ echo "Head branch is in $GITHUB_REPOSITORY; allowing."; exit 0
67
+ fi
68
+ # Both sides of a rename: `gh pr diff --name-only` lists only the new
69
+ # path, so a fork could move a workflow out of .github/workflows/ unseen.
70
+ changed="$(gh api --paginate "repos/$GITHUB_REPOSITORY/pulls/$PR/files" \
71
+ --jq '.[] | .filename, (.previous_filename // empty)')"
72
+ if echo "$changed" | grep -qE '^\.github/workflows/'; then
73
+ echo "::error::PR modifies .github/workflows/ — not accepted from external contributors."
74
+ # Explain once, on the PR event; replies re-run the check, not the comment.
75
+ if [ "$EVENT" = "pull_request_target" ]; then
76
+ gh pr comment "$PR" --repo "$GITHUB_REPOSITORY" --body \
77
+ $'🚫 **Workflow changes are not accepted via pull request.** Please open an issue and a maintainer will make the change.'
78
+ fi
79
+ exit 1
80
+ fi
81
+ echo "No workflow files changed."
82
+
83
+ # ── 2) Review the PR diff (no checkout, BYO key) ────────────────────────────
84
+ # The reviewer is maintained centrally in gatehouse's reusable workflow and the
85
+ # pinned container — so security fixes reach you without copying logic around.
86
+ # Scope OPENROUTER_API_KEY to this reusable workflow so only it can read the key.
87
+ review:
88
+ name: Gatehouse review
89
+ if: github.event_name == 'pull_request_target'
90
+ permissions:
91
+ contents: read
92
+ pull-requests: write
93
+ uses: crunchtools/gatehouse/.github/workflows/review.yml@v0.15.2
94
+ # Advisory by default — findings post as comments, the check always passes.
95
+ # Uncomment to let critical/high findings fail the check (still not required):
96
+ # with:
97
+ # blocking: true
98
+ secrets:
99
+ OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
100
+
101
+ # ── 3) Every finding answered ──────────────────────────────────────────────
102
+ # Runs after the review on a push, and alone on a reply (review is skipped
103
+ # then, hence always()). Read-only, no secrets.
104
+ triage:
105
+ name: Gatehouse triage
106
+ needs: review
107
+ if: always()
108
+ permissions:
109
+ pull-requests: read
110
+ uses: crunchtools/gatehouse/.github/workflows/triage.yml@v0.15.2
@@ -0,0 +1,29 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ id-token: write # Required for trusted publishing
13
+
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v7
19
+ with:
20
+ version: "latest"
21
+
22
+ - name: Set up Python
23
+ run: uv python install 3.12
24
+
25
+ - name: Build package
26
+ run: uv build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1