diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 0e00d99..64a2b39 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -101,6 +101,9 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + # gh extension install의 비인증 API rate limit 회피용 (이미지 레이어에는 남지 않음) + secrets: | + gh_token=${{ secrets.GITHUB_TOKEN }} # Sign the resulting Docker image digest except on PRs. # This will only write to the public Rekor transparency log when the Docker diff --git a/CLAUDE.md b/CLAUDE.md index e7558db..9a1172d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,6 +12,7 @@ This is a Docker base image for Coder workspaces, built on top of `codercom/ente - Docker with coder user in docker group - Homebrew package manager - Graphite CLI for stacked PRs +- GitHub CLI extensions: `gh stack` (github/gh-stack) and `gh actions-lock` (github/gh-actions-lock) - AWS CLI, Google Cloud CLI, and Qodana CLI - Orca headless server (`orca-server` wrapper; launch via Coder template startup script) - Custom Nerd Fonts for terminal display @@ -52,7 +53,7 @@ The repository uses a two-phase Docker build with clear separation between root **Build Phases:** - **Phase 1 (Root)**: System packages, CLI tools (gh, gcloud), fonts, Docker, root-level tools -- **Phase 2 (Coder User)**: Development SDKs, Zimfw modules + Powerlevel10k prompt, Homebrew, Graphite CLI +- **Phase 2 (Coder User)**: Development SDKs, Zimfw modules + Powerlevel10k prompt, Homebrew, Graphite CLI, GitHub CLI extensions **For detailed build phases, script organization, and configuration files, see [images/CLAUDE.md](images/CLAUDE.md)** diff --git a/README.md b/README.md index 2150397..f2f903d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ A comprehensive Docker base image for [Coder](https://coder.com/) workspaces, bu - **Docker**: Containerization with coder user in docker group - **Homebrew**: Package manager for Linux - **Graphite CLI**: Stacked pull request workflow +- **GitHub CLI extensions**: `gh stack` (native stacked PRs) and `gh actions-lock` (lock and verify GitHub Actions dependencies) - **GitHub CLI (gh)**: GitHub operations from terminal - **AWS CLI**: Amazon Web Services command line interface - **Qodana CLI**: JetBrains code quality platform @@ -105,6 +106,7 @@ All installation scripts are located in the `scripts/` directory: | `install-prompt.sh` | Zimfw modules (`.zimrc`), Powerlevel10k prompt, Orca history | coder | | `install-brew.sh` | Homebrew package manager | coder | | `install-graphite.sh` | Graphite CLI | coder | +| `install-gh-extensions.sh` | GitHub CLI extensions (gh-stack, gh-actions-lock) | coder | ## Customization diff --git a/images/CLAUDE.md b/images/CLAUDE.md index b53ca75..1e21a38 100644 --- a/images/CLAUDE.md +++ b/images/CLAUDE.md @@ -20,7 +20,8 @@ images/ ├── install-sdk.sh # 사용자 개발 도구 (mise 글로벌 런타임, Claude Code) ├── install-prompt.sh # Zimfw 모듈 + Powerlevel10k 프롬프트 ├── install-brew.sh # Homebrew 패키지 매니저 - └── install-graphite.sh # Graphite CLI (스택 PR) + ├── install-graphite.sh # Graphite CLI (스택 PR) + └── install-gh-extensions.sh # GitHub CLI 확장 (gh-stack, gh-actions-lock) ``` ## base/ 이미지 @@ -53,6 +54,7 @@ images/ **기타:** - Homebrew 패키지 매니저 - Graphite CLI (스택 PR 관리) +- GitHub CLI 확장: `gh stack`(GitHub 네이티브 stacked PR), `gh actions-lock`(Actions 의존성 lock·검증) - 커스텀 Nerd Fonts (MesloLGS NF, JetBrainsMono, D2Coding) - Qodana CLI @@ -238,6 +240,17 @@ Graphite CLI 설치: - 스택 PR 관리 도구 - **중요**: mise가 관리하는 node(`install-sdk.sh`)가 먼저 설치되어야 함 (shims로 npm 사용) +#### install-gh-extensions.sh (Coder User) + +GitHub CLI 확장 설치: +- `gh extension install github/gh-stack`, `gh extension install github/gh-actions-lock` +- 설치 위치: `~/.local/share/gh/extensions/` +- 공개 저장소라 인증 없이 설치되지만, 비인증 API rate limit(IP당 시간당 60회)을 피하려고 + CI는 `GITHUB_TOKEN`을 BuildKit secret(`gh_token`)으로 넘긴다. secret은 해당 `RUN`에만 + 마운트되고 이미지 레이어에는 남지 않는다. 로컬 빌드에서는 생략해도 된다 + (`docker build --secret id=gh_token,env=GH_TOKEN ...`로 넘길 수도 있다) +- `gh extension list`는 인증이 필요하므로 설치 확인은 각 확장을 직접 실행해서 한다 + ## 중요 사항 ### 실행 순서 @@ -259,7 +272,8 @@ Graphite CLI 설치: 1. SDK (`install-sdk.sh`) - mise 글로벌 런타임(node/bun/deno/java), npm 전역 패키지, Claude Code 2. 프롬프트 (`install-prompt.sh`) - Zimfw 설치 이후 3. Graphite (`install-graphite.sh`) - mise node(npm) 필요 -4. Homebrew +4. GitHub CLI 확장 (`install-gh-extensions.sh`) - root 단계의 GitHub CLI 필요 +5. Homebrew ### 사용자 컨텍스트 diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 258fee1..810fbbf 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -137,6 +137,14 @@ RUN chmod +x /tmp/install-graphite.sh && \ /bin/bash /tmp/install-graphite.sh && \ rm /tmp/install-graphite.sh +# GitHub CLI 확장 설치 (gh-stack, gh-actions-lock) +# gh_token secret은 선택 사항 — 없으면 비인증으로 설치한다 +COPY --chown=coder:coder scripts/install-gh-extensions.sh /tmp/install-gh-extensions.sh +RUN --mount=type=secret,id=gh_token,mode=0444 \ + chmod +x /tmp/install-gh-extensions.sh && \ + /bin/bash /tmp/install-gh-extensions.sh && \ + rm /tmp/install-gh-extensions.sh + # Homebrew 설치 RUN /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" diff --git a/images/base/scripts/install-gh-extensions.sh b/images/base/scripts/install-gh-extensions.sh new file mode 100755 index 0000000..a01f0a1 --- /dev/null +++ b/images/base/scripts/install-gh-extensions.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -e + +echo "🧩 Installing GitHub CLI extensions..." + +# gh는 root 단계의 apt 설치에 의존한다 — 없으면 원인을 바로 알리고 중단한다 +if ! command -v gh &> /dev/null; then + echo "❌ GitHub CLI (gh) not found; the root-phase GitHub CLI install must run first" >&2 + exit 1 +fi + +# 공개 저장소의 확장은 인증 없이 설치되지만, 비인증 API는 IP당 시간당 60회로 제한된다. +# CI는 BuildKit secret(gh_token)으로 토큰을 넘겨 공유 러너 IP의 rate limit을 피한다. +if [ -s /run/secrets/gh_token ]; then + GH_TOKEN="$(cat /run/secrets/gh_token)" + export GH_TOKEN +fi + +# gh-stack: GitHub 네이티브 stacked PR / gh-actions-lock: Actions 의존성 lock·검증 +gh extension install github/gh-stack || { echo "❌ Failed to install github/gh-stack" >&2; exit 1; } +gh extension install github/gh-actions-lock || { echo "❌ Failed to install github/gh-actions-lock" >&2; exit 1; } + +# 설치 확인 (`gh extension list`는 인증이 필요하므로 각 확장을 직접 실행한다) +if gh stack --version &> /dev/null && gh actions-lock --help &> /dev/null; then + echo "✅ GitHub CLI extensions installation completed!" + gh stack --version +else + echo "❌ GitHub CLI extensions verification failed!" >&2 + exit 1 +fi