name: Update Versions and Release Helm Chart # 毎週月曜 3:00 AM JST(日曜 18:00 UTC)に実行。 # - 主アプリ = Claude Code CLI(npm: @anthropic-ai/claude-code)の最新版を確認 # - base image = gateway(nginx) / manager(python) の最新 Alpine タグを確認 # - 主アプリが更新: values.yaml / Chart.yaml / README 履歴を更新しコミット → タグ + Gitea リリース + チャート publish # - base image のみ更新: values.yaml を更新してコミットのみ(リリースなし) # # セッションイメージのビルドは session-image.yaml が担当する(このワークフローが # Chart.yaml を push した結果として発火する)。 on: schedule: - cron: '0 18 * * 0' workflow_dispatch: env: REGISTRY_URL: https://git.cafepieters.com OWNER: helmchart jobs: update-and-release: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 - name: Install Helm uses: azure/setup-helm@v3 with: version: 'v3.16.4' - name: Ensure jq run: command -v jq >/dev/null 2>&1 || (sudo apt-get update -qq && sudo apt-get install -y -qq jq) - name: Check Claude Code (npm) version id: cc run: | set -e CURRENT=$(grep '^appVersion:' Chart.yaml | sed 's/.*"\(.*\)".*/\1/') LATEST=$(curl -s --retry 3 --retry-delay 5 \ "https://registry.npmjs.org/@anthropic-ai/claude-code/latest" | jq -r '.version // empty') echo "Current: $CURRENT / npm latest: ${LATEST:-not found}" if [ -n "$LATEST" ]; then HIGHER=$(printf '%s\n%s' "$CURRENT" "$LATEST" | sort -V | tail -1) if [ "$HIGHER" != "$LATEST" ] && [ "$CURRENT" != "$LATEST" ]; then echo "Warning: npm latest ($LATEST) < current ($CURRENT). Skipping." LATEST="$CURRENT" fi else LATEST="$CURRENT" fi echo "current=$CURRENT" >> $GITHUB_OUTPUT echo "latest=$LATEST" >> $GITHUB_OUTPUT - name: Check base image (nginx / python) tags id: base run: | set -e NGINX_CUR=$(grep -A3 'gateway:' values.yaml | grep 'tag:' | head -1 | sed 's/.*"\(.*\)".*/\1/') PY_CUR=$(grep -A3 'manager:' values.yaml | grep 'tag:' | head -1 | sed 's/.*"\(.*\)".*/\1/') NGINX_LATEST=$(curl -s --retry 3 "https://registry.hub.docker.com/v2/repositories/nginxinc/nginx-unprivileged/tags?page_size=100" \ | jq -r '.results[].name' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+-alpine$' | sort -V | tail -1) PY_LATEST=$(curl -s --retry 3 "https://registry.hub.docker.com/v2/repositories/library/python/tags?page_size=100&name=alpine" \ | jq -r '.results[].name' | grep -E '^3\.[0-9]+-alpine$' | sort -V | tail -1) [ -n "$NGINX_LATEST" ] || NGINX_LATEST="$NGINX_CUR" [ -n "$PY_LATEST" ] || PY_LATEST="$PY_CUR" echo "nginx: $NGINX_CUR -> $NGINX_LATEST ; python: $PY_CUR -> $PY_LATEST" echo "nginx_cur=$NGINX_CUR" >> $GITHUB_OUTPUT echo "nginx_latest=$NGINX_LATEST" >> $GITHUB_OUTPUT echo "py_cur=$PY_CUR" >> $GITHUB_OUTPUT echo "py_latest=$PY_LATEST" >> $GITHUB_OUTPUT - name: Decide id: decide run: | set -e CC=false; BASE=false [ "${{ steps.cc.outputs.current }}" != "${{ steps.cc.outputs.latest }}" ] && CC=true [ "${{ steps.base.outputs.nginx_cur }}" != "${{ steps.base.outputs.nginx_latest }}" ] && BASE=true [ "${{ steps.base.outputs.py_cur }}" != "${{ steps.base.outputs.py_latest }}" ] && BASE=true echo "cc=$CC" >> $GITHUB_OUTPUT echo "base=$BASE" >> $GITHUB_OUTPUT echo "update_needed=$([ "$CC" = true ] || [ "$BASE" = true ] && echo true || echo false)" >> $GITHUB_OUTPUT - name: Update values.yaml (image tags) if: steps.decide.outputs.update_needed == 'true' run: | set -e sed -i "s|tag: \"${{ steps.base.outputs.nginx_cur }}\"|tag: \"${{ steps.base.outputs.nginx_latest }}\"|g" values.yaml sed -i "s|tag: \"${{ steps.base.outputs.py_cur }}\"|tag: \"${{ steps.base.outputs.py_latest }}\"|g" values.yaml if [ "${{ steps.decide.outputs.cc }}" = "true" ]; then sed -i "s|tag: \"${{ steps.cc.outputs.current }}\"|tag: \"${{ steps.cc.outputs.latest }}\"|g" values.yaml fi git diff --stat values.yaml || true - name: Update Chart.yaml (version == Claude Code version) if: steps.decide.outputs.cc == 'true' run: | set -e NEW="${{ steps.cc.outputs.latest }}" sed -i "s/^version: .*/version: ${NEW}/" Chart.yaml sed -i "s/^appVersion: .*/appVersion: \"${NEW}\"/" Chart.yaml cat Chart.yaml - name: Update README version history if: steps.decide.outputs.cc == 'true' run: | set -e NEW="${{ steps.cc.outputs.latest }}" sed -i "/^| バージョン | Claude Code | 変更内容 |/{ n a\| ${NEW} | ${NEW} | 自動更新 | }" README.md - name: Lint if: steps.decide.outputs.update_needed == 'true' run: helm lint . - name: Commit if: steps.decide.outputs.update_needed == 'true' run: | set -e git config user.name "Claude" git config user.email "claude@cafepieters.com" if [ "${{ steps.decide.outputs.cc }}" = "true" ]; then git add values.yaml Chart.yaml README.md git commit -m "chore: update Claude Code to ${{ steps.cc.outputs.latest }} (nginx ${{ steps.base.outputs.nginx_latest }}, python ${{ steps.base.outputs.py_latest }})" else git add values.yaml git commit -m "chore: bump base images — nginx ${{ steps.base.outputs.nginx_latest }}, python ${{ steps.base.outputs.py_latest }} (no release)" fi git push origin "${GITHUB_REF_NAME:-main}" - name: Package if: steps.decide.outputs.cc == 'true' run: | set -e helm package . echo "CHART_FILE=$(ls claude-code-*.tgz)" >> $GITHUB_ENV - name: Git tag if: steps.decide.outputs.cc == 'true' run: | set -e V="v${{ steps.cc.outputs.latest }}" git rev-parse "$V" >/dev/null 2>&1 && { echo "tag $V exists"; exit 0; } git tag -a "$V" -m "Release $V" git push origin "$V" - name: Gitea Release if: steps.decide.outputs.cc == 'true' env: GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} run: | set -e NEW="${{ steps.cc.outputs.latest }}"; V="v${NEW}" if curl -s -H "Authorization: token ${GITEA_TOKEN}" "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${V}" | jq -e '.id' >/dev/null 2>&1; then echo "release ${V} exists, skip" else RID=$(curl -s -X POST -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" \ -d "{\"tag_name\":\"${V}\",\"name\":\"${V}\",\"body\":\"claude-code Helm Chart ${V} — Claude Code CLI ${NEW}\"}" \ "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases" | jq -r '.id') curl --fail-with-body -X POST -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/gzip" \ --data-binary "@${CHART_FILE}" \ "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/${RID}/assets?name=${CHART_FILE}" fi - name: Publish chart to Gitea Package Registry if: steps.decide.outputs.cc == 'true' run: | set -e curl --fail-with-body -u "${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_TOKEN }}" \ -X POST --upload-file "${CHART_FILE}" \ "${REGISTRY_URL}/api/packages/${OWNER}/helm/api/charts" - name: Summary if: always() run: | echo "Claude Code : ${{ steps.cc.outputs.current }} -> ${{ steps.cc.outputs.latest }} (updated: ${{ steps.decide.outputs.cc }})" echo "nginx : ${{ steps.base.outputs.nginx_cur }} -> ${{ steps.base.outputs.nginx_latest }}" echo "python : ${{ steps.base.outputs.py_cur }} -> ${{ steps.base.outputs.py_latest }}" echo "release : ${{ steps.decide.outputs.cc }}"