Skip to content

Commit 1c80ea2

Browse files
committed
pull in
1 parent 068b547 commit 1c80ea2

32 files changed

Lines changed: 494 additions & 184 deletions

‎.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.116
2+
_commit: v0.0.119-5-g9e48575
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 & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
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.5-noble
4+
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:6.0.3-noble
55

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

8-
# temporary hack until yarn updates its GPG key
9-
RUN rm /etc/apt/sources.list.d/yarn.list || true && \
10-
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /etc/apt/keyrings/yarn-archive-keyring.gpg > /dev/null
11-
128
RUN apt-get update -y && apt-get install -y \
139
"bash-completion=$(apt-cache madison bash-completion | awk '{print $3}' | grep '^1:2.11' | head -n 1)" --no-install-recommends \
1410
&& apt-get clean \

‎.devcontainer/devcontainer.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
"extensions": [
2323
// basic tooling
2424
// "eamodio.gitlens@15.5.1",
25-
"coderabbit.coderabbit-vscode@0.18.5",
25+
"coderabbit.coderabbit-vscode@0.19.2",
2626
"ms-vscode.live-server@0.5.2025051301",
2727
"MS-vsliveshare.vsliveshare@1.0.5905",
2828
"github.copilot@1.388.0",
2929
"github.copilot-chat@0.44.2",
30-
"anthropic.claude-code@2.1.117",
30+
"anthropic.claude-code@2.1.126",
3131

3232
// Python
3333
"ms-python.python@2026.5.2026032701",
@@ -54,7 +54,7 @@
5454
},
5555
"ruff.nativeServer": "on",
5656
// TODO: see if there's a way to specify different configurations for different folders
57-
"ruff.configuration": "/workspaces/copier-python-package-template/ruff-test.toml", // use the test configuration since it's less restrictive and won't show false positives and underline things
57+
"ruff.configuration": "/workspaces/copier-python-package-template/ruff-non-src.toml", // use the non-src configuration since it's less restrictive and won't show false positives and underline things
5858
"[jsonc][json][javascript][typescript][graphql][css][scss][html][vue]": {
5959
"editor.defaultFormatter": "esbenp.prettier-vscode",
6060
"editor.formatOnSave": true
@@ -65,5 +65,5 @@
6565
"initializeCommand": "sh .devcontainer/initialize-command.sh",
6666
"onCreateCommand": "sh .devcontainer/on-create-command.sh",
6767
"postStartCommand": "sh .devcontainer/post-start-command.sh"
68-
// Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 1d087024 # spellchecker:disable-line
68+
// Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 4ff43210 # spellchecker:disable-line
6969
}

‎.devcontainer/install-ci-tooling.py‎

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import tempfile
88
from pathlib import Path
99

