google-cloud-support-mcp 0.1.0__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.
- google_cloud_support_mcp-0.1.0/.github/dependabot.yml +17 -0
- google_cloud_support_mcp-0.1.0/.github/workflows/ci.yml +56 -0
- google_cloud_support_mcp-0.1.0/.github/workflows/release.yml +292 -0
- google_cloud_support_mcp-0.1.0/.gitignore +35 -0
- google_cloud_support_mcp-0.1.0/.python-version +1 -0
- google_cloud_support_mcp-0.1.0/.specify/.gitignore +9 -0
- google_cloud_support_mcp-0.1.0/.specify/init-options.json +9 -0
- google_cloud_support_mcp-0.1.0/.specify/integration.json +15 -0
- google_cloud_support_mcp-0.1.0/.specify/integrations/claude.manifest.json +17 -0
- google_cloud_support_mcp-0.1.0/.specify/integrations/speckit.manifest.json +19 -0
- google_cloud_support_mcp-0.1.0/.specify/memory/.constitution-template.json +4 -0
- google_cloud_support_mcp-0.1.0/.specify/memory/constitution.md +192 -0
- google_cloud_support_mcp-0.1.0/.specify/scripts/bash/check-prerequisites.sh +230 -0
- google_cloud_support_mcp-0.1.0/.specify/scripts/bash/common.sh +918 -0
- google_cloud_support_mcp-0.1.0/.specify/scripts/bash/create-new-feature.sh +407 -0
- google_cloud_support_mcp-0.1.0/.specify/scripts/bash/resolve-template.sh +57 -0
- google_cloud_support_mcp-0.1.0/.specify/scripts/bash/setup-plan.sh +85 -0
- google_cloud_support_mcp-0.1.0/.specify/scripts/bash/setup-tasks.sh +94 -0
- google_cloud_support_mcp-0.1.0/.specify/templates/checklist-template.md +45 -0
- google_cloud_support_mcp-0.1.0/.specify/templates/constitution-template.md +50 -0
- google_cloud_support_mcp-0.1.0/.specify/templates/plan-template.md +113 -0
- google_cloud_support_mcp-0.1.0/.specify/templates/spec-template.md +131 -0
- google_cloud_support_mcp-0.1.0/.specify/templates/tasks-template.md +252 -0
- google_cloud_support_mcp-0.1.0/.specify/workflows/speckit/workflow.yml +78 -0
- google_cloud_support_mcp-0.1.0/.specify/workflows/workflow-registry.json +13 -0
- google_cloud_support_mcp-0.1.0/PKG-INFO +265 -0
- google_cloud_support_mcp-0.1.0/README.md +253 -0
- google_cloud_support_mcp-0.1.0/REFERENCE.md +2 -0
- google_cloud_support_mcp-0.1.0/fastmcp.json +11 -0
- google_cloud_support_mcp-0.1.0/pyproject.toml +74 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/checklists/requirements.md +49 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/contracts/tools.md +302 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/data-model.md +240 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/deferred.md +197 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/plan.md +195 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/quickstart.md +257 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/research.md +305 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/spec.md +163 -0
- google_cloud_support_mcp-0.1.0/specs/001-gcp-support-mcp/tasks.md +354 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/__init__.py +11 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/__main__.py +4 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/auth.py +61 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/clients.py +48 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/confirm.py +158 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/errors.py +233 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/fanout.py +145 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/media.py +81 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/models.py +185 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/prompts.py +37 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/redaction.py +97 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/resources.py +54 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/serializers.py +148 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/server.py +172 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/settings.py +63 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/tools/__init__.py +23 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/tools/attachments.py +170 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/tools/cases.py +440 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/tools/classifications.py +122 -0
- google_cloud_support_mcp-0.1.0/src/google_cloud_support_mcp/tools/comments.py +124 -0
- google_cloud_support_mcp-0.1.0/tests/__init__.py +0 -0
- google_cloud_support_mcp-0.1.0/tests/conftest.py +205 -0
- google_cloud_support_mcp-0.1.0/tests/contract/__init__.py +0 -0
- google_cloud_support_mcp-0.1.0/tests/contract/test_confirm_writes.py +155 -0
- google_cloud_support_mcp-0.1.0/tests/contract/test_console_url.py +39 -0
- google_cloud_support_mcp-0.1.0/tests/contract/test_gating.py +43 -0
- google_cloud_support_mcp-0.1.0/tests/contract/test_lifecycle_and_media.py +179 -0
- google_cloud_support_mcp-0.1.0/tests/contract/test_protocol_eras.py +32 -0
- google_cloud_support_mcp-0.1.0/tests/contract/test_read_tools.py +142 -0
- google_cloud_support_mcp-0.1.0/tests/contract/test_tool_inventory.py +125 -0
- google_cloud_support_mcp-0.1.0/tests/integration/__init__.py +0 -0
- google_cloud_support_mcp-0.1.0/tests/integration/conftest.py +47 -0
- google_cloud_support_mcp-0.1.0/tests/integration/test_create_journey.py +64 -0
- google_cloud_support_mcp-0.1.0/tests/integration/test_lifecycle_journey.py +80 -0
- google_cloud_support_mcp-0.1.0/tests/integration/test_read_journey.py +40 -0
- google_cloud_support_mcp-0.1.0/tests/unit/__init__.py +0 -0
- google_cloud_support_mcp-0.1.0/tests/unit/test_classification_query.py +33 -0
- google_cloud_support_mcp-0.1.0/tests/unit/test_errors.py +140 -0
- google_cloud_support_mcp-0.1.0/tests/unit/test_fanout.py +110 -0
- google_cloud_support_mcp-0.1.0/tests/unit/test_integration_guard.py +33 -0
- google_cloud_support_mcp-0.1.0/tests/unit/test_redaction.py +65 -0
- google_cloud_support_mcp-0.1.0/tests/unit/test_serializers.py +140 -0
- google_cloud_support_mcp-0.1.0/uv.lock +1603 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Action tags move faster than anything else here, and a stale action inside a
|
|
4
|
+
# workflow that holds id-token: write is worth noticing early.
|
|
5
|
+
- package-ecosystem: github-actions
|
|
6
|
+
directory: /
|
|
7
|
+
schedule:
|
|
8
|
+
interval: weekly
|
|
9
|
+
commit-message:
|
|
10
|
+
prefix: ci
|
|
11
|
+
|
|
12
|
+
- package-ecosystem: uv
|
|
13
|
+
directory: /
|
|
14
|
+
schedule:
|
|
15
|
+
interval: weekly
|
|
16
|
+
commit-message:
|
|
17
|
+
prefix: build
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
# A newer push to the same branch makes the older run irrelevant.
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ci-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
check:
|
|
19
|
+
name: Lint and test
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
timeout-minutes: 10
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
|
|
25
|
+
- name: Set up uv
|
|
26
|
+
# Pinned to an exact patch, unlike the other actions here, because
|
|
27
|
+
# astral-sh/setup-uv publishes no floating `v10` major tag — only
|
|
28
|
+
# v10.0.0 and v10.0.1. `@v10` fails to resolve and the job dies
|
|
29
|
+
# before it runs anything.
|
|
30
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.14"
|
|
33
|
+
enable-cache: true
|
|
34
|
+
|
|
35
|
+
- name: Install
|
|
36
|
+
run: uv sync --locked --all-extras --dev
|
|
37
|
+
|
|
38
|
+
- name: Lint
|
|
39
|
+
run: uv run ruff check .
|
|
40
|
+
|
|
41
|
+
- name: Format
|
|
42
|
+
run: uv run ruff format --check .
|
|
43
|
+
|
|
44
|
+
- name: Test
|
|
45
|
+
# Integration tests are deselected by pyproject's addopts; they need
|
|
46
|
+
# live Google Cloud Support credentials and would create real cases.
|
|
47
|
+
run: uv run pytest -q
|
|
48
|
+
|
|
49
|
+
- name: Server loads through the FastMCP CLI
|
|
50
|
+
# Constitution principle VI, and the one check the test suite cannot
|
|
51
|
+
# make: the tests import the package directly, while the CLI loads
|
|
52
|
+
# server.py by path with no parent package. A relative import added to
|
|
53
|
+
# that file passes every test above and breaks `fastmcp inspect`, `run`
|
|
54
|
+
# and `dev` — which is exactly how this went unnoticed until it was
|
|
55
|
+
# found by hand.
|
|
56
|
+
run: uv run fastmcp inspect
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Two ways in.
|
|
4
|
+
#
|
|
5
|
+
# 1. Push a tag you set yourself — the normal path:
|
|
6
|
+
#
|
|
7
|
+
# git tag v0.1.1
|
|
8
|
+
# git push origin v0.1.1
|
|
9
|
+
#
|
|
10
|
+
# That is the whole release. The version is derived from the tag, so there is
|
|
11
|
+
# no version field to bump and nothing to commit first.
|
|
12
|
+
#
|
|
13
|
+
# 2. Re-run an existing tag from the Actions tab, for when a release failed
|
|
14
|
+
# partway and you want to retry without inventing a new version number.
|
|
15
|
+
#
|
|
16
|
+
# Nothing publishes on an ordinary push to main.
|
|
17
|
+
on:
|
|
18
|
+
push:
|
|
19
|
+
tags: ["v*"]
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
inputs:
|
|
22
|
+
tag:
|
|
23
|
+
description: "Existing tag to publish or retry, e.g. v0.1.1"
|
|
24
|
+
required: true
|
|
25
|
+
type: string
|
|
26
|
+
|
|
27
|
+
env:
|
|
28
|
+
# `github.ref_name` is the tag on a tag push and the branch on a manual run,
|
|
29
|
+
# so the input takes precedence and every job reads the same value.
|
|
30
|
+
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
|
|
31
|
+
|
|
32
|
+
# Never let two runs for the same tag upload at once. `cancel-in-progress: false`
|
|
33
|
+
# on purpose: cancelling mid-upload is how you get a half-published release.
|
|
34
|
+
concurrency:
|
|
35
|
+
group: release-${{ inputs.tag || github.ref_name }}
|
|
36
|
+
cancel-in-progress: false
|
|
37
|
+
|
|
38
|
+
permissions:
|
|
39
|
+
contents: read
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
verify:
|
|
43
|
+
name: Verify tag and test
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
timeout-minutes: 10
|
|
46
|
+
outputs:
|
|
47
|
+
released: ${{ steps.check.outputs.released }}
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@v7
|
|
50
|
+
with:
|
|
51
|
+
ref: ${{ env.RELEASE_TAG }}
|
|
52
|
+
# The version is derived from git tags, so a shallow clone would
|
|
53
|
+
# silently build 0.0.0 instead of the release.
|
|
54
|
+
fetch-depth: 0
|
|
55
|
+
|
|
56
|
+
- name: Set up uv
|
|
57
|
+
# Pinned to an exact patch, unlike the other actions here, because
|
|
58
|
+
# astral-sh/setup-uv publishes no floating `v10` major tag — only
|
|
59
|
+
# v10.0.0 and v10.0.1. `@v10` fails to resolve and the job dies
|
|
60
|
+
# before it runs anything.
|
|
61
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
62
|
+
with:
|
|
63
|
+
python-version: "3.14"
|
|
64
|
+
|
|
65
|
+
- name: Tag must be a release tag
|
|
66
|
+
id: check
|
|
67
|
+
# pyproject.toml carries no version to compare against — it is derived
|
|
68
|
+
# from this tag — so the only thing to validate here is the tag itself.
|
|
69
|
+
# That the build actually produced this version is asserted in `build`.
|
|
70
|
+
run: |
|
|
71
|
+
case "$RELEASE_TAG" in
|
|
72
|
+
v[0-9]*) ;;
|
|
73
|
+
*)
|
|
74
|
+
echo "::error::'$RELEASE_TAG' is not a release tag; expected something like v0.1.1."
|
|
75
|
+
exit 1
|
|
76
|
+
;;
|
|
77
|
+
esac
|
|
78
|
+
echo "released=${RELEASE_TAG#v}" >> "$GITHUB_OUTPUT"
|
|
79
|
+
echo "Releasing ${RELEASE_TAG#v} from ${RELEASE_TAG}"
|
|
80
|
+
|
|
81
|
+
- name: Install
|
|
82
|
+
run: uv sync --locked --all-extras --dev
|
|
83
|
+
|
|
84
|
+
- name: Lint
|
|
85
|
+
run: uv run ruff check . && uv run ruff format --check .
|
|
86
|
+
|
|
87
|
+
- name: Test
|
|
88
|
+
run: uv run pytest -q
|
|
89
|
+
|
|
90
|
+
build:
|
|
91
|
+
name: Build distributions
|
|
92
|
+
needs: verify
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
timeout-minutes: 10
|
|
95
|
+
steps:
|
|
96
|
+
- uses: actions/checkout@v7
|
|
97
|
+
with:
|
|
98
|
+
ref: ${{ env.RELEASE_TAG }}
|
|
99
|
+
# Same reason as above: hatchling reads the tag to compute the version.
|
|
100
|
+
fetch-depth: 0
|
|
101
|
+
|
|
102
|
+
- name: Set up uv
|
|
103
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
104
|
+
with:
|
|
105
|
+
python-version: "3.14"
|
|
106
|
+
|
|
107
|
+
- name: Build sdist and wheel
|
|
108
|
+
run: uv build
|
|
109
|
+
|
|
110
|
+
- name: Built version must be the tag
|
|
111
|
+
# Replaces the old tag-vs-pyproject comparison. With the version derived
|
|
112
|
+
# from git, the failure mode is no longer a stale string in a file — it
|
|
113
|
+
# is a checkout that could not see the tag, which yields something like
|
|
114
|
+
# 0.0.0.post7.dev0+ed6fdff. PyPI rejects local version segments, so
|
|
115
|
+
# catching it here turns a confusing upload error into a clear one.
|
|
116
|
+
run: |
|
|
117
|
+
want="${RELEASE_TAG#v}"
|
|
118
|
+
got="$(ls dist/*.whl | head -1 | sed -E 's|.*/[^-]+-([^-]+)-.*|\1|')"
|
|
119
|
+
if [ "$got" != "$want" ]; then
|
|
120
|
+
echo "::error::Built ${got} but the tag says ${want}."
|
|
121
|
+
echo "::error::Usually this means the checkout could not see tag ${RELEASE_TAG} — check fetch-depth and that the tag is pushed."
|
|
122
|
+
exit 1
|
|
123
|
+
fi
|
|
124
|
+
echo "Built ${got}, matching ${RELEASE_TAG}"
|
|
125
|
+
|
|
126
|
+
- name: Smoke-test the wheel
|
|
127
|
+
# Catches the packaging failure that matters most here. A wheel that
|
|
128
|
+
# installs but does not expose the `google-cloud-support-mcp` console
|
|
129
|
+
# script breaks `uvx google-cloud-support-mcp` for every user, and
|
|
130
|
+
# nothing in the test suite would notice — the tests import the package
|
|
131
|
+
# directly.
|
|
132
|
+
run: |
|
|
133
|
+
uv venv /tmp/smoke
|
|
134
|
+
VIRTUAL_ENV=/tmp/smoke uv pip install dist/*.whl
|
|
135
|
+
test -x /tmp/smoke/bin/google-cloud-support-mcp \
|
|
136
|
+
|| { echo "::error::console script missing from the wheel"; exit 1; }
|
|
137
|
+
/tmp/smoke/bin/python -c "import google_cloud_support_mcp as m; assert callable(m.main)"
|
|
138
|
+
echo "console script and entry point present"
|
|
139
|
+
|
|
140
|
+
- uses: actions/upload-artifact@v7
|
|
141
|
+
with:
|
|
142
|
+
name: dist
|
|
143
|
+
path: dist/
|
|
144
|
+
if-no-files-found: error
|
|
145
|
+
|
|
146
|
+
pypi:
|
|
147
|
+
name: Publish to PyPI
|
|
148
|
+
needs: build
|
|
149
|
+
runs-on: ubuntu-latest
|
|
150
|
+
timeout-minutes: 10
|
|
151
|
+
# Lets you require a manual approval, or restrict which tags may publish.
|
|
152
|
+
environment:
|
|
153
|
+
name: pypi
|
|
154
|
+
url: https://pypi.org/p/google-cloud-support-mcp
|
|
155
|
+
permissions:
|
|
156
|
+
# Trusted Publishing and Sigstore both need this: GitHub mints a
|
|
157
|
+
# short-lived OIDC token, PyPI verifies it against a publisher you
|
|
158
|
+
# registered, and uv signs the PEP 740 attestations with it. No API
|
|
159
|
+
# token is stored anywhere.
|
|
160
|
+
id-token: write
|
|
161
|
+
steps:
|
|
162
|
+
# v8 pairs with upload-artifact v7: it reads Content-Type and only
|
|
163
|
+
# decompresses what is actually zipped, which is what makes v7's direct
|
|
164
|
+
# uploads work. It also errors on a digest mismatch rather than warning.
|
|
165
|
+
# The majors differ because these are separate repositories, not because
|
|
166
|
+
# one is stale.
|
|
167
|
+
- uses: actions/download-artifact@v8
|
|
168
|
+
with:
|
|
169
|
+
name: dist
|
|
170
|
+
path: dist/
|
|
171
|
+
|
|
172
|
+
- name: Set up uv
|
|
173
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
174
|
+
|
|
175
|
+
- name: Publish
|
|
176
|
+
# --trusted-publishing always: if OIDC is not configured, fail here
|
|
177
|
+
# rather than silently falling back to a token that does not exist.
|
|
178
|
+
# --check-url: makes a retry safe. If a previous run uploaded the sdist
|
|
179
|
+
# and then died before the wheel, uv skips what is already on the
|
|
180
|
+
# index instead of erroring on a duplicate. This is what makes
|
|
181
|
+
# "re-run failed jobs" a real recovery path rather than a second
|
|
182
|
+
# failure. Attestations are uploaded by default.
|
|
183
|
+
run: |
|
|
184
|
+
uv publish \
|
|
185
|
+
--trusted-publishing always \
|
|
186
|
+
--check-url https://pypi.org/simple
|
|
187
|
+
|
|
188
|
+
github-release:
|
|
189
|
+
name: Create GitHub release
|
|
190
|
+
needs: [verify, pypi]
|
|
191
|
+
runs-on: ubuntu-latest
|
|
192
|
+
timeout-minutes: 10
|
|
193
|
+
permissions:
|
|
194
|
+
contents: write
|
|
195
|
+
steps:
|
|
196
|
+
- uses: actions/checkout@v7
|
|
197
|
+
with:
|
|
198
|
+
ref: ${{ env.RELEASE_TAG }}
|
|
199
|
+
# git-cliff reads the commit range between tags, so a shallow clone
|
|
200
|
+
# would produce an empty changelog.
|
|
201
|
+
fetch-depth: 0
|
|
202
|
+
|
|
203
|
+
# v8 pairs with upload-artifact v7: it reads Content-Type and only
|
|
204
|
+
# decompresses what is actually zipped, which is what makes v7's direct
|
|
205
|
+
# uploads work. It also errors on a digest mismatch rather than warning.
|
|
206
|
+
# The majors differ because these are separate repositories, not because
|
|
207
|
+
# one is stale.
|
|
208
|
+
- uses: actions/download-artifact@v8
|
|
209
|
+
with:
|
|
210
|
+
name: dist
|
|
211
|
+
path: dist/
|
|
212
|
+
|
|
213
|
+
- name: Generate changelog
|
|
214
|
+
id: changelog
|
|
215
|
+
uses: orhun/git-cliff-action@v4
|
|
216
|
+
# Deferred, not swallowed. PyPI has already published by this point and
|
|
217
|
+
# git-cliff panics rather than degrading when the GitHub API 404s or
|
|
218
|
+
# rate-limits, so stopping here would leave the package on PyPI with no
|
|
219
|
+
# release pointing at it. Instead the release is still created and the
|
|
220
|
+
# job then fails on purpose in the final step below — the run goes red,
|
|
221
|
+
# and nothing is lost.
|
|
222
|
+
continue-on-error: true
|
|
223
|
+
with:
|
|
224
|
+
# `github` renders the familiar release-note shape and, with the API
|
|
225
|
+
# reachable, adds contributors and pull-request links.
|
|
226
|
+
# Swap to `detailed` for sections grouped by Conventional Commit type
|
|
227
|
+
# (Features / Bug Fixes / Documentation) with per-commit links.
|
|
228
|
+
config: github
|
|
229
|
+
args: --latest --strip header
|
|
230
|
+
env:
|
|
231
|
+
GITHUB_REPO: ${{ github.repository }}
|
|
232
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
233
|
+
|
|
234
|
+
- name: Publish release
|
|
235
|
+
uses: softprops/action-gh-release@v3
|
|
236
|
+
with:
|
|
237
|
+
# Explicit because a manual re-run is not triggered by the tag itself.
|
|
238
|
+
tag_name: ${{ env.RELEASE_TAG }}
|
|
239
|
+
files: dist/*
|
|
240
|
+
# Re-running must refresh the attached files rather than fail on them.
|
|
241
|
+
overwrite_files: true
|
|
242
|
+
# A pre-release tag such as v1.0.0-rc1 should not be marked "latest".
|
|
243
|
+
prerelease: ${{ contains(env.RELEASE_TAG, '-') }}
|
|
244
|
+
# Falls back to GitHub's own generator if the step above degraded,
|
|
245
|
+
# so the release is never published with an empty body. The
|
|
246
|
+
# substitution is reported as a failure by the next step.
|
|
247
|
+
generate_release_notes: ${{ steps.changelog.outcome != 'success' }}
|
|
248
|
+
body: |
|
|
249
|
+
${{ steps.changelog.outputs.content }}
|
|
250
|
+
|
|
251
|
+
## Install
|
|
252
|
+
|
|
253
|
+
Run it without cloning anything:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
uvx google-cloud-support-mcp
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Or pin this exact release:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
uvx google-cloud-support-mcp@${{ needs.verify.outputs.released }}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
MCP client configuration:
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"mcpServers": {
|
|
270
|
+
"google-cloud-support": {
|
|
271
|
+
"command": "uvx",
|
|
272
|
+
"args": ["google-cloud-support-mcp"],
|
|
273
|
+
"env": {
|
|
274
|
+
"GOOGLE_CLOUD_SUPPORT_MCP_PARENTS": "[\"projects/my-project\"]",
|
|
275
|
+
"GOOGLE_CLOUD_SUPPORT_MCP_QUOTA_PROJECT": "my-project"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
- name: Fail if the changelog was not generated
|
|
283
|
+
# The release exists and PyPI is published — neither is rolled back.
|
|
284
|
+
# But a run that silently swapped in generic notes would report success
|
|
285
|
+
# and nobody would know the release notes are wrong, so this makes the
|
|
286
|
+
# degradation loud instead.
|
|
287
|
+
if: steps.changelog.outcome != 'success'
|
|
288
|
+
run: |
|
|
289
|
+
echo "::error title=Changelog degraded::git-cliff failed; the release was published with GitHub's generic notes instead of the Conventional Commit changelog."
|
|
290
|
+
echo "::error::Nothing was lost — the PyPI upload and the GitHub release for ${RELEASE_TAG} both completed."
|
|
291
|
+
echo "::error::Fix the cause, then either edit the release body by hand or re-run this job."
|
|
292
|
+
exit 1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
venv/
|
|
12
|
+
|
|
13
|
+
# Tooling caches
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
|
|
18
|
+
# Local agent/editor tooling — vendored or generated, not project artifacts.
|
|
19
|
+
# .specify/ is deliberately NOT listed: it carries the project constitution
|
|
20
|
+
# (.specify/memory/constitution.md), which governs this repo.
|
|
21
|
+
.claude/
|
|
22
|
+
.codegraph/
|
|
23
|
+
.cursor/
|
|
24
|
+
.aider*
|
|
25
|
+
.idea/
|
|
26
|
+
.vscode/
|
|
27
|
+
|
|
28
|
+
# Secrets
|
|
29
|
+
.env
|
|
30
|
+
.env.*
|
|
31
|
+
|
|
32
|
+
# OS
|
|
33
|
+
.DS_Store
|
|
34
|
+
Thumbs.db
|
|
35
|
+
*.swp
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Machine-local Spec Kit state — not meant to be shared.
|
|
2
|
+
# Managed by the Specify CLI; safe to edit (your changes are preserved on refresh).
|
|
3
|
+
|
|
4
|
+
# Local pointer to the current feature directory. Rewritten every time you
|
|
5
|
+
# switch features, so it is per-checkout state rather than something to share.
|
|
6
|
+
feature.json
|
|
7
|
+
|
|
8
|
+
# Per-machine extension config overrides.
|
|
9
|
+
extensions/*/local-config.yml
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.1",
|
|
3
|
+
"integration_state_schema": 1,
|
|
4
|
+
"installed_integrations": [
|
|
5
|
+
"claude"
|
|
6
|
+
],
|
|
7
|
+
"integration_settings": {
|
|
8
|
+
"claude": {
|
|
9
|
+
"script": "sh",
|
|
10
|
+
"invoke_separator": "-"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"integration": "claude",
|
|
14
|
+
"default_integration": "claude"
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"integration": "claude",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"installed_at": "2026-09-01T00:45:12.876815+00:00",
|
|
5
|
+
"files": {
|
|
6
|
+
".claude/skills/speckit-analyze/SKILL.md": "e1f8323285ed23a9ec6b74a6436d7ebd23a3511778d5cc181bd27afa2b545427",
|
|
7
|
+
".claude/skills/speckit-clarify/SKILL.md": "f4b3f2c95087ac2343c0b67faff67f7223d34213ca1816aa25908db5b9aff0ac",
|
|
8
|
+
".claude/skills/speckit-constitution/SKILL.md": "a93047917a5fefeefff7aa35991109ce8f9938c4890e52206408b511bf756eb5",
|
|
9
|
+
".claude/skills/speckit-implement/SKILL.md": "51bd89322e0258ae377ea66a6af41a159b0e1a05304d5a17ea0f9a9baa6640a9",
|
|
10
|
+
".claude/skills/speckit-converge/SKILL.md": "65ea8b863835750931b522a9935391da887c4d188f1410113d16efe6396c2214",
|
|
11
|
+
".claude/skills/speckit-plan/SKILL.md": "2fe3f96886e96284965c8586d14df5d226c1e796b3eb39d110c9d8231abe6417",
|
|
12
|
+
".claude/skills/speckit-checklist/SKILL.md": "34c8c681f5472f2790d65ac29ca01e23f4f32ab6f06c9dca1b38fc89e2cfba86",
|
|
13
|
+
".claude/skills/speckit-specify/SKILL.md": "42fe016b9183bb8fa7ce7c65e04ea8d382f7f2abfc94849aeead999247675886",
|
|
14
|
+
".claude/skills/speckit-tasks/SKILL.md": "597853362a0a770fe967c5d56136e2db38de1aa7b97b89552db667b70ac493c1",
|
|
15
|
+
".claude/skills/speckit-taskstoissues/SKILL.md": "76a6ec1fcc2d4f2f4ae4d1a70e59eca034fd9a3f97c5454094b023ed3da65151"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"integration": "speckit",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"installed_at": "2026-09-01T00:45:12.891097+00:00",
|
|
5
|
+
"files": {
|
|
6
|
+
".specify/scripts/bash/common.sh": "de9a49210b1a136e4e7b2bc0c16010a773bace22ef6fa19419b6bc652d50bc3c",
|
|
7
|
+
".specify/scripts/bash/setup-plan.sh": "061cec0c6d71f8f88008b4d3d7f5bbc2bfbdb85d734d9e73fc5f07a3c60c88a6",
|
|
8
|
+
".specify/scripts/bash/setup-tasks.sh": "4a33dd1e6c32ddc7d570f4b538572c54069192573eed0ec654d9fb826e31a4fe",
|
|
9
|
+
".specify/scripts/bash/check-prerequisites.sh": "a7020699e6b6011aae09cffd7b20890b1321df7a12d8fe2814841ae99cba910f",
|
|
10
|
+
".specify/scripts/bash/resolve-template.sh": "829e227096abc8bf0889889ec9f792f503ca5d395b7836a8a7eb739ee75214e7",
|
|
11
|
+
".specify/scripts/bash/create-new-feature.sh": "fe99ea8da184380056ce8512ca5d37f67fb499ee4234835c15dcf7c4fb75451c",
|
|
12
|
+
".specify/templates/constitution-template.md": "ce7549540fa45543cca797a150201d868e64495fdff39dc38246fb17bd4024b3",
|
|
13
|
+
".specify/templates/checklist-template.md": "856532b3cb66171c662cc16f16b31a5856e4655a8666aad1e545bbfc7f603ca1",
|
|
14
|
+
".specify/templates/tasks-template.md": "fc29a233f6f5a27ca31f1aa46b596af6500c627441c6e62b2bc4a1d721525842",
|
|
15
|
+
".specify/templates/spec-template.md": "3945437fc35cd30a5b2bf7beea680337c3516826d3efa5a6b92c4a7eca1ba28e",
|
|
16
|
+
".specify/templates/plan-template.md": "7e637502d41eccf0ca672496636365691fdca62ef37b27ec07fcb412dbfa90d4",
|
|
17
|
+
".specify/.gitignore": "8c908410d177a1ef3d0dee16d7ad55f2ac3333df3104c4d4adee1c9b82f1dbc1"
|
|
18
|
+
}
|
|
19
|
+
}
|