Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion .claude/settings/permissions/bash.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,17 @@
"Bash(tail *)",
// Search
"Bash(rg *)",
// Research
"Bash(gh issue list *)",
"Bash(gh pr view *)",
"Bash(gh pr diff *)"
],
"ask": [
"Bash(gh *)", // let's hold off before we let it use the github CLI in any free running allow mode...I don't want it somehow approving PRs with the user's credentials
// let's hold off before we let it use the github CLI in any free running allow mode...I don't want it somehow approving PRs with the user's credentials
"Bash(gh repo *)",
"Bash(gh release *)",
"Bash(gh secret *)",
"Bash(gh ruleset *)",
"Bash(aws *)", // let's hold off before we let it use AWS CLI in any free running allow mode. We need to be very sure we don't have any access to staging or production credentials in our dev environment (...which we shouldn't...but we need to double check that or consider any other safeguards first)
"Bash(curl *)",
"Bash(ln *)",
Expand All @@ -85,6 +93,17 @@
"deny": [
// Exceptions to generally allowed AI tooling
"Bash(bd init*)", // we need to control the init process, don't let AI do that in the background
// Github
// Claude should not ever interfere with the PR process, that is how we gate AI's work
"Bash(gh pr create *)",
"Bash(gh pr edit *)",
"Bash(gh pr ready *)",
"Bash(gh pr review *)",
"Bash(gh pr merge *)",
"Bash(gh pr close *)",
"Bash(gh pr comment *)",
"Bash(gh pr update-branch *)",

// Destructive File Operations
"Bash(chmod -R *)",
"Bash(chown -R *)",
Expand Down
2 changes: 2 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ reviews:
instructions: "These files came from a vendor and we're not allowed to change them. Refer to it if you need to understand how the main code interacts with it, but do not make comments about it."
- path: "**/*.py"
instructions: "Check the `ruff.toml` and `ruff-test.toml` for linting rules we've explicitly disabled and don't suggest changes to please conventions we've disabled. Do not express concerns about ruff rules; a pre-commit hook already runs a ruff check. Do not warn about unnecessary super().__init__() calls; pyright prefers those to be present. Do not warn about missing type hints; a pre-commit hook already checks for that."
- path: "**/.copier-answers.yml"
instructions: "Do not comment about the `_commit` value needing to be a clean release tag. A CI job will fail if that is not the case."
tools:
eslint: # when the code contains typescript, eslint will be run by pre-commit, and coderabbit often generates false positives
enabled: false
Expand Down
2 changes: 1 addition & 1 deletion .copier-answers.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Changes here will be overwritten by Copier
_commit: v0.0.106
_commit: v0.0.109
_src_path: gh:LabAutomationAndScreening/copier-base-template.git
description: Copier template for creating Python libraries and executables
install_claude_cli: true
Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# base image tags available at https://mcr.microsoft.com/v2/devcontainers/universal/tags/list
# added the platform flag to override any local settings since this image is only compatible with linux/amd64. since this image is only x64 compatible, suppressing the hadolint rule
# hadolint ignore=DL3029
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:5.1.4-noble
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:5.1.5-noble

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

Expand Down
18 changes: 11 additions & 7 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"hostRequirements": {
"cpus": 2,
"memory": "4gb"
},
"dockerComposeFile": "docker-compose.yml",
"service": "devcontainer",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
Expand All @@ -22,21 +26,21 @@
"ms-vscode.live-server@0.5.2025051301",
"MS-vsliveshare.vsliveshare@1.0.5905",
"github.copilot@1.388.0",
"github.copilot-chat@0.38.2026022704",
"anthropic.claude-code@2.1.74",
"github.copilot-chat@0.42.2026032602",
"anthropic.claude-code@2.1.84",

// Python
"ms-python.python@2026.2.2026021801",
"ms-python.vscode-pylance@2026.1.1",
"ms-python.python@2026.5.2026032701",
"ms-python.vscode-pylance@2026.1.102",
"ms-vscode-remote.remote-containers@0.414.0",
"charliermarsh.ruff@2026.36.0",
"charliermarsh.ruff@2026.38.0",

// Misc file formats
"bierner.markdown-mermaid@1.29.0",
"samuelcolvin.jinjahtml@0.20.0",
"tamasfe.even-better-toml@0.19.2",
"emilast.LogFileHighlighter@3.3.3",
"esbenp.prettier-vscode@12.3.0"
"esbenp.prettier-vscode@12.4.0"
],
"settings": {
"editor.accessibilitySupport": "off", // turn off sounds
Expand All @@ -61,5 +65,5 @@
"initializeCommand": "sh .devcontainer/initialize-command.sh",
"onCreateCommand": "sh .devcontainer/on-create-command.sh",
"postStartCommand": "sh .devcontainer/post-start-command.sh"
// Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): c4997eda # spellchecker:disable-line
// Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): d77a3ff3 # spellchecker:disable-line
}
2 changes: 1 addition & 1 deletion .devcontainer/install-ci-tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pathlib import Path

UV_VERSION = "0.10.12"
PNPM_VERSION = "10.32.1"
PNPM_VERSION = "10.33.0"
COPIER_VERSION = "==9.14.0"
COPIER_TEMPLATE_EXTENSIONS_VERSION = "==0.3.3"
PRE_COMMIT_VERSION = "4.5.1"
Expand Down
17 changes: 17 additions & 0 deletions .devcontainer/manual-setup-deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
default=False,
help="Allow uv to install new versions of Python on the fly. This is typically only needed when instantiating the copier template.",
)
_ = parser.add_argument(
"--skip-installing-pulumi-cli",
action="store_true",
default=False,
help="Do not install the Pulumi CLI even if the lock file references it",
)


