Skip to content

Commit 6df486c

Browse files
authored
Copier update: workflow summary (#87)
Pull in upstream template changes Tested in downstream repos, including LabAutomationAndScreening/cloud-courier#51 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Enhanced CI/CD pipeline with duplicate pull request detection to prevent redundant checks * Added template version validation workflow for release tag enforcement * **Chores** * Updated devcontainer base image and VS Code extensions to latest versions * Updated development tool dependencies (pnpm, Pulumi, and related packages) * Improved GitHub CLI permission rules for enhanced security controls * Added optional Pulumi CLI installation skipping for faster setup * **Documentation** * Expanded developer testing guidelines with isolation patterns and mock/spy assertions * Enhanced tooling best practices with explicit command execution preferences <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 747600a commit 6df486c

29 files changed

+378
-59
lines changed

.claude/settings/permissions/bash.jsonc

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,17 @@
7474
"Bash(tail *)",
7575
// Search
7676
"Bash(rg *)",
77+
// Research
78+
"Bash(gh issue list *)",
79+
"Bash(gh pr view *)",
80+
"Bash(gh pr diff *)"
7781
],
7882
"ask": [
79-
"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
83+
// 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
84+
"Bash(gh repo *)",
85+
"Bash(gh release *)",
86+
"Bash(gh secret *)",
87+
"Bash(gh ruleset *)",
8088
"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)
8189
"Bash(curl *)",
8290
"Bash(ln *)",
@@ -85,6 +93,17 @@
8593
"deny": [
8694
// Exceptions to generally allowed AI tooling
8795
"Bash(bd init*)", // we need to control the init process, don't let AI do that in the background
96+
// Github
97+
// Claude should not ever interfere with the PR process, that is how we gate AI's work
98+
"Bash(gh pr create *)",
99+
"Bash(gh pr edit *)",
100+
"Bash(gh pr ready *)",
101+
"Bash(gh pr review *)",
102+
"Bash(gh pr merge *)",
103+
"Bash(gh pr close *)",
104+
"Bash(gh pr comment *)",
105+
"Bash(gh pr update-branch *)",
106+
88107
// Destructive File Operations
89108
"Bash(chmod -R *)",
90109
"Bash(chown -R *)",

.coderabbit.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ reviews:
77
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."
88
- path: "**/*.py"
99
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."
10+
- path: "**/.copier-answers.yml"
11+
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."
1012
tools:
1113
eslint: # when the code contains typescript, eslint will be run by pre-commit, and coderabbit often generates false positives
1214
enabled: false

.copier-answers.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Changes here will be overwritten by Copier
2-
_commit: v0.0.106
2+
_commit: v0.0.109
33
_src_path: gh:LabAutomationAndScreening/copier-base-template.git
44
description: Copier template for creating Python libraries and executables
55
install_claude_cli: true

.devcontainer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# base image tags available at https://mcr.microsoft.com/v2/devcontainers/universal/tags/list
22
# 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
33
# hadolint ignore=DL3029
4-
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:5.1.4-noble
4+
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:5.1.5-noble
55

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

.devcontainer/devcontainer.json

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
2+
"hostRequirements": {
3+
"cpus": 2,
4+
"memory": "4gb"
5+
},
26
"dockerComposeFile": "docker-compose.yml",
37
"service": "devcontainer",
48
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
@@ -22,21 +26,21 @@
2226
"ms-vscode.live-server@0.5.2025051301",
2327
"MS-vsliveshare.vsliveshare@1.0.5905",
2428
"github.copilot@1.388.0",
25-
"github.copilot-chat@0.38.2026022704",
26-
"anthropic.claude-code@2.1.74",
29+
"github.copilot-chat@0.42.2026032602",
30+
"anthropic.claude-code@2.1.84",
2731

2832
// Python
29-
"ms-python.python@2026.2.2026021801",
30-
"ms-python.vscode-pylance@2026.1.1",
33+
"ms-python.python@2026.5.2026032701",
34+
"ms-python.vscode-pylance@2026.1.102",
3135
"ms-vscode-remote.remote-containers@0.414.0",
32-
"charliermarsh.ruff@2026.36.0",
36+
"charliermarsh.ruff@2026.38.0",
3337

3438
// Misc file formats
3539
"bierner.markdown-mermaid@1.29.0",
3640
"samuelcolvin.jinjahtml@0.20.0",
3741
"tamasfe.even-better-toml@0.19.2",
3842
"emilast.LogFileHighlighter@3.3.3",
39-
"esbenp.prettier-vscode@12.3.0"
43+
"esbenp.prettier-vscode@12.4.0"
4044
],
4145
"settings": {
4246
"editor.accessibilitySupport": "off", // turn off sounds
@@ -61,5 +65,5 @@
6165
"initializeCommand": "sh .devcontainer/initialize-command.sh",
6266
"onCreateCommand": "sh .devcontainer/on-create-command.sh",
6367
"postStartCommand": "sh .devcontainer/post-start-command.sh"
64-
// Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): c4997eda # spellchecker:disable-line
68+
// Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): d77a3ff3 # spellchecker:disable-line
6569
}

.devcontainer/install-ci-tooling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pathlib import Path
99

1010
UV_VERSION = "0.10.12"
11-
PNPM_VERSION = "10.32.1"
11+
PNPM_VERSION = "10.33.0"
1212
COPIER_VERSION = "==9.14.0"
1313
COPIER_TEMPLATE_EXTENSIONS_VERSION = "==0.3.3"
1414
PRE_COMMIT_VERSION = "4.5.1"

.devcontainer/manual-setup-deps.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
default=False,
4545
help="Allow uv to install new versions of Python on the fly. This is typically only needed when instantiating the copier template.",
4646
)
47+
_ = parser.add_argument(
48+
"--skip-installing-pulumi-cli",
49+
action="store_true",
50+
default=False,
51+
help="Do not install the Pulumi CLI even if the lock file references it",
52+
)
4753

