gcp-pytemplate 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.
- gcp_pytemplate-0.1.0/.gitattributes +2 -0
- gcp_pytemplate-0.1.0/.github/CODEOWNERS +1 -0
- gcp_pytemplate-0.1.0/.github/dependabot.yml +36 -0
- gcp_pytemplate-0.1.0/.github/workflows/release.yml +47 -0
- gcp_pytemplate-0.1.0/.github/workflows/tests.yml +32 -0
- gcp_pytemplate-0.1.0/.gitignore +223 -0
- gcp_pytemplate-0.1.0/.mcp.json +7 -0
- gcp_pytemplate-0.1.0/.pre-commit-config.yaml +17 -0
- gcp_pytemplate-0.1.0/.python-version +1 -0
- gcp_pytemplate-0.1.0/AGENTS.md +115 -0
- gcp_pytemplate-0.1.0/CHANGELOG.md +185 -0
- gcp_pytemplate-0.1.0/CLAUDE.md +1 -0
- gcp_pytemplate-0.1.0/LICENSE +21 -0
- gcp_pytemplate-0.1.0/Makefile +51 -0
- gcp_pytemplate-0.1.0/PKG-INFO +222 -0
- gcp_pytemplate-0.1.0/README.md +192 -0
- gcp_pytemplate-0.1.0/SECURITY.md +22 -0
- gcp_pytemplate-0.1.0/examples/api_project.yaml +12 -0
- gcp_pytemplate-0.1.0/examples/cli_project.yaml +12 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/.gcp-pytemplate.yaml +8 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/.gitattributes +2 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/.gitignore +90 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/.python-version +1 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/AGENTS.md +89 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/Makefile +58 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/Procfile +2 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/README.md +77 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/deploy_configs/prod.deploy.env +16 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/deploy_configs/stage.deploy.env +16 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/pyproject.toml +64 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/scripts/deploy_cloud_run.sh +101 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/scripts/invoke_cloud_run.sh +116 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/api/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/api/router.py +44 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/app/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/app/models.py +36 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/config/app_config.py +64 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/config/app_configs/local.env +5 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/config/app_configs/prod.env +5 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/config/app_configs/stage.env +5 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/config/gcp_env.py +79 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/config/logging_config.py +96 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/main_api.py +70 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/utils/cache.py +55 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/utils/gcp_auth/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/utils/gcp_auth/exceptions.py +9 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/src/example_api_service/utils/gcp_auth/service_account.py +169 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/tests/conftest.py +5 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/tests/integration/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/tests/unit/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/tests/unit/test_base_api.py +38 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/tests/unit/test_cache.py +184 -0
- gcp_pytemplate-0.1.0/examples/example-api-service/uv.lock +976 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/.gcp-pytemplate.yaml +8 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/.gitattributes +2 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/.gitignore +90 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/.python-version +1 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/AGENTS.md +97 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/Makefile +51 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/Procfile +5 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/README.md +78 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/deploy_configs/prod.deploy.env +16 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/deploy_configs/stage.deploy.env +16 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/pyproject.toml +65 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/scripts/deploy_cloud_run_job.sh +109 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/scripts/execute_cloud_run_job.sh +92 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/app/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/app/models.py +36 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/cli/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/cli/commands.py +34 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/config/app_config.py +64 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/config/app_configs/local.env +5 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/config/app_configs/prod.env +5 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/config/app_configs/stage.env +5 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/config/gcp_env.py +79 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/config/logging_config.py +96 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/main_cli.py +14 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/utils/cache.py +55 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/utils/gcp_auth/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/utils/gcp_auth/exceptions.py +9 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/src/example_cli_job/utils/gcp_auth/service_account.py +169 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/tests/conftest.py +5 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/tests/integration/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/tests/unit/__init__.py +0 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/tests/unit/test_base_cli.py +34 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/tests/unit/test_cache.py +184 -0
- gcp_pytemplate-0.1.0/examples/example-cli-job/uv.lock +684 -0
- gcp_pytemplate-0.1.0/pyproject.toml +143 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/__init__.py +5 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/main.py +463 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/mcp_server.py +244 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/render.py +99 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/.gitattributes +2 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/.gitignore +90 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/.python-version +1 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/AGENTS.md +115 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/Makefile +84 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/Procfile +11 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/README.md +114 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/deploy_configs/prod.deploy.env +29 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/deploy_configs/stage.deploy.env +29 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/pyproject.toml.jinja +79 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/scripts/deploy_cloud_run.sh +101 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/scripts/deploy_cloud_run_job.sh +109 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/scripts/execute_cloud_run_job.sh +92 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/scripts/invoke_cloud_run.sh +116 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/__init__.py +0 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/api/__init__.py +0 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/api/router.py +44 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/app/__init__.py +0 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/app/models.py +36 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/cli/__init__.py +0 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/cli/commands.py +34 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/config/app_config.py +64 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/config/app_configs/local.env +5 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/config/app_configs/prod.env +5 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/config/app_configs/stage.env +5 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/config/gcp_env.py +79 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/config/logging_config.py +96 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/main_api.py +70 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/main_cli.py +14 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/utils/cache.py +55 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/utils/gcp_auth/__init__.py +0 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/utils/gcp_auth/exceptions.py +9 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/src/{{ project_module }}/utils/gcp_auth/service_account.py +169 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/tests/conftest.py +5 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/tests/integration/__init__.py +0 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/tests/unit/__init__.py +0 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/tests/unit/test_base_api.py +38 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/tests/unit/test_base_cli.py +34 -0
- gcp_pytemplate-0.1.0/src/gcp_pytemplate/templates/app/{{ project_slug }}/tests/unit/test_cache.py +184 -0
- gcp_pytemplate-0.1.0/tests/__init__.py +0 -0
- gcp_pytemplate-0.1.0/tests/test_mcp_server.py +200 -0
- gcp_pytemplate-0.1.0/tests/test_render.py +410 -0
- gcp_pytemplate-0.1.0/tests/test_update.py +211 -0
- gcp_pytemplate-0.1.0/uv.lock +1831 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @jasonlopez01
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
updates:
|
|
4
|
+
# Only the tool itself is listed here.
|
|
5
|
+
#
|
|
6
|
+
# Deliberately excluded:
|
|
7
|
+
# src/gcp_pytemplate/templates/ Jinja2 sources; the pyproject.toml there is not valid TOML
|
|
8
|
+
# until rendered, so nothing can resolve its dependencies.
|
|
9
|
+
# examples/ generated output. Its pyproject.toml files must keep matching
|
|
10
|
+
# what `make generate-examples` produces, so a bump there would
|
|
11
|
+
# desync them from the template.
|
|
12
|
+
- package-ecosystem: "uv"
|
|
13
|
+
directory: "/"
|
|
14
|
+
schedule:
|
|
15
|
+
interval: "weekly"
|
|
16
|
+
open-pull-requests-limit: 5
|
|
17
|
+
# chore is non-releasable under [tool.semantic_release], so a dependency bump never cuts a
|
|
18
|
+
# release on its own. Change to "fix" if you would rather they ship as patch releases.
|
|
19
|
+
commit-message:
|
|
20
|
+
prefix: "chore"
|
|
21
|
+
groups:
|
|
22
|
+
python-dependencies:
|
|
23
|
+
patterns:
|
|
24
|
+
- "*"
|
|
25
|
+
|
|
26
|
+
- package-ecosystem: "github-actions"
|
|
27
|
+
directory: "/"
|
|
28
|
+
schedule:
|
|
29
|
+
interval: "weekly"
|
|
30
|
+
open-pull-requests-limit: 5
|
|
31
|
+
commit-message:
|
|
32
|
+
prefix: "ci"
|
|
33
|
+
groups:
|
|
34
|
+
github-actions:
|
|
35
|
+
patterns:
|
|
36
|
+
- "*"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_run:
|
|
5
|
+
workflows: [Tests]
|
|
6
|
+
types: [completed]
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write # PSR: push version commit + tag, create GitHub release
|
|
11
|
+
id-token: write # PyPI: OIDC trusted publisher (no token needed)
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
release:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0 # PSR needs full git history to parse commits
|
|
21
|
+
|
|
22
|
+
- uses: astral-sh/setup-uv@v5
|
|
23
|
+
|
|
24
|
+
- name: Semantic Release
|
|
25
|
+
id: release
|
|
26
|
+
uses: python-semantic-release/python-semantic-release@v9
|
|
27
|
+
with:
|
|
28
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
29
|
+
|
|
30
|
+
# Built here rather than through PSR's build_command: that runs inside the PSR container,
|
|
31
|
+
# which has no uv, so it failed with exit 127. By this point PSR has created the version
|
|
32
|
+
# tag, so hatch-vcs resolves the real version rather than a .dev local one.
|
|
33
|
+
- name: Build distributions
|
|
34
|
+
if: steps.release.outputs.released == 'true'
|
|
35
|
+
run: uv build
|
|
36
|
+
|
|
37
|
+
- name: Publish to PyPI
|
|
38
|
+
# Note: no credentials needed, the OIDC trusted publisher handles auth
|
|
39
|
+
if: steps.release.outputs.released == 'true'
|
|
40
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
41
|
+
|
|
42
|
+
- name: Attach distributions to the GitHub Release
|
|
43
|
+
if: steps.release.outputs.released == 'true'
|
|
44
|
+
uses: python-semantic-release/publish-action@v9
|
|
45
|
+
with:
|
|
46
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
47
|
+
tag: ${{ steps.release.outputs.tag }}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: astral-sh/setup-uv@v5
|
|
14
|
+
- run: uv sync --group dev
|
|
15
|
+
- run: uv run ruff check .
|
|
16
|
+
- run: uv run ruff format --check .
|
|
17
|
+
|
|
18
|
+
test:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-tags: true # hatch-vcs needs tags to resolve the package version
|
|
28
|
+
- uses: astral-sh/setup-uv@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
- run: uv sync --group dev
|
|
32
|
+
- run: uv run pytest
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# poetry
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
102
|
+
#poetry.lock
|
|
103
|
+
|
|
104
|
+
# pdm
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
106
|
+
#pdm.lock
|
|
107
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
108
|
+
# in version control.
|
|
109
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
110
|
+
.pdm.toml
|
|
111
|
+
|
|
112
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
113
|
+
__pypackages__/
|
|
114
|
+
|
|
115
|
+
# Celery stuff
|
|
116
|
+
celerybeat-schedule
|
|
117
|
+
celerybeat.pid
|
|
118
|
+
|
|
119
|
+
# SageMath parsed files
|
|
120
|
+
*.sage.py
|
|
121
|
+
|
|
122
|
+
# Environments
|
|
123
|
+
.venv
|
|
124
|
+
env/
|
|
125
|
+
venv/
|
|
126
|
+
ENV/
|
|
127
|
+
env.bak/
|
|
128
|
+
venv.bak/
|
|
129
|
+
|
|
130
|
+
# Spyder project settings
|
|
131
|
+
.spyderproject
|
|
132
|
+
.spyproject
|
|
133
|
+
|
|
134
|
+
# Rope project settings
|
|
135
|
+
.ropeproject
|
|
136
|
+
|
|
137
|
+
# mkdocs documentation
|
|
138
|
+
/site
|
|
139
|
+
|
|
140
|
+
# mypy
|
|
141
|
+
.mypy_cache/
|
|
142
|
+
.dmypy.json
|
|
143
|
+
dmypy.json
|
|
144
|
+
|
|
145
|
+
# Pyre type checker
|
|
146
|
+
.pyre/
|
|
147
|
+
|
|
148
|
+
# pytype static type analyzer
|
|
149
|
+
.pytype/
|
|
150
|
+
|
|
151
|
+
# Cython debug symbols
|
|
152
|
+
cython_debug/
|
|
153
|
+
|
|
154
|
+
# PyCharm
|
|
155
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
156
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
157
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
158
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
159
|
+
.idea/
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# VSCode
|
|
163
|
+
.vscode/*
|
|
164
|
+
!.vscode/settings.json
|
|
165
|
+
!.vscode/tasks.json
|
|
166
|
+
!.vscode/launch.json
|
|
167
|
+
!.vscode/extensions.json
|
|
168
|
+
!.vscode/*.code-snippets
|
|
169
|
+
|
|
170
|
+
# Local History for Visual Studio Code
|
|
171
|
+
.history/
|
|
172
|
+
|
|
173
|
+
# Built Visual Studio Code Extensions
|
|
174
|
+
*.vsix
|
|
175
|
+
|
|
176
|
+
# Mac files
|
|
177
|
+
**/.DS_Store
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# Terraform
|
|
181
|
+
|
|
182
|
+
# Local .terraform directories
|
|
183
|
+
**/.terraform/*
|
|
184
|
+
|
|
185
|
+
# .tfstate files
|
|
186
|
+
*.tfstate
|
|
187
|
+
*.tfstate.*
|
|
188
|
+
|
|
189
|
+
# Crash log files
|
|
190
|
+
crash.log
|
|
191
|
+
|
|
192
|
+
# Exclude all .tfvars files, which are likely to contain sentitive data, such as
|
|
193
|
+
# password, private keys, and other secrets. These should not be part of version
|
|
194
|
+
# control as they are data points which are potentially sensitive and subject
|
|
195
|
+
# to change depending on the environment.
|
|
196
|
+
#
|
|
197
|
+
*.tfvars
|
|
198
|
+
|
|
199
|
+
# Ignore override files as they are usually used to override resources locally and so
|
|
200
|
+
# are not checked in
|
|
201
|
+
override.tf
|
|
202
|
+
override.tf.json
|
|
203
|
+
*_override.tf
|
|
204
|
+
*_override.tf.json
|
|
205
|
+
|
|
206
|
+
# Include override files you do wish to add to version control using negated pattern
|
|
207
|
+
#
|
|
208
|
+
# !example_override.tf
|
|
209
|
+
|
|
210
|
+
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
|
|
211
|
+
# example: *tfplan*
|
|
212
|
+
|
|
213
|
+
# Ignore CLI configuration files
|
|
214
|
+
.terraformrc
|
|
215
|
+
terraform.rc
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# Added:
|
|
219
|
+
secrets/
|
|
220
|
+
TODO
|
|
221
|
+
|
|
222
|
+
# Per-machine Claude Code settings (contains local absolute paths)
|
|
223
|
+
.claude/settings.local.json
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v5.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: trailing-whitespace
|
|
6
|
+
- id: end-of-file-fixer
|
|
7
|
+
# Files under templates/ contain Jinja2 syntax and are not valid TOML/YAML until rendered.
|
|
8
|
+
- id: check-yaml
|
|
9
|
+
exclude: ^src/gcp_pytemplate/templates/
|
|
10
|
+
- id: check-toml
|
|
11
|
+
exclude: ^src/gcp_pytemplate/templates/
|
|
12
|
+
|
|
13
|
+
- repo: https://github.com/commitizen-tools/commitizen
|
|
14
|
+
rev: v4.1.0
|
|
15
|
+
hooks:
|
|
16
|
+
- id: commitizen
|
|
17
|
+
stages: [commit-msg]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# gcp-pytemplate — Agent Guide
|
|
2
|
+
|
|
3
|
+
A CLI tool that scaffolds production-ready GCP Python projects. It renders a Jinja2 template tree into a new project directory.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
Use `make` for all core operations.
|
|
8
|
+
|
|
9
|
+
| Command | Description |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `make setup` | Install dependencies and git hooks |
|
|
12
|
+
| `make install` | Install CLI and MCP server globally as editable (source changes apply immediately) |
|
|
13
|
+
| `make lint` | Lint and autoformat (ruff) |
|
|
14
|
+
| `make test` | Run tests |
|
|
15
|
+
| `make test-all` | Run tests against all supported Python versions (3.10–3.14) |
|
|
16
|
+
| `make generate-examples` | Regenerate `examples/` from the YAML files in `examples/*.yaml` |
|
|
17
|
+
|
|
18
|
+
Do not invoke `uv`, `ruff`, or `pytest` directly — use the make targets above.
|
|
19
|
+
|
|
20
|
+
### MCP server
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
gcp-pytemplate-mcp # starts the stdio MCP server (requires the [mcp] extra)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
See the **MCP Server** section in `README.md` for installation and client config.
|
|
27
|
+
|
|
28
|
+
### Running the CLI
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uv run gcp-pytemplate new # interactive prompts
|
|
32
|
+
uv run gcp-pytemplate new --from-file examples/api_project.yaml
|
|
33
|
+
uv run gcp-pytemplate update <project-path> --components logging_config
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Project Layout
|
|
37
|
+
|
|
38
|
+
- `src/gcp_pytemplate/main.py` — Typer CLI (`new` and `update` commands), input validation, Jinja2 context assembly
|
|
39
|
+
- `src/gcp_pytemplate/render.py` — walks the template tree, renders file contents and paths with Jinja2
|
|
40
|
+
- `src/gcp_pytemplate/templates/app/{{ project_slug }}/` — the project template (Jinja2; not valid Python until rendered)
|
|
41
|
+
- `examples/` — pre-generated example projects (`example-api-service`, `example-cli-job`) plus the YAML inputs used to generate them
|
|
42
|
+
- `src/gcp_pytemplate/mcp_server.py` — MCP server (`create_project`, `update_project`, `list_components` tools)
|
|
43
|
+
- `tests/` — `test_render.py` (template output), `test_update.py` (update command), `test_mcp_server.py` (MCP tools)
|
|
44
|
+
|
|
45
|
+
## Coding Standards
|
|
46
|
+
|
|
47
|
+
**Use Pydantic for data modeling.** Prefer `pydantic.BaseModel` over native `@dataclass` for any structured data (config objects, request/response shapes, context models). Use `model_validator` and `field_validator` for validation logic rather than `__post_init__`. Pydantic models are the single source of truth for schema, validation, and serialization.
|
|
48
|
+
|
|
49
|
+
**Use modern Python type hints.** Target Python 3.10+ syntax throughout:
|
|
50
|
+
- Built-in generics: `list[str]`, `dict[str, int]`, `tuple[str, ...]` — not `List`, `Dict`, `Tuple` from `typing`
|
|
51
|
+
- Union shorthand: `str | None` — not `Optional[str]` or `Union[str, None]`
|
|
52
|
+
- `typing.Any`, `typing.Literal`, `typing.TypeVar`, `typing.Protocol` are still fine where needed
|
|
53
|
+
- Annotate all function signatures (parameters and return types); omit only where the type is genuinely unknowable
|
|
54
|
+
|
|
55
|
+
**Write pytest-style tests.** Use plain functions (`def test_*`) and `assert` statements — no `unittest.TestCase`. Fixtures go in `conftest.py`. Parametrize with `@pytest.mark.parametrize` rather than looping inside a test. Use `tmp_path` for filesystem fixtures. Avoid mocking internals; test at the public API surface.
|
|
56
|
+
|
|
57
|
+
## Key Rules
|
|
58
|
+
|
|
59
|
+
**CLI and MCP server must stay in sync.** When adding or changing inputs to the `new` command in `main.py` (parameters, defaults, validation, resolution logic), apply the equivalent change to `create_project` in `mcp_server.py`. Both share `_build_context()` for validation, but default resolution (e.g. git/gcloud config lookups) and the elicitation summary in `_format_summary` must be updated manually to match.
|
|
60
|
+
|
|
61
|
+
**Templates and examples must stay in sync.** When editing any file under `templates/`, apply the equivalent change to the corresponding file in `examples/example-api-service/` and/or `examples/example-cli-job/`. Alternatively, run `make generate-examples` to fully regenerate both examples (only appropriate when the change should affect all generated content, not for manual example-specific edits).
|
|
62
|
+
|
|
63
|
+
**Templates are excluded from ruff.** Files under `src/gcp_pytemplate/templates/` contain Jinja2 syntax and are not valid Python — ruff is configured to skip them. Don't run linting on template files.
|
|
64
|
+
|
|
65
|
+
**A `.jinja` suffix on a template file is stripped when rendered.** `pyproject.toml.jinja` renders to `pyproject.toml`. Use this for any template whose real filename would make external tooling try to parse it: under its real name, GitHub's dependency graph picked up the template `pyproject.toml` as a pip manifest and failed on the Jinja2 syntax. The suffix is stripped before the exclusion rules in `render.py` are evaluated, so those rules are written against the final path.
|
|
66
|
+
|
|
67
|
+
**Keep documentation in sync.** When making changes that affect functionality or interfaces (CLI flags, MCP tools, Python version support, make targets, project layout), update `README.md` and `AGENTS.md` to match. The Prerequisites, Usage, and Development sections of `README.md` and the Commands table in `AGENTS.md` are the primary places to check.
|
|
68
|
+
|
|
69
|
+
**Commit style: conventional commits.** Pre-commit hooks enforce the format. Prefixes and their effect on versioning and the changelog:
|
|
70
|
+
|
|
71
|
+
| Prefix | Version bump | In changelog |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `feat:` | minor | yes |
|
|
74
|
+
| `fix:`, `perf:` | patch | yes |
|
|
75
|
+
| `docs:` | none | yes |
|
|
76
|
+
| `chore:`, `ci:`, `style:`, `test:`, `refactor:` | none | no |
|
|
77
|
+
|
|
78
|
+
## SQL Conventions
|
|
79
|
+
|
|
80
|
+
**Use fully qualified resource paths.** Always reference tables with their full path — no bare table names:
|
|
81
|
+
- BigQuery: `project.dataset.table`
|
|
82
|
+
- Other databases: `database.schema.table`
|
|
83
|
+
|
|
84
|
+
**Use lowercase keywords.** Write all SQL keywords in lowercase: `select`, `from`, `where`, `join`, `group by`, `order by`, etc.
|
|
85
|
+
|
|
86
|
+
**Use single spaces around aliases.** No alignment padding — exactly one space on each side of `as`:
|
|
87
|
+
```sql
|
|
88
|
+
-- correct
|
|
89
|
+
select
|
|
90
|
+
order_id as id,
|
|
91
|
+
customer_name as name
|
|
92
|
+
from project.dataset.orders
|
|
93
|
+
|
|
94
|
+
-- wrong
|
|
95
|
+
select
|
|
96
|
+
order_id as id,
|
|
97
|
+
customer_name as name
|
|
98
|
+
from project.dataset.orders
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Use trailing commas.** Place commas at the end of each item in a select list, not the beginning.
|
|
102
|
+
|
|
103
|
+
**Indent with 4 spaces.** Indent column lists and `on` clauses 4 spaces relative to their clause keyword.
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
## Writing Style
|
|
107
|
+
|
|
108
|
+
**Avoid AI tells.** Comments, docs, commit messages, and PR descriptions should read like they were written by a developer, not generated. Specific patterns to avoid:
|
|
109
|
+
|
|
110
|
+
- No em-dashes (`—`). Use a comma, semicolon, colon, or rewrite the sentence.
|
|
111
|
+
- No filler openers: "Certainly", "Sure", "Of course", "Absolutely", "Great", "Happy to help".
|
|
112
|
+
- No over-explanation of obvious things. If the code is clear, don't restate it in a comment.
|
|
113
|
+
- No "This commit..." or "This PR..." prefix in commit/PR titles. Start with the verb: "Add", "Fix", "Remove", "Update".
|
|
114
|
+
- No closing affirmations: "Let me know if you have questions", "Hope this helps", "Feel free to reach out".
|
|
115
|
+
- Prefer plain words over formal ones: "use" not "utilize", "show" not "demonstrate", "check" not "verify" when the meaning is the same.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## v0.1.0 (2026-08-06)
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- Guard destructive scaffolding and repair generated project defects
|
|
9
|
+
([`20be16b`](https://github.com/jasonlopez01/gcp-pytemplate/commit/20be16b8212ae0e155e9acfbf5787b9c2133102e))
|
|
10
|
+
|
|
11
|
+
The MCP create_project tool silently overwrote an existing project's files. It now refuses a
|
|
12
|
+
non-empty target unless overwrite=true, validates input before prompting, and warns in the
|
|
13
|
+
confirmation summary when it will replace a directory. The CLI gained a matching --overwrite flag.
|
|
14
|
+
|
|
15
|
+
A project name consisting only of punctuation slugified to "", which resolved the project root back
|
|
16
|
+
to the output directory itself; confirming the overwrite prompt then deleted that directory.
|
|
17
|
+
Project names are now rejected unless they produce an importable module name.
|
|
18
|
+
|
|
19
|
+
Jinja2 strips the final newline by default, so every rendered file was written without one and
|
|
20
|
+
generated projects failed their own ruff format check. Render with keep_trailing_newline and fix
|
|
21
|
+
the template lint errors this exposed, plus the trailing blank lines it surfaced in the Makefile
|
|
22
|
+
and deploy configs.
|
|
23
|
+
|
|
24
|
+
gcp_env raised a ValidationError at import when a runtime set a service name but no revision, and an
|
|
25
|
+
unreachable metadata server took the whole app down. It also stamped "not-set" over real
|
|
26
|
+
GCP_PROJECT and GCP_REGION values on local runs; the export is now gated on IS_DEPLOYED and never
|
|
27
|
+
overwrites.
|
|
28
|
+
|
|
29
|
+
Also corrects the documented Python version: the tool needs 3.10+, but generated projects pin 3.13+.
|
|
30
|
+
|
|
31
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
32
|
+
|
|
33
|
+
- Handle non-text files in the template tree
|
|
34
|
+
([`d22c21c`](https://github.com/jasonlopez01/gcp-pytemplate/commit/d22c21ca1bf33b5a842a0ea572357b86c368371f))
|
|
35
|
+
|
|
36
|
+
A .DS_Store inside the template root aborted the whole render with an uncaught UnicodeDecodeError.
|
|
37
|
+
Because it sorts first, no files were written at all, and the traceback did not name the offending
|
|
38
|
+
file. Only jinja2.TemplateError was caught, so the decode error escaped.
|
|
39
|
+
|
|
40
|
+
Skip OS metadata by name, since it should never reach a generated project, and fall back to copying
|
|
41
|
+
any file that is not valid UTF-8 rather than trying to render it. Binary assets in the template
|
|
42
|
+
now pass through untouched.
|
|
43
|
+
|
|
44
|
+
Pin the read and write encoding to UTF-8 and write with newline="" so output does not depend on the
|
|
45
|
+
host locale, and so rendered shell scripts and Procfiles keep LF endings on Windows hosts instead
|
|
46
|
+
of gaining CRLF.
|
|
47
|
+
|
|
48
|
+
render_service takes an optional template_root so tests can render a fixture tree instead of the
|
|
49
|
+
packaged one; the five new tests each fail against the specific defect they cover.
|
|
50
|
+
|
|
51
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
52
|
+
|
|
53
|
+
- Keep per-machine Claude Code settings out of the sdist
|
|
54
|
+
([`a975aa1`](https://github.com/jasonlopez01/gcp-pytemplate/commit/a975aa1b00cf449e7486afaa94af119b14822cad))
|
|
55
|
+
|
|
56
|
+
.claude/settings.local.json was reaching the published sdist, carrying local absolute paths. It is
|
|
57
|
+
untracked only because of a user-level global gitignore, which hatchling does not read.
|
|
58
|
+
|
|
59
|
+
Ignore it in the repo and exclude /.claude from the sdist target so the result does not depend on
|
|
60
|
+
how an individual clone is configured.
|
|
61
|
+
|
|
62
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
63
|
+
|
|
64
|
+
- Pin example authors so regeneration is user-independent
|
|
65
|
+
([`850d24c`](https://github.com/jasonlopez01/gcp-pytemplate/commit/850d24c4dc592d87276be1be1636b6b882ca3756))
|
|
66
|
+
|
|
67
|
+
The example YAML inputs omitted author_name and author_email, so 'new' fell back to the git config
|
|
68
|
+
of whoever ran make generate-examples and wrote that identity into each example's pyproject.toml
|
|
69
|
+
and .gcp-pytemplate.yaml.
|
|
70
|
+
|
|
71
|
+
Set both fields explicitly to a documentation address (RFC 2606) so the examples regenerate
|
|
72
|
+
byte-identically for any contributor.
|
|
73
|
+
|
|
74
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
75
|
+
|
|
76
|
+
- Rename the template pyproject so tooling stops parsing it
|
|
77
|
+
([`4854701`](https://github.com/jasonlopez01/gcp-pytemplate/commit/4854701cd3100663f7c317fa00c5a465d8f854dd))
|
|
78
|
+
|
|
79
|
+
GitHub's dependency graph scans the repo for manifests by filename, found
|
|
80
|
+
src/gcp_pytemplate/templates/app/{{ project_slug }}/pyproject.toml, and failed on the Jinja2
|
|
81
|
+
syntax. That produced a failing "Graph Update: pip in ..." job on every scan. Dependabot config
|
|
82
|
+
cannot exclude a path from the graph, so the file has to stop looking like a manifest.
|
|
83
|
+
|
|
84
|
+
render.py now strips a trailing .jinja from the rendered path, and the template is named
|
|
85
|
+
pyproject.toml.jinja. Stripping happens before the exclusion rules are evaluated so those rules
|
|
86
|
+
stay written against final paths.
|
|
87
|
+
|
|
88
|
+
Rendered output is unchanged: both examples regenerate byte-identically, and a project scaffolded
|
|
89
|
+
from the built wheel still produces a parseable pyproject.toml with no .jinja files left behind.
|
|
90
|
+
|
|
91
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
92
|
+
|
|
93
|
+
- Serve the health check at the configured route
|
|
94
|
+
([`28193f8`](https://github.com/jasonlopez01/gcp-pytemplate/commit/28193f8b867b430debc974f72fea373f51292039))
|
|
95
|
+
|
|
96
|
+
HEALTH_CHECK_ROUTE was defined in app_config and set in the app config env files, but main_api
|
|
97
|
+
hardcoded "/healthcheck", so changing the setting had no effect. Bind the route to
|
|
98
|
+
APP_CONFIG.HEALTH_CHECK_ROUTE and read it from the same config in the generated test.
|
|
99
|
+
|
|
100
|
+
invoke_cloud_run.sh --health also assumed the default path. It now resolves the route from the app
|
|
101
|
+
config named by the deploy config, falling back to /healthcheck, so the shorthand keeps working on
|
|
102
|
+
a customized route.
|
|
103
|
+
|
|
104
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
105
|
+
|
|
106
|
+
- Validate update paths and fail cleanly without a terminal
|
|
107
|
+
([`3b8f40d`](https://github.com/jasonlopez01/gcp-pytemplate/commit/3b8f40d5871d56e92ec6092fb90421273e76e0eb))
|
|
108
|
+
|
|
109
|
+
The MCP update_project tool rejected absolute and parent-relative --files paths, but the CLI update
|
|
110
|
+
command did not, and an absolute path there crashed with an unhandled ValueError from relative_to
|
|
111
|
+
when printing results. Move the check into a shared _validate_rel_paths helper so both entry
|
|
112
|
+
points enforce it.
|
|
113
|
+
|
|
114
|
+
The questionary prompts also raised an opaque OSError with a full traceback when stdin was not a
|
|
115
|
+
terminal, which made scripted use of new and update unusable. Fall back to the documented defaults
|
|
116
|
+
for the interfaces and deploy target prompts, decline the overwrite prompt (pointing at
|
|
117
|
+
--overwrite), and require --components or --files for update. Aborting because the target exists
|
|
118
|
+
now exits 1 instead of 0.
|
|
119
|
+
|
|
120
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
121
|
+
|
|
122
|
+
### Documentation
|
|
123
|
+
|
|
124
|
+
- Add security and codeowners
|
|
125
|
+
([`b3741d1`](https://github.com/jasonlopez01/gcp-pytemplate/commit/b3741d128d6240c17b9a4a0a8403571d96b55a01))
|
|
126
|
+
|
|
127
|
+
- Correct the deploy script referenced by execute_cloud_run_job
|
|
128
|
+
([`81eccc1`](https://github.com/jasonlopez01/gcp-pytemplate/commit/81eccc1baaac666e0f3aafd6ae493d4fdc15c42e))
|
|
129
|
+
|
|
130
|
+
The requirements comment pointed at deploy_job_from_image.sh, which is not part of the template; the
|
|
131
|
+
script that deploys the job is deploy_cloud_run_job.sh.
|
|
132
|
+
|
|
133
|
+
Also record why args travel in an env var, and that --update-env-vars on 'jobs execute' is a
|
|
134
|
+
per-execution override rather than an edit to the deployed job definition.
|
|
135
|
+
|
|
136
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
137
|
+
|
|
138
|
+
- Update agent guides
|
|
139
|
+
([`0730b28`](https://github.com/jasonlopez01/gcp-pytemplate/commit/0730b28848969191f562e67504520cbb3b6e28c5))
|
|
140
|
+
|
|
141
|
+
- Update docs
|
|
142
|
+
([`d583193`](https://github.com/jasonlopez01/gcp-pytemplate/commit/d583193bca7784dc9451fb163633ef0393a5d1f6))
|
|
143
|
+
|
|
144
|
+
- Update examples
|
|
145
|
+
([`b583a45`](https://github.com/jasonlopez01/gcp-pytemplate/commit/b583a45454b798eb0bb9ed6fd542b650614993bc))
|
|
146
|
+
|
|
147
|
+
- Update notes
|
|
148
|
+
([`0c0404f`](https://github.com/jasonlopez01/gcp-pytemplate/commit/0c0404f84b1865d034aeef262e3ff8b96e51721e))
|
|
149
|
+
|
|
150
|
+
- Update readmes
|
|
151
|
+
([`7d3ab3d`](https://github.com/jasonlopez01/gcp-pytemplate/commit/7d3ab3ddcbc8b2c29ef8bcca8c578f30d9c361d5))
|
|
152
|
+
|
|
153
|
+
### Features
|
|
154
|
+
|
|
155
|
+
- Collect an author name only, never an email
|
|
156
|
+
([`9bd8e7c`](https://github.com/jasonlopez01/gcp-pytemplate/commit/9bd8e7c7ffa53ef39079da12a9bc6fbfab86f94d))
|
|
157
|
+
|
|
158
|
+
Author was the one input resolved silently: gcp_project, gcp_region and gcp_service_account are all
|
|
159
|
+
prompted with a visible default, while name and email were read from git config and written into
|
|
160
|
+
the generated project without ever being shown. Prompt for the name with git config as the default
|
|
161
|
+
so the identity that lands in pyproject.toml is always something the user saw, and drop email
|
|
162
|
+
collection entirely. Users who want an email published can add the key to their pyproject.toml by
|
|
163
|
+
hand.
|
|
164
|
+
|
|
165
|
+
The generated authors block is now conditional. An empty entry is a hard build failure ("Author #1
|
|
166
|
+
of field project.authors must specify either name or email"), which create_project could already
|
|
167
|
+
produce on a machine with no git identity because it fell back to empty strings while the CLI fell
|
|
168
|
+
back to placeholder text. Both now agree, and the field is omitted rather than emitted blank.
|
|
169
|
+
|
|
170
|
+
Removes the --author-email flag and the author_email tool argument.
|
|
171
|
+
|
|
172
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
173
|
+
|
|
174
|
+
- Log unhandled request errors and report env in the health check
|
|
175
|
+
([`8e2c6c3`](https://github.com/jasonlopez01/gcp-pytemplate/commit/8e2c6c38320f8fb8a25dfe7f10faeab03bbd49fb))
|
|
176
|
+
|
|
177
|
+
The request logging middleware wrapped call_next without a handler, so an unhandled error in a route
|
|
178
|
+
produced no request log line at all, only the server's own traceback. Wrap it, emit the failure
|
|
179
|
+
with its duration, and re-raise.
|
|
180
|
+
|
|
181
|
+
The health check hardcoded the project slug as the service name, which drifts from whatever APP_NAME
|
|
182
|
+
the loaded config sets. Source both the service name and the environment from APP_CONFIG so the
|
|
183
|
+
response follows APP_CONFIG_FILE.
|
|
184
|
+
|
|
185
|
+
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|