class PackageManager(str, enum.Enum):
Expand Down Expand Up @@ -127,6 +133,17 @@ def main():
check=True,
env=uv_env,
)
if (
not generate_lock_file_only
and not args.skip_installing_pulumi_cli
and platform.system() == "Linux"
and env.lock_file.exists()
and '"pulumi"' in env.lock_file.read_text()
):
_ = subprocess.run(
["sh", str(REPO_ROOT_DIR / ".devcontainer" / "install-pulumi-cli.sh"), str(env.lock_file)],
check=True,
)
Comment on lines +136 to +146
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the install script exists
fd -t f 'install-pulumi-cli.sh' .devcontainer

# Check the script's expected arguments
cat .devcontainer/install-pulumi-cli.sh 2>/dev/null | head -30

Repository: LabAutomationAndScreening/copier-python-package-template

Length of output: 82


🏁 Script executed:

#!/bin/bash
# List all files in .devcontainer directory
echo "=== All files in .devcontainer ===" 
fd -t f . .devcontainer

echo -e "\n=== Search for any install or pulumi related scripts ===" 
rg -l 'install|pulumi' .devcontainer --type sh 2>/dev/null || echo "No matches found"

echo -e "\n=== Check if .devcontainer directory exists ===" 
ls -la .devcontainer/ 2>/dev/null || echo ".devcontainer directory not found"

Repository: LabAutomationAndScreening/copier-python-package-template

Length of output: 1693


🏁 Script executed:

#!/bin/bash
# Search for any references to install-pulumi-cli in the codebase
echo "=== References to install-pulumi-cli ===" 
rg 'install-pulumi-cli' . --type py --type sh

echo -e "\n=== Context around line 136-146 in manual-setup-deps.py ===" 
head -150 .devcontainer/manual-setup-deps.py | tail -30

Repository: LabAutomationAndScreening/copier-python-package-template

Length of output: 1672


The Pulumi CLI install script referenced at line 139 does not exist in the repository.

