fix_62589 #84
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # WEKO3 リポジトリ(RCOSDP/weko)の .github/workflows/ に配置する。 | |
| # | |
| # 【重要】このリポジトリは public。Actions のログ・artifact・PR コメントは誰でも読める。 | |
| # したがって: | |
| # - 台帳(所見・実証結果を含む)とベースラインは **このリポジトリに置かない**。 | |
| # プライベートリポジトリ(RCOSDP/weko-secret)から Secret 経由で取得する。 | |
| # - 台帳は WEKO3 のブランチごとに内容が違う。既定ブランチを固定で見ると、ブランチ間の | |
| # 経路差がそのまま差分として出続けて形骸化する。PR の head → base → 既定 の順で | |
| # プライベートリポジトリの**同名ブランチ**を探して使う(Resolve inventory ref)。 | |
| # - 出力は --summary-only で **件数のみ**。URI や endpoint 名は出さない。 | |
| # 明細はプライベートリポジトリ側に置いたレポートで確認する。 | |
| # | |
| # 必要な Secret: | |
| # secrets.API_INVENTORY_REPO 取得元の private リポジトリ (RCOSDP/weko-secret) | |
| # secrets.API_INVENTORY_SSH_KEY weko-secret に登録した read-only deploy key の秘密鍵 | |
| # deploy key を使うのは、対象が1リポジトリに構造的に限定され、読み取り専用で、 | |
| # 個人アカウントに紐づかないため(PAT より事故時の影響が小さい)。 | |
| # 未設定なら、このジョブは何もせずスキップする(fork からの PR でも安全)。 | |
| # | |
| # 設置手順: tools/api-inventory/ci/README.md | |
| name: API Inventory Drift | |
| on: | |
| pull_request: | |
| branches: ['**'] | |
| workflow_dispatch: | |
| jobs: | |
| drift: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| # fork からの PR には Secret が渡らない。無駄に起動しない。 | |
| if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # changed_rows.py が base..head の diff を取るため | |
| - name: Check secrets | |
| id: cfg | |
| env: | |
| REPO: ${{ secrets.API_INVENTORY_REPO }} | |
| KEY: ${{ secrets.API_INVENTORY_SSH_KEY }} | |
| run: | | |
| if [ -n "$REPO" ] && [ -n "$KEY" ]; then | |
| echo "enabled=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "enabled=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::API_INVENTORY_REPO / API_INVENTORY_SSH_KEY が未設定のためスキップします" | |
| fi | |
| # 使う台帳ブランチを決める。存在しない ref を checkout に渡すと落ちるので、 | |
| # 先に ls-remote で候補を絞る。 | |
| # 1. PR の head ブランチ名 台帳更新 PR が**未マージでも**拾える(順序制約を作らない) | |
| # 2. PR の base ブランチ名 台帳を触らない PR、および両方マージ後の定常状態 | |
| # 3. 既定ブランチ 警告を出して続行(件数は当てにならない) | |
| - name: Resolve inventory ref | |
| id: ref | |
| if: steps.cfg.outputs.enabled == 'true' | |
| env: | |
| REPO: ${{ secrets.API_INVENTORY_REPO }} | |
| KEY: ${{ secrets.API_INVENTORY_SSH_KEY }} | |
| HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| BASE_REF: ${{ github.event.pull_request.base.ref || github.ref_name }} | |
| run: | | |
| set -eu | |
| d=$(mktemp -d); trap 'rm -rf "$d"' EXIT | |
| printf '%s\n' "$KEY" > "$d/key"; chmod 600 "$d/key" | |
| export GIT_SSH_COMMAND="ssh -i $d/key -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new" | |
| # 出るのはブランチ名だけ。鍵も台帳の中身も出ない。 | |
| # 認証に失敗したらここで落とす(黙って既定ブランチに落ちるのを防ぐ)。 | |
| heads=$(git ls-remote --heads "git@github.com:$REPO.git") | |
| have() { printf '%s\n' "$heads" | awk -v r="refs/heads/$1" '$2==r{f=1} END{exit !f}'; } | |
| pick='' | |
| if [ -n "${HEAD_REF:-}" ] && have "$HEAD_REF"; then | |
| pick="$HEAD_REF" | |
| elif [ -n "${BASE_REF:-}" ] && have "$BASE_REF"; then | |
| pick="$BASE_REF" | |
| fi | |
| if [ -n "$pick" ]; then | |
| echo "ref=$pick" >> "$GITHUB_OUTPUT" | |
| echo "fallback=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::台帳ブランチ: $pick" | |
| else | |
| echo "ref=" >> "$GITHUB_OUTPUT" | |
| echo "fallback=true" >> "$GITHUB_OUTPUT" | |
| echo "::warning::プライベートリポジトリに ${HEAD_REF:-} / ${BASE_REF:-} のいずれもありません。既定ブランチの台帳と比較します。ブランチ間の経路差がそのまま差分に出るため件数は当てになりません。同名ブランチを作ってください。" | |
| fi | |
| # 台帳・ベースラインをプライベートリポジトリから取得する。 | |
| # チェックアウト先は .api-inventory-data/(.gitignore 済み)。 | |
| # ref が空文字なら actions/checkout は既定ブランチを取る(上記フォールバック)。 | |
| - name: Checkout inventory data (private) | |
| if: steps.cfg.outputs.enabled == 'true' | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ secrets.API_INVENTORY_REPO }} | |
| ref: ${{ steps.ref.outputs.ref }} | |
| ssh-key: ${{ secrets.API_INVENTORY_SSH_KEY }} | |
| path: .api-inventory-data | |
| persist-credentials: false | |
| - uses: actions/setup-python@v5 | |
| if: steps.cfg.outputs.enabled == 'true' | |
| with: | |
| python-version: '3.11' | |
| - name: Start WEKO containers | |
| if: steps.cfg.outputs.enabled == 'true' | |
| run: | | |
| chmod +x install.sh | |
| ./install.sh | |
| env: | |
| DOCKER_BUILDKIT: 1 | |
| COMPOSE_DOCKER_CLI_BUILD: 1 | |
| - name: Wait for web container | |
| if: steps.cfg.outputs.enabled == 'true' | |
| run: | | |
| for i in $(seq 1 60); do | |
| if docker compose -f docker-compose2.yml exec -T web \ | |
| bash -lc 'source ~/.virtualenvs/invenio/bin/activate; invenio --help' >/dev/null 2>&1; then | |
| echo "ready"; exit 0 | |
| fi | |
| sleep 10 | |
| done | |
| docker compose -f docker-compose2.yml logs web | tail -100 | |
| exit 1 | |
| - name: Run drift checks | |
| if: steps.cfg.outputs.enabled == 'true' | |
| env: | |
| WEKO_API_INVENTORY_DIR: ${{ github.workspace }}/.api-inventory-data | |
| run: | | |
| set -o pipefail | |
| T=tools/api-inventory/scripts | |
| # 実機 url_map からスナップショットを作る(生成物は公開領域に置かない) | |
| python3 $T/snapshot.py --out /tmp/api_snapshot.new.json --profile default | |
| # 以降はすべて --summary-only。件数だけを標準出力に出す。 | |
| python3 $T/diff_snapshot.py \ | |
| "$WEKO_API_INVENTORY_DIR/api_snapshot.json" /tmp/api_snapshot.new.json \ | |
| --summary-only --gate --out /tmp/drift.md | |
| python3 $T/reconcile.py \ | |
| --snapshot /tmp/api_snapshot.new.json \ | |
| --summary-only --gate --out /tmp/reconcile.md | |
| - name: Probe changed endpoints | |
| if: always() && steps.cfg.outputs.enabled == 'true' | |
| env: | |
| WEKO_API_INVENTORY_DIR: ${{ github.workspace }}/.api-inventory-data | |
| run: | | |
| T=tools/api-inventory/scripts | |
| # 変更が触れた台帳行を割り出す(no のみを出力。URIは出さない) | |
| python3 $T/changed_rows.py \ | |
| "${{ github.event.pull_request.base.sha || github.event.before }}" "${{ github.sha }}" \ | |
| --out /tmp/rerun_nos.txt > /dev/null | |
| # install.sh はレコードを作らないので最小コーパスを投入してから測る | |
| python3 $T/fixtures.py --out /tmp/fixtures.json | |
| python3 $T/probe_ci.py \ | |
| --fixtures /tmp/fixtures.json --only /tmp/rerun_nos.txt \ | |
| --allow-writes --summary-only --gate --out /tmp/probe.json | |
| # artifact は件数のみのサマリに限定する(public なので誰でも取得できる)。 | |
| # drift.md / reconcile.md は --summary-only で生成済み。 | |
| # probe.json / api_snapshot.new.json は明細を含むため **上げない**。 | |
| - name: Upload summary (counts only) | |
| if: always() && steps.cfg.outputs.enabled == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: api-inventory-summary | |
| path: | | |
| /tmp/drift.md | |
| /tmp/reconcile.md | |
| - name: Comment on PR (counts only) | |
| if: always() && steps.cfg.outputs.enabled == 'true' && github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| env: | |
| INVENTORY_REF: ${{ steps.ref.outputs.ref }} | |
| INVENTORY_FALLBACK: ${{ steps.ref.outputs.fallback }} | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const read = (p, title) => { | |
| try { return `\n\n### ${title}\n\n` + fs.readFileSync(p, 'utf8'); } | |
| catch (e) { return `\n\n### ${title}\n\n(生成されませんでした)`; } | |
| }; | |
| // どの台帳と比べた件数なのかが分からないと、レビュアは数字を判断できない。 | |
| const ref = process.env.INVENTORY_REF; | |
| const fallback = process.env.INVENTORY_FALLBACK; | |
| let body = '## API インベントリ差分(件数のみ)\n\n'; | |
| if (fallback === 'true') { | |
| body += '> ⚠️ **プライベートリポジトリに対応ブランチが無いため、既定ブランチの台帳と比較しています。**\n' | |
| + '> ブランチ間の経路差がそのまま差分として出るので、以下の件数は当てになりません。\n' | |
| + '> この PR のブランチと同名のブランチをプライベートリポジトリに作ってください。\n\n'; | |
| } else if (ref) { | |
| body += `> 台帳ブランチ: \`${ref}\`\n\n`; | |
| } else { | |
| body += '> ⚠️ 台帳ブランチを解決できませんでした(Resolve inventory ref が失敗しています)。\n\n'; | |
| } | |
| body += '> 明細は公開できないため件数のみ表示しています。' | |
| + '該当箇所はプライベートリポジトリ側の台帳・レポートで確認してください。'; | |
| body += read('/tmp/drift.md', 'ベースラインとの差分'); | |
| body += read('/tmp/reconcile.md', '台帳との突き合わせ'); | |
| await github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: body.slice(0, 60000), | |
| }); | |
| - name: Teardown | |
| if: always() && steps.cfg.outputs.enabled == 'true' | |
| run: docker compose -f docker-compose2.yml down -v |