diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9d12583a..dca586ef 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -71,5 +71,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): e3cf4594 # spellchecker:disable-line + // Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): d487598c # spellchecker:disable-line } diff --git a/.devcontainer/install-ci-tooling.py b/.devcontainer/install-ci-tooling.py index 30e47f60..23c5bc44 100644 --- a/.devcontainer/install-ci-tooling.py +++ b/.devcontainer/install-ci-tooling.py @@ -50,6 +50,27 @@ type=str, help="What version to install.", ) +_ = parser.add_argument( + "--install-pre-commit-tooling", + default=False, + action="store_true", + help="Install pre-commit, identify and prek in CI. Outside CI, this script always installs them.", +) +_ = parser.add_argument( + "--install-copier", + default=False, + action="store_true", + help="Install copier in CI. Outside CI, this script always installs it.", +) + + +def should_install(*, requested: bool) -> bool: + if requested: + return True + # GitHub Actions always sets CI, so its absence means a developer's machine or devcontainer, which gets every tool + if "CI" not in os.environ: + return True + return False def run_with_retries( @@ -176,40 +197,42 @@ def main(): _ = subprocess.run(["pnpm -v"], shell=True, check=True) # noqa: S602,S607 # we need shell=True for pnpm commands, and this is all our own input install_uv(uv_path=uv_path, uv_env=uv_env) if not args.no_python: - run_with_retries( - [ - uv_path, - "tool", - "install", - f"copier{COPIER_VERSION}", - "--with", - f"copier-template-extensions{COPIER_TEMPLATE_EXTENSIONS_VERSION}", - ], - description="Installing copier", - env=uv_env, - ) - run_with_retries( - [ - uv_path, - "tool", - "install", - f"pre-commit{PRE_COMMIT_VERSION}", - "--with", - f"identify{IDENTIFY_VERSION}", - ], - description="Installing pre-commit", - env=uv_env, - ) - run_with_retries( - [ - uv_path, - "tool", - "install", - f"prek{PREK_VERSION}", - ], - description="Installing prek", - env=uv_env, - ) + if should_install(requested=args.install_copier): + run_with_retries( + [ + uv_path, + "tool", + "install", + f"copier{COPIER_VERSION}", + "--with", + f"copier-template-extensions{COPIER_TEMPLATE_EXTENSIONS_VERSION}", + ], + description="Installing copier", + env=uv_env, + ) + if should_install(requested=args.install_pre_commit_tooling): + run_with_retries( + [ + uv_path, + "tool", + "install", + f"pre-commit{PRE_COMMIT_VERSION}", + "--with", + f"identify{IDENTIFY_VERSION}", + ], + description="Installing pre-commit", + env=uv_env, + ) + run_with_retries( + [ + uv_path, + "tool", + "install", + f"prek{PREK_VERSION}", + ], + description="Installing prek", + env=uv_env, + ) install_task(uv_path=uv_path, uv_env=uv_env) _ = subprocess.run( # noqa: S603 # this is all our own input [ diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d68f7c14..ada1a75d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -35,7 +35,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install Tooling - run: python .devcontainer/install-ci-tooling.py + run: python .devcontainer/install-ci-tooling.py --install-pre-commit-tooling - name: Install Dependencies run: | @@ -157,7 +157,7 @@ jobs: node-version: 24.11.1 - name: Install Tooling - run: python .devcontainer/install-ci-tooling.py + run: python .devcontainer/install-ci-tooling.py --install-copier --install-pre-commit-tooling - name: Instantiate copier template run: | diff --git a/template/.devcontainer/install-ci-tooling.py.jinja-base b/template/.devcontainer/install-ci-tooling.py.jinja-base index 544c4f89..26ec9d58 100644 --- a/template/.devcontainer/install-ci-tooling.py.jinja-base +++ b/template/.devcontainer/install-ci-tooling.py.jinja-base @@ -72,6 +72,27 @@ _ = parser.add_argument( default=False, help="Skip installing the SSM plugin for AWS CLI", ) +_ = parser.add_argument( + "--install-pre-commit-tooling", + action="store_true", + default=False, + help="Install pre-commit, identify and prek in CI. Outside CI, this script always installs them.", +) +_ = parser.add_argument( + "--install-copier", + action="store_true", + default=False, + help="Install copier in CI. Outside CI, this script always installs it.", +) + + +def should_install(*, requested: bool) -> bool: + if requested: + return True + # GitHub Actions always sets CI, so its absence means a developer's machine or devcontainer, which gets every tool + if "CI" not in os.environ: + return True + return False def pwsh_cmd(cmd: str) -> list[str]: @@ -352,40 +373,42 @@ def main(): uv_path = "uv" install_uv(uv_path=uv_path, uv_env=uv_env, is_windows=is_windows) if not args.no_python: - run_with_retries( - [ - uv_path, - "tool", - "install", - f"copier{COPIER_VERSION}", - "--with", - f"copier-template-extensions{COPIER_TEMPLATE_EXTENSIONS_VERSION}", - ], - description="Installing copier", - env=uv_env, - ) - run_with_retries( - [ - uv_path, - "tool", - "install", - f"pre-commit{PRE_COMMIT_VERSION}", - "--with", - f"identify{IDENTIFY_VERSION}", - ], - description="Installing pre-commit", - env=uv_env, - ) - run_with_retries( - [ - uv_path, - "tool", - "install", - f"prek{PREK_VERSION}", - ], - description="Installing prek", - env=uv_env, - ) + if should_install(requested=args.install_copier): + run_with_retries( + [ + uv_path, + "tool", + "install", + f"copier{COPIER_VERSION}", + "--with", + f"copier-template-extensions{COPIER_TEMPLATE_EXTENSIONS_VERSION}", + ], + description="Installing copier", + env=uv_env, + ) + if should_install(requested=args.install_pre_commit_tooling): + run_with_retries( + [ + uv_path, + "tool", + "install", + f"pre-commit{PRE_COMMIT_VERSION}", + "--with", + f"identify{IDENTIFY_VERSION}", + ], + description="Installing pre-commit", + env=uv_env, + ) + run_with_retries( + [ + uv_path, + "tool", + "install", + f"prek{PREK_VERSION}", + ], + description="Installing prek", + env=uv_env, + ) if not args.no_node: install_pnpm(is_windows=is_windows) # Task is installed outside the --no-node branch because CI always passes --no-node (pnpm/setup handles pnpm there), and every job still needs the task runner diff --git a/template/.github/actions/install_deps/action.yml.jinja-base b/template/.github/actions/install_deps/action.yml.jinja-base index 7529c662..bbf89560 100644 --- a/template/.github/actions/install_deps/action.yml.jinja-base +++ b/template/.github/actions/install_deps/action.yml.jinja-base @@ -21,6 +21,14 @@ inputs: required: false default: false description: Whether to explicitly skip installing the SSM Plugin manager when setting up basic CI tooling + install-pre-commit-tooling: + required: false + default: false + description: Whether to install the tooling the pre-commit hooks need (pre-commit, identify and prek), for jobs that run pre-commit + install-copier: + required: false + default: false + description: Whether to install copier, for jobs that instantiate a copier template project-dir: description: What's the relative path to the project? required: false @@ -95,7 +103,7 @@ runs: - name: Install tooling # the funky syntax is github action ternary # --no-node is always passed because the only node tooling this script installs is pnpm, which pnpm/setup above already installed - run: python .devcontainer/install-ci-tooling.py ${{ inputs.python-version == 'notUsing' && '--no-python' || '' }} --no-node ${{ inputs.skip-installing-ssm-plugin-manager == 'true' && '--skip-installing-ssm-plugin' || '' }} + run: python .devcontainer/install-ci-tooling.py ${{ inputs.python-version == 'notUsing' && '--no-python' || '' }} --no-node ${{ inputs.skip-installing-ssm-plugin-manager == 'true' && '--skip-installing-ssm-plugin' || '' }} ${{ inputs.install-pre-commit-tooling == 'true' && '--install-pre-commit-tooling' || '' }} ${{ inputs.install-copier == 'true' && '--install-copier' || '' }} shell: pwsh - name: OIDC Auth for CodeArtifact diff --git a/template/.github/workflows/ci.yaml.jinja-base b/template/.github/workflows/ci.yaml.jinja-base index b58e7357..a9c0b2f4 100644 --- a/template/.github/workflows/ci.yaml.jinja-base +++ b/template/.github/workflows/ci.yaml.jinja-base @@ -124,6 +124,8 @@ jobs: python-version: ${{ matrix.python-version }}{% endraw %}{% if template_uses_typescript is defined and template_uses_typescript is sameas(true) %}{% raw %} node-version: {% endraw %}{{ default_node_version }}{% raw %}{% endraw %}{% endif %}{% raw %} install-deps: false + install-copier: true + install-pre-commit-tooling: true - name: Instantiate copier template run: | diff --git a/template/.github/workflows/pre-commit.yaml.jinja-base b/template/.github/workflows/pre-commit.yaml.jinja-base index 3283cc7e..26e3450c 100644 --- a/template/.github/workflows/pre-commit.yaml.jinja-base +++ b/template/.github/workflows/pre-commit.yaml.jinja-base @@ -51,6 +51,7 @@ jobs: node-version: ${{ inputs.node-version }} skip-installing-ssm-plugin-manager: true skip-installing-pulumi-cli: true + install-pre-commit-tooling: true - name: Compute Pre-commit cache key # must run after checkout, since hashFiles needs the file on disk run: |