The file .devcontainer/install-pulumi-cli.sh is missing. When the conditional logic evaluates to true (Linux platform, Pulumi in lock file, not skipping install), subprocess.run() with check=True will raise a CalledProcessError and crash the script. Either create the missing script or remove this installation logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.devcontainer/manual-setup-deps.py around lines 136 - 146, The code calls
subprocess.run on REPO_ROOT_DIR / ".devcontainer" / "install-pulumi-cli.sh" when
generate_lock_file_only is false, args.skip_installing_pulumi_cli is false and
env.lock_file contains "pulumi", but that script is missing and will raise
CalledProcessError; fix by either adding the missing script at
.devcontainer/install-pulumi-cli.sh or by guarding the call with a
file-existence check (e.g. verify (REPO_ROOT_DIR / ".devcontainer" /
"install-pulumi-cli.sh").exists()) and only invoking subprocess.run when the
script exists, or remove this installation branch entirely so
generate_lock_file_only / args.skip_installing_pulumi_cli / env.lock_file logic
does not attempt to run a non-existent installer (references:
generate_lock_file_only, args.skip_installing_pulumi_cli, env.lock_file, and the
install-pulumi-cli.sh path).

elif env.package_manager == PackageManager.PNPM:
pnpm_command = ["pnpm", "install", "--dir", str(env.path)]
if env_check_lock:
Expand Down
6 changes: 3 additions & 3 deletions .devcontainer/on-create-command.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ set -ex

# For some reason the directory is not setup correctly and causes build of devcontainer to fail since
# it doesn't have access to the workspace directory. This can normally be done in post-start-command
git config --global --add safe.directory /workspaces/copier-python-package-template
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
repo_root="$(CDPATH= cd -- "$script_dir/.." && pwd)"
git config --global --add safe.directory "$repo_root"

sh .devcontainer/on-create-command-boilerplate.sh
# install json5 for merging claude settings. TODO: consider if we can install json5 globally...or somehow eliminate this dependency
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
repo_root="$(CDPATH= cd -- "$script_dir/.." && pwd)"
mkdir -p "$repo_root/.claude"
chmod -R ug+rwX "$repo_root/.claude"
chgrp -R 0 "$repo_root/.claude" || true
Expand Down
4 changes: 3 additions & 1 deletion .devcontainer/post-start-command.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ set -ex

# For some reason the directory is not setup correctly and causes build of devcontainer to fail since
# it doesn't have access to the workspace directory. This can normally be done in post-start-command
git config --global --add safe.directory /workspaces/copier-python-package-template
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
repo_root="$(CDPATH= cd -- "$script_dir/.." && pwd)"
git config --global --add safe.directory "$repo_root"
pre-commit run merge-claude-settings -a
if ! bd ready; then
echo "It's likely the Dolt server has not yet been initialized to support beads, running that now" # TODO: figure out a better way to match this specific scenario than just a non-zero exit code...but beads still seems like in high flux right now so not sure what to tie it to
Expand Down
44 changes: 44 additions & 0 deletions .github/actions/check-skip-duplicates/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Check Skip Duplicates
description: 'Check that will output a variable to allow you to skip duplicate runs. Example: If you have both push and pull_request triggers enabled and you dont want to run 2 jobs for the same commit if a PR is already open you can add this to your jobs to skip that extra execution.'

outputs:
should-run:
description: 'Flag that determines if this execution should run or not'
value: ${{ steps.check.outputs.should_run }}

runs:
using: composite
steps:
- name: Check if push has associated open PR
id: check
env:
GH_TOKEN: ${{ github.token }}
REF_NAME: ${{ github.ref_name }}
REPO_NAME: ${{ github.repository }}
EVENT_NAME: ${{ github.event_name }}
shell: bash
run: |
# For non-push events, always run
if [ "$EVENT_NAME" != "push" ]; then
echo "should_run=true" >> $GITHUB_OUTPUT
echo "Event is $EVENT_NAME, will run CI"
exit 0
fi

# For push events, check if there's an open PR for this branch
pr_json=$(gh pr list \
--repo "$REPO_NAME" \
--head "$REF_NAME" \
--state open \
--json number \
--limit 1)

pr_number=$(echo "$pr_json" | jq -r '.[0].number // ""')