10-
UV_VERSION = "0.11.7"
11-
PNPM_VERSION = "10.33.1"
12-
COPIER_VERSION = "==9.14.3"
10+
UV_VERSION = "0.11.12"
11+
PNPM_VERSION = "11.0.9"
12+
COPIER_VERSION = "==9.15.0"
1313
COPIER_TEMPLATE_EXTENSIONS_VERSION = "==0.3.3"
1414
PRE_COMMIT_VERSION = "4.5.1"
1515
GITHUB_WINDOWS_RUNNER_BIN_PATH = r"C:\Users\runneradmin\.local\bin"
@@ -52,7 +52,7 @@ def main():
5252
if is_windows:
5353
uv_env.update({"PATH": rf"{GITHUB_WINDOWS_RUNNER_BIN_PATH};{uv_env['PATH']}"})
5454
# invoke installer in a pwsh process
55-
_ = subprocess.run(
55+
_ = subprocess.run( # noqa: S603 # this is all our own input
5656
[
5757
pwsh, # type: ignore[reportPossiblyUnboundVariable] # this matches the conditional above that defines pwsh
5858
"-NoProfile",
@@ -64,14 +64,14 @@ def main():
6464
env=uv_env,
6565
)
6666
else:
67-
_ = subprocess.run(
67+
_ = subprocess.run( # noqa: S602 # we need to set shell to true to use the pipe operator, and this is all our own input
6868
f"curl -fsSL --connect-timeout 20 --max-time 40 --retry 3 --retry-delay 5 --retry-connrefused --proto '=https' https://astral.sh/uv/{UV_VERSION}/install.sh | sh",
6969
check=True,
7070
shell=True,
7171
env=uv_env,
7272
)
7373
# TODO: add uv autocompletion to the shell https://docs.astral.sh/uv/getting-started/installation/#shell-autocompletion
74-
_ = subprocess.run(
74+
_ = subprocess.run( # noqa: S603 # this is all our own input
7575
[
7676
uv_path,
7777
"tool",
@@ -83,7 +83,7 @@ def main():
8383
check=True,
8484
env=uv_env,
8585
)
86-
_ = subprocess.run(
86+
_ = subprocess.run( # noqa: S603 # this is all our own input
8787
[
8888
uv_path,
8989
"tool",
@@ -93,7 +93,7 @@ def main():
9393
check=True,
9494
env=uv_env,
9595
)
96-
_ = subprocess.run(
96+
_ = subprocess.run( # noqa: S603 # this is all our own input
9797
[
9898
uv_path,
9999
"tool",
@@ -105,7 +105,7 @@ def main():
105105
if not args.no_node:
106106
pnpm_install_sequence = ["npm -v", f"npm install -g pnpm@{PNPM_VERSION}", "pnpm -v"]
107107
for cmd in pnpm_install_sequence:
108-
cmd = (
108+
run_cmd = (
109109
[
110110
pwsh, # type: ignore[reportPossiblyUnboundVariable] # this matches the conditional above that defines pwsh
111111
"-NoProfile",
@@ -116,46 +116,54 @@ def main():
116116
if is_windows
117117
else [cmd]
118118
)
119-
_ = subprocess.run(cmd, shell=True, check=True)
119+
_ = subprocess.run(run_cmd, shell=True, check=True) # noqa: S602 # we need shell=True for npm commands, and this is all our own input
120120
if INSTALL_SSM_PLUGIN_BY_DEFAULT and not args.skip_installing_ssm_plugin:
121121
with tempfile.TemporaryDirectory() as tmp_dir:
122122
if is_windows:
123123
local_package_path = Path(tmp_dir) / "SessionManagerPluginSetup.exe"
124124
# Based on https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-windows.html
125125
# no specific reason for that version, just pinning it for best practice
126-
_ = subprocess.run(
127-
[
126+
_ = subprocess.run( # noqa: S603 # this is all our own input
127+
[ # noqa: S607 # curl should always be on PATH
128128
"curl",
129129
"https://s3.amazonaws.com/session-manager-downloads/plugin/1.2.707.0/windows/SessionManagerPluginSetup.exe",
130130
"-o",
131131
f"{local_package_path}",
132132
],
133133
check=True,
134134
)
135-
_ = subprocess.run(
135+
_ = subprocess.run( # noqa: S603 # this is all our own input
136136
[str(local_package_path), "/quiet"],
137137
check=True,
138138
)
139139
else:
140140
local_package_path = Path(tmp_dir) / "session-manager-plugin.deb"
141141
# Based on https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-debian-and-ubuntu.html
142142
# no specific reason for that version, just pinning it for best practice
143-
_ = subprocess.run(
144-
[
143+
_ = subprocess.run( # noqa: S603 # this is all our own input
144+
[ # noqa: S607 # curl should always be on PATH
145145
"curl",
146146
"https://s3.amazonaws.com/session-manager-downloads/plugin/1.2.707.0/ubuntu_64bit/session-manager-plugin.deb",
147147
"-o",
148148
f"{local_package_path}",
149149
],
150150
check=True,
151151
)
152-
_ = subprocess.run(
153-
["sudo", "dpkg", "-i", str(local_package_path)],
152+
_ = subprocess.run( # noqa: S603 # this is all our own input
153+
[ # noqa: S607 # sudo should always be on PATH
154+
"sudo",
155+
"dpkg",
156+
"-i",
157+
str(local_package_path),
158+
],
154159
check=True,
155160
)
156-
print("SSM Plugin Manager Version: ")
161+
print("SSM Plugin Manager Version: ") # noqa: T201 # we want the script to print to console for easy viewing
157162
_ = subprocess.run(
158-
["session-manager-plugin", "--version"],
163+
[ # noqa: S607 # session-manager-plugin should be on PATH because we just installed it
164+
"session-manager-plugin",
165+
"--version",
166+
],
159167
check=True,
160168
)
161169

‎.devcontainer/manual-setup-deps.py‎

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import argparse
2-
import enum
32
import json
43
import os
54
import platform
65
import shutil
76
import subprocess
87
import sys
8+
from enum import StrEnum
99
from pathlib import Path
1010
from typing import Any
1111

@@ -53,7 +53,7 @@
5353
)
5454

5555

56-
class PackageManager(str, enum.Enum):
56+
class PackageManager(StrEnum):
5757
UV = "uv"
5858
PNPM = "pnpm"
5959

@@ -73,7 +73,7 @@ def __init__(self, json_dict: dict[str, Any]):
7373
raise NotImplementedError(f"Package manager {self.package_manager} is not supported")
7474

7575

76-
def main():
76+
def main(): # noqa: C901,PLR0912,PLR0915 # TODO: cleanup into some subfunctions
7777
args = parser.parse_args(sys.argv[1:])
7878
is_windows = platform.system() == "Windows"
7979
uv_env = dict(os.environ)
@@ -82,7 +82,9 @@ def main():
8282
generate_lock_file_only = args.only_create_lock
8383
check_lock_file = not (args.skip_check_lock or args.optionally_check_lock or generate_lock_file_only)
8484
if args.skip_check_lock and args.optionally_check_lock:
85-
print("Cannot skip and optionally check the lock file at the same time.")
85+
print( # noqa: T201 # we want this to print to console for easy viewing
86+
"Cannot skip and optionally check the lock file at the same time."
87+
)
8688
sys.exit(1)
8789

8890
with ENVS_CONFIG.open("r") as f:
@@ -91,10 +93,14 @@ def main():
9193
for env_dict in envs:
9294
env = EnvConfig(env_dict)
9395
if args.no_python and env.package_manager == PackageManager.UV:
94-
print(f"Skipping environment {env.path} as it uses a Python package manager and --no-python is set")
96+
print( # noqa: T201 # we want this to print to console for easy viewing
97+
f"Skipping environment {env.path} as it uses a Python package manager and --no-python is set"
98+
)
9599
continue
96100
if args.no_node and env.package_manager == PackageManager.PNPM:
97-
print(f"Skipping environment {env.path} as it uses a Node package manager and --no-node is set")
101+
print( # noqa: T201 # we want this to print to console for easy viewing
102+
f"Skipping environment {env.path} as it uses a Node package manager and --no-node is set"
103+
)
98104
continue
99105
if env.package_manager == PackageManager.UV and not UV_PYTHON_ALREADY_CONFIGURED:
100106
if args.python_version is not None:
@@ -119,7 +125,9 @@ def main():
119125
if not generate_lock_file_only:
120126
uv_args.append("--check")
121127
uv_args.extend(["--directory", str(env.path)])
122-
_ = subprocess.run(uv_args, check=True, env=uv_env)
128+
_ = subprocess.run( # noqa: S603 # this is all our own input
129+
uv_args, check=True, env=uv_env
130+
)
123131
elif env.package_manager == PackageManager.PNPM:
124132
pass # doesn't seem to be a way to do this https://github.com/orgs/pnpm/discussions/3202
125133
else:
@@ -129,7 +137,7 @@ def main():
129137
if env_check_lock:
130138
sync_command.append("--frozen")
131139
if not generate_lock_file_only:
132-
_ = subprocess.run(
140+
_ = subprocess.run( # noqa: S603 # this is all our own input
133141
sync_command,
134142
check=True,
135143
env=uv_env,
@@ -142,18 +150,18 @@ def main():
142150
and '"pulumi"' in env.lock_file.read_text()
143151
):
144152
if not PULUMI_CLI_INSTALL_SCRIPT.exists():
145-
print(
153+
print( # noqa: T201 # we want this to print to console for easy viewing
146154
f"Pulumi CLI install script not found at {PULUMI_CLI_INSTALL_SCRIPT}, skipping Pulumi CLI installation"
147155
)
148156
else:
149-
_ = subprocess.run(
150-
["sh", str(PULUMI_CLI_INSTALL_SCRIPT), str(env.lock_file)],
157+
_ = subprocess.run( # noqa: S603 # this is all our own input
158+
["sh", str(PULUMI_CLI_INSTALL_SCRIPT), str(env.lock_file)], # noqa: S607 # sh should always be on PATH
151159
check=True,
152160
)
153161
elif env.package_manager == PackageManager.PNPM:
154162
pnpm_command = ["pnpm", "install", "--dir", str(env.path)]
155163
if env_check_lock:
156-
pnpm_command.append("--frozen-lockfile")
164+
pnpm_command[1] = "ci"
157165
if is_windows:
158166
pwsh = shutil.which("pwsh") or shutil.which("powershell")
159167
if not pwsh:
@@ -165,7 +173,7 @@ def main():
165173
"-Command",
166174
" ".join(pnpm_command),
167175
]
168-
_ = subprocess.run(
176+
_ = subprocess.run( # noqa: S603 # this is all our own input
169177
pnpm_command,
170178
check=True,
171179
)
@@ -180,7 +188,9 @@ def main():
180188
check=True,
181189
cwd=REPO_ROOT_DIR,
182190
)
183-
print(result.stdout)
191+
print( # noqa: T201 # we need this to print it out so that other scripts can read it from stdout
192+
result.stdout
193+
)
184194

185195

186196
if __name__ == "__main__":

‎.github/dependabot.yml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
version: 2
22
updates:
3+
- package-ecosystem: "devcontainers"
4+
directory: "/"
5+
schedule:
6+
interval: weekly
7+
day: "monday"
8+
time: "16:00"
9+
open-pull-requests-limit: 5
10+
ignore:
11+
- dependency-name: "*"
12+
update-types:
13+
- "version-update:semver-patch" # we don't want to be bothered with patch updates for anything except security updates
314
- package-ecosystem: "uv"
415
directories:
516
- "/"

‎.github/reusable_workflows/build-docker-image.yaml‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ on:
2121
type: string
2222
required: false
2323
default: './'
24+
build-contexts:
25+
description: 'Additional named build contexts (e.g. "repo-root=.")'
26+
type: string
27+
required: false
28+
default: ''
29+
additional-hash-paths:
30+
description: 'Space-separated extra file paths (relative to repo root) to include in the build context hash'
31+
type: string
32+
required: false
33+
default: ''
2434
push-role-name:
2535
type: string
2636
description: What's the IAM role name to use for Pushing to the ECR?
@@ -85,7 +95,12 @@ jobs:
8595
id: calculate-build-context-hash
8696
run: |
8797
python3 --version
88-
BUILD_HASH=$(python3 .github/workflows/hash_git_files.py ${{ inputs.context }})
98+
EXTRA_PATHS="${{ inputs.additional-hash-paths }}"
99+
EXTRA_ARGS=""
100+
if [ -n "$EXTRA_PATHS" ]; then
101+
EXTRA_ARGS="--extra-paths $EXTRA_PATHS"
102+
fi
103+
BUILD_HASH=$(python3 .github/workflows/hash_git_files.py ${{ inputs.context }} $EXTRA_ARGS)
89104
echo "build_context_tag=context-${BUILD_HASH}" >> "$GITHUB_OUTPUT"
90105
echo "Calculated build context tag as: ${BUILD_HASH}"
91106
@@ -123,15 +138,16 @@ jobs:
123138
124139
- name: Set up Docker Buildx
125140
if: ${{ (inputs.save-as-artifact && inputs.push-role-name == 'no-push') || steps.check-if-exists.outputs.status == 'notfound' }}
126-
uses: docker/setup-buildx-action@v3.11.1
141+
uses: docker/setup-buildx-action@v4.0.0
127142
with:
128-
version: v0.27.0
143+
version: v0.33.0
129144

130145
- name: Build Docker Image
131146
if: ${{ (inputs.save-as-artifact && inputs.push-role-name == 'no-push') || steps.check-if-exists.outputs.status == 'notfound' }}
132-
uses: docker/build-push-action@v6.18.0
147+
uses: docker/build-push-action@v7.1.0
133148
with:
134149
context: ${{ inputs.context }}
150+
build-contexts: ${{ inputs.build-contexts }}
135151
push: ${{ inputs.push-role-name != 'no-push' && steps.check-if-exists.outputs.status == 'notfound' }}
136152
load: ${{ inputs.save-as-artifact }} # make the image available later for the `docker save` step
137153
tags: ${{ steps.calculate-build-context-hash.outputs.full_image_tag }}

‎.github/workflows/ci.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ jobs:
173173
timeout-minutes: 8 # this is the amount of time this action will wait to attempt to acquire the mutex lock before failing, e.g. if other jobs are queued up in front of it
174174

175175
- name: Cache Pre-commit hooks
176-
uses: actions/cache@v5.0.4
176+
uses: actions/cache@v5.0.5
177177
env:
178178
cache-name: cache-pre-commit-hooks
179179
with:

0 commit comments

Comments
 (0)