4854

4955
class PackageManager(str, enum.Enum):
@@ -127,6 +133,17 @@ def main():
127133
check=True,
128134
env=uv_env,
129135
)
136+
if (
137+
not generate_lock_file_only
138+
and not args.skip_installing_pulumi_cli
139+
and platform.system() == "Linux"
140+
and env.lock_file.exists()
141+
and '"pulumi"' in env.lock_file.read_text()
142+
):
143+
_ = subprocess.run(
144+
["sh", str(REPO_ROOT_DIR / ".devcontainer" / "install-pulumi-cli.sh"), str(env.lock_file)],
145+
check=True,
146+
)
130147
elif env.package_manager == PackageManager.PNPM:
131148
pnpm_command = ["pnpm", "install", "--dir", str(env.path)]
132149
if env_check_lock:

.devcontainer/on-create-command.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ set -ex
33

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

810
sh .devcontainer/on-create-command-boilerplate.sh
911
# install json5 for merging claude settings. TODO: consider if we can install json5 globally...or somehow eliminate this dependency
10-
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
11-
repo_root="$(CDPATH= cd -- "$script_dir/.." && pwd)"
1212
mkdir -p "$repo_root/.claude"
1313
chmod -R ug+rwX "$repo_root/.claude"
1414
chgrp -R 0 "$repo_root/.claude" || true

.devcontainer/post-start-command.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ set -ex
33

44
# For some reason the directory is not setup correctly and causes build of devcontainer to fail since
55
# it doesn't have access to the workspace directory. This can normally be done in post-start-command
6-
git config --global --add safe.directory /workspaces/copier-python-package-template
6+
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
7+
repo_root="$(CDPATH= cd -- "$script_dir/.." && pwd)"
8+
git config --global --add safe.directory "$repo_root"
79
pre-commit run merge-claude-settings -a
810
if ! bd ready; then
911
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
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Check Skip Duplicates
2+
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.'
3+
4+
outputs:
5+
should-run:
6+
description: 'Flag that determines if this execution should run or not'
7+
value: ${{ steps.check.outputs.should_run }}
8+
9+
runs:
10+
using: composite
11+
steps:
12+
- name: Check if push has associated open PR
13+
id: check
14+
env:
15+
GH_TOKEN: ${{ github.token }}
16+
REF_NAME: ${{ github.ref_name }}
17+
REPO_NAME: ${{ github.repository }}
18+
EVENT_NAME: ${{ github.event_name }}
19+
shell: bash
20+
run: |
21+
# For non-push events, always run
22+
if [ "$EVENT_NAME" != "push" ]; then
23+
echo "should_run=true" >> $GITHUB_OUTPUT
24+
echo "Event is $EVENT_NAME, will run CI"
25+
exit 0
26+
fi
27+
28+
# For push events, check if there's an open PR for this branch
29+
pr_json=$(gh pr list \
30+
--repo "$REPO_NAME" \
31+
--head "$REF_NAME" \
32+
--state open \
33+
--json number \
34+
--limit 1)
35+
36+
pr_number=$(echo "$pr_json" | jq -r '.[0].number // ""')
37+
38+
if [ -n "$pr_number" ]; then
39+
echo "should_run=false" >> $GITHUB_OUTPUT
40+
echo "Push to branch with open PR #$pr_number detected, skipping (PR event will run CI)"
41+
else
42+
echo "should_run=true" >> $GITHUB_OUTPUT
43+
echo "Push to branch without open PR, will run CI"
44+
fi

0 commit comments

Comments
 (0)