if [ -n "$pr_number" ]; then
echo "should_run=false" >> $GITHUB_OUTPUT
echo "Push to branch with open PR #$pr_number detected, skipping (PR event will run CI)"
else
echo "should_run=true" >> $GITHUB_OUTPUT
echo "Push to branch without open PR, will run CI"
fi
Comment on lines +1 to +44
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if the ci.yaml workflow has workflow-level permissions that would cover pull-requests: read
rg -n 'permissions:' -A 10 .github/workflows/ci.yaml | head -30

Repository: LabAutomationAndScreening/copier-python-package-template

Length of output: 1155


🏁 Script executed:

# Check GitHub Actions documentation patterns and verify the output naming
# Look for any other composite actions in the repo to see how they handle outputs
fd -e yml -e yaml | xargs grep -l "outputs:" | head -5

Repository: LabAutomationAndScreening/copier-python-package-template

Length of output: 82


🏁 Script executed:

# Get the full check-skip-duplicate job definition to see if it has a permissions block
sed -n '24,41p' .github/workflows/ci.yaml

Repository: LabAutomationAndScreening/copier-python-package-template

Length of output: 602


Add pull-requests: read permission to the check-skip-duplicate job.

The gh pr list command requires pull-requests: read permission. The workflow-level permissions define id-token: write and contents: read, but do not include pull-requests: read. The check-skip-duplicate job does not override this with an explicit permissions block, so the gh pr list call will fail with insufficient permissions.

Add a permissions block to the job:

check-skip-duplicate:
  runs-on: ubuntu-24.04
  permissions:
    pull-requests: read
  outputs:
    should-run: ${{ steps.check.outputs.should-run }}

The rest of the action logic is sound—the handling of non-push events and the jq null-coalescing are correct.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/check-skip-duplicates/action.yml around lines 1 - 44, The gh
pr list call in the composite action's check step requires pull-requests: read
permission, so update the job that uses this composite action (the
check-skip-duplicate job) to include a permissions block granting pull-requests:
read; specifically, in the workflow where you declare the check-skip-duplicate
job (the job with outputs.should-run and the step id "check"), add permissions:
pull-requests: read so the "gh pr list" command invoked in the action's step (id
"check") can run successfully.

7 changes: 6 additions & 1 deletion .github/actions/install_deps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ inputs:
description: Whether to skip updating the hash when running manual-setup-deps.py
default: true
required: false
skip-installing-pulumi-cli:
type: boolean
description: Whether to skip installing the Pulumi CLI even if the lock file references it
default: false
required: false


runs:
Expand Down Expand Up @@ -83,5 +88,5 @@ runs:
- name: Install dependencies
# the funky syntax is github action ternary
if: ${{ inputs.install-deps }}
run: python .devcontainer/manual-setup-deps.py ${{ inputs.python-version == 'notUsing' && '--no-python' || '' }} ${{ inputs.node-version == 'notUsing' && '--no-node' || '' }} ${{ inputs.skip-updating-devcontainer-hash && '--skip-updating-devcontainer-hash' || '' }}
run: python .devcontainer/manual-setup-deps.py ${{ inputs.python-version == 'notUsing' && '--no-python' || '' }} ${{ inputs.node-version == 'notUsing' && '--no-node' || '' }} ${{ inputs.skip-updating-devcontainer-hash && '--skip-updating-devcontainer-hash' || '' }} ${{ inputs.skip-installing-pulumi-cli && '--skip-installing-pulumi-cli' || '' }}
shell: pwsh
43 changes: 42 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,39 @@ on:
branches-ignore:
- 'gh-readonly-queue/**' # don't run (again) when on these special branches created during merge groups; the `on: merge_group` already triggers it.
merge_group:
pull_request:

env:
PYTHONUNBUFFERED: True
PRE_COMMIT_HOME: ${{ github.workspace }}/.precommit_cache

permissions:
id-token: write # needed to assume OIDC roles (e.g. for downloading from CodeArtifact)
contents: read # need to explicitly provide this whenever defining permissions because the default value is 'none' for anything not explicitly set when permissions are defined

jobs:
get-values:
uses: ./.github/workflows/get-values.yaml
permissions:
contents: write # needed for updating dependabot branches

check-skip-duplicate:
runs-on: ubuntu-24.04
outputs:
should-run: ${{ steps.check.outputs.should-run }}
steps:
- name: Checkout code
uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- id: check
uses: ./.github/actions/check-skip-duplicates

pre-commit:
needs:
- get-values
- check-skip-duplicate
if: needs.check-skip-duplicate.outputs.should-run == 'true'
uses: ./.github/workflows/pre-commit.yaml
permissions:
contents: write # needed for mutex
Expand All @@ -32,6 +48,8 @@ jobs:
unit-test:
needs:
- pre-commit
- check-skip-duplicate
if: needs.check-skip-duplicate.outputs.should-run == 'true'
strategy:
matrix:
os:
Expand Down Expand Up @@ -66,6 +84,8 @@ jobs:
lint-matrix:
needs:
- pre-commit
- check-skip-duplicate
if: needs.check-skip-duplicate.outputs.should-run == 'true'
strategy:
matrix:
os:
Expand Down Expand Up @@ -175,11 +195,18 @@ jobs:
name: pre-commit-log--${{ github.jobs.lint-matrix.name }}
path: "${{ github.workspace }}/.precommit_cache/pre-commit.log"

required-check:
confirm-on-tagged-copier-template:
if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }}
uses: ./.github/workflows/confirm-on-tagged-copier-template.yaml


workflow-summary:
runs-on: ubuntu-24.04
timeout-minutes: 2
needs:
- get-values
- check-skip-duplicate
- confirm-on-tagged-copier-template
- pre-commit
- unit-test
- lint-matrix
Expand All @@ -192,13 +219,27 @@ jobs:
success_pattern="^(skipped|success)$" # these are the possibilities: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#needs-context

if [[ ! "${{ needs.get-values.result }}" =~ $success_pattern ]] ||
[[ ! "${{ needs.confirm-on-tagged-copier-template.result }}" =~ $success_pattern ]] ||
[[ ! "${{ needs.check-skip-duplicate.result }}" =~ $success_pattern ]] ||
[[ ! "${{ needs.pre-commit.result }}" =~ $success_pattern ]] ||
[[ ! "${{ needs.unit-test.result }}" =~ $success_pattern ]] ||
[[ ! "${{ needs.lint-matrix.result }}" =~ $success_pattern ]]; then
echo "❌ One or more jobs did not finish with skipped or success"
exit 1
fi
echo "✅ All jobs finished with skipped or success"

- name: Mark the required-check as succeeded so the PR can be merged
if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }}
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api \
-X POST -H "Accept: application/vnd.github.v3+json" \
"${{ github.event.pull_request.statuses_url }}" \
-f state=success -f context="required-check" -f description="✅ All required checks passed in the job triggered by pull_request" \
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
Comment on lines +232 to +241
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

statuses_url is undefined for merge_group events.

Same issue as in the template: the condition includes merge_group, but github.event.pull_request.statuses_url only exists for pull_request events. This will cause the API call to fail during merge queue runs.

Proposed fix
       - name: Mark the required-check as succeeded so the PR can be merged
-        if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }}
+        if: ${{ github.event_name == 'pull_request' }}
         env:
           GH_TOKEN: ${{ github.token }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Mark the required-check as succeeded so the PR can be merged
if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }}
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api \
-X POST -H "Accept: application/vnd.github.v3+json" \
"${{ github.event.pull_request.statuses_url }}" \
-f state=success -f context="required-check" -f description="✅ All required checks passed in the job triggered by pull_request" \
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
- name: Mark the required-check as succeeded so the PR can be merged
if: ${{ github.event_name == 'pull_request' }}
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api \
-X POST -H "Accept: application/vnd.github.v3+json" \
"${{ github.event.pull_request.statuses_url }}" \
-f state=success -f context="required-check" -f description="✅ All required checks passed in the job triggered by pull_request" \
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yaml around lines 232 - 241, The workflow step "Mark
the required-check as succeeded so the PR can be merged" uses
github.event.pull_request.statuses_url which is only present for pull_request
events; modify the step's if condition so it only runs when a pull_request
payload exists (e.g. change the if to check github.event.pull_request != null or
restrict to github.event_name == 'pull_request') or otherwise short-circuit by
first deriving statuses_url into an env only if github.event.pull_request is
defined and skip the API call when it is undefined; update the step referenced
by its name and the use of github.event.pull_request.statuses_url accordingly.


- name: Mark updated dependabot hash commit as succeeded
if: needs.get-values.outputs.dependabot-commit-created == 'true'
env:
Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/confirm-on-tagged-copier-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Confirm using tagged copier template version

on:
workflow_call:
inputs:
answers_file:
description: 'Path to the copier answers file'
type: string
default: '.copier-answers.yml'

jobs:
confirm-on-tagged-copier-template:
runs-on: ubuntu-24.04
timeout-minutes: 2
name: Fail if template under development
steps:
- name: Checkout code
uses: actions/checkout@v6.0.2
with:
persist-credentials: false

- name: Check _commit is a clean release tag
run: |
ANSWERS_FILE="${{ inputs.answers_file }}"
if [ ! -f "$ANSWERS_FILE" ]; then
echo "Error: $ANSWERS_FILE not found"
exit 1
fi
COMMIT_LINE=$(grep "^_commit:" "$ANSWERS_FILE")
if echo "$COMMIT_LINE" | grep -q "-"; then
echo "Error: $COMMIT_LINE"
echo "_commit must be a clean release tag (e.g. v0.0.111), not a dev commit (e.g. v0.0.106-14-g7847d7b)"
exit 1
fi
Comment on lines +29 to +34
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider edge case: prerelease semver tags containing hyphens.

The hyphen check correctly rejects git-describe dev commits (e.g., v0.0.106-14-g7847d7b), but it would also reject valid prerelease tags like v1.0.0-alpha or v2.0.0-rc.1. If you only use simple numeric semver tags (as indicated by the example v0.0.111), this is fine. Otherwise, a more precise regex could distinguish git-describe format (which has the -<N>-g<hash> suffix pattern).

Optional: More precise git-describe detection
-          if echo "$COMMIT_LINE" | grep -q "-"; then
+          # git-describe format: v0.0.106-14-g7847d7b (tag-commits-gHASH)
+          if echo "$COMMIT_LINE" | grep -qE -- '-[0-9]+-g[0-9a-f]+'; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/confirm-on-tagged-copier-template.yaml around lines 29 -
34, The current hyphen-based rejection (checking COMMIT_LINE from ANSWERS_FILE
with grep -q "-") incorrectly rejects valid prerelease semver (e.g.,
v1.0.0-alpha); change the check to detect the specific git-describe dev suffix
pattern instead (match "-<number>-g<hash>", e.g. -[0-9]+-g[0-9a-f]+) using a
precise regex (grep -E or similar) against COMMIT_LINE, and update the error
message to mention that only git-describe style dev commits are rejected while
allowing prerelease tags.

1 change: 1 addition & 0 deletions .github/workflows/pre-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ jobs:
python-version: ${{ inputs.python-version }}
node-version: ${{ inputs.node-version }}
skip-installing-ssm-plugin-manager: true
skip-installing-pulumi-cli: true

- name: Set up mutex # Github concurrency management is horrible, things get arbitrarily cancelled if queued up. So using mutex until github fixes itself. When multiple jobs are modifying cache at once, weird things can happen. possible issue is https://github.com/actions/toolkit/issues/658
if: ${{ runner.os != 'Windows' }} # we're just gonna have to YOLO on Windows, because this action doesn't support it yet https://github.com/ben-z/gh-action-mutex/issues/14
Expand Down
Loading