はじめに
AIを使った開発をしていると GitHubリポジトリが増えがちです。開発が止まった GitHubリポジトリを放置していると、GitHub Actions の定期実行が残り続けることがあります。
典型例は次のような workflow です。
Security AuditSecurity ScanningDependency Security CheckDocker Security ScanMonitoringBenchmark
これらは開発中は有用ですが、開発停止後は依存関係、Secrets、外部サービス、Docker image、クラウド権限などが古くなり、毎日失敗通知を出すだけのノイズになることがあります。
この記事では、GitHub Actions の基礎から、定期実行の確認、停止、停止確認までを整理します。
この記事で分かること
- GitHub では何が自動実行されるのか
- GitHub Actions の workflow / event / job / step / runner の関係
-
scheduleによる定期実行の仕組み -
ghコマンドで scheduled workflow を確認する方法 - workflow を停止する方法
-
scheduleだけを削除する方法 - run 履歴ベースの確認で見落とすケース
- 開発停止リポジトリの棚卸し用スクリプト
前提
この記事では GitHub CLI を使います。
gh --version
gh auth status
認証していない場合は以下でログインします。
gh auth login
以降の例では、リポジトリ名は OWNER/REPO の形式で表記します。
OWNER/REPO
例: octocat/example
1. GitHub の自動実行の中心は GitHub Actions
GitHub Actions は、GitHub 上のイベントを契機に処理を自動実行する仕組みです。
主な用途は以下です。
| 分類 | 例 |
|---|---|
| CI | push / Pull Request ごとの lint、test、build |
| CD | main merge 後の staging / production deploy |
| セキュリティ | CodeQL、依存関係監査、Docker image scan |
| 品質管理 | coverage、静的解析、型チェック |
| 運用 | 定期 health check、監視、レポート生成 |
| リポジトリ管理 | Issue ラベル付け、古い Issue の close |
| 外部連携 | 外部サービスから API 経由で workflow 起動 |
| 再利用 | 共通 workflow を複数 repo から呼び出す |
GitHub Actions の設定ファイルは、通常リポジトリ内の以下に置きます。
.github/workflows/*.yml
.github/workflows/*.yaml
1 つのリポジトリに複数の workflow を置けます。
2. GitHub Actions の基本構造
GitHub Actions は、次の構造で理解すると分かりやすいです。
event
↓
workflow
↓
workflow run
↓
job
↓
step
↓
action または shell command
用語を整理します。
| 用語 | 意味 |
|---|---|
| workflow | 自動化処理の定義。.github/workflows/*.yml に書く |
| event / trigger | workflow を起動する契機 |
| workflow run | workflow が 1 回実行された履歴 |
| job | workflow 内の実行単位 |
| step | job 内の処理単位 |
| action | 再利用可能な処理部品 |
| runner | job を実行する環境 |
| artifact | 実行結果として保存するファイル |
| secret / variable | workflow に渡す機密情報・設定値 |
最小構成の例です。
name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Run tests
run: |
npm ci
npm test
この workflow は以下で起動します。
-
mainbranch への push - Pull Request
- 手動実行
3. workflow を起動する event
GitHub Actions の on: に指定するものが event です。
代表的なものは以下です。
| event | いつ動くか | 用途 |
|---|---|---|
push |
commit が push されたとき | 通常の CI |
pull_request |
PR 作成・更新時 | PR 検証 |
release |
release 作成・公開時 | package publish / deploy |
schedule |
cron による定期実行 | 定期 scan / 定期監視 |
workflow_dispatch |
手動実行 | 任意タイミングの実行 |
repository_dispatch |
GitHub API 経由の外部 trigger | 外部システム連携 |
workflow_run |
他 workflow の実行後 | workflow chaining |
workflow_call |
他 workflow から呼び出し | reusable workflow |
この記事で問題にしているのは schedule です。
4. schedule による定期実行
schedule は cron 形式で workflow を定期実行します。
例:
name: Security Audit
on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm audit
cron の形式は次の 5 フィールドです。
┌───────────── minute: 0-59
│ ┌───────────── hour: 0-23
│ │ ┌───────────── day of month: 1-31
│ │ │ ┌───────────── month: 1-12
│ │ │ │ ┌───────────── day of week: 0-6
│ │ │ │ │
0 0 * * *
0 0 * * * は毎日 0:00 の意味です。
GitHub Actions の scheduled workflow では、デフォルトの時刻は UTC です。現在の GitHub Actions では、必要に応じて timezone も指定できます。
on:
schedule:
- cron: "30 5 * * 1-5"
timezone: "Asia/Tokyo"
なお、scheduled workflow は default branch 上の workflow file を対象に動作します。
5. 開発停止リポジトリで scheduled workflow が問題になる理由
開発が止まったリポジトリでは、次の理由で scheduled workflow が失敗しやすくなります。
- 依存パッケージが古くなる
- lock file が現行 registry と合わなくなる
- Docker image が消える、または脆弱性検出で落ちる
- GitHub Secrets が失効する
- 外部 API token が失効する
- クラウド側の権限やリソースが消える
- テスト前提のサービスが動いていない
- セキュリティ scanner の仕様が変わる
- ベンチマークや監視対象がなくなる
この状態で schedule が残っていると、毎日または毎週、同じ失敗通知が発生します。
運用上の判断として、開発停止リポジトリでは次のどちらかを選ぶことになります。
| 方針 | 内容 |
|---|---|
| workflow 全体を止める |
gh workflow disable で停止 |
| 定期実行だけ止める | YAML から on.schedule を削除 |
6. まず run 履歴を見る
過去に schedule で動いていたかを確認します。
gh run list -R OWNER/REPO --event schedule --limit 20
例:
gh run list -R octocat/example --event schedule --limit 20
出力例:
STATUS TITLE WORKFLOW BRANCH EVENT ID ELAPSED AGE
X Security Scanning Security Scanning main schedule 12345678901 53s about 4 hours ago
X Security Scanning Security Scanning main schedule 12345678902 58s about 1 day ago
X Security Scanning Security Scanning main schedule 12345678903 53s about 2 days ago
EVENT が schedule なら、定期実行で起動した run です。
複数リポジトリを見る場合:
repos=(
"OWNER/REPO1"
"OWNER/REPO2"
"OWNER/REPO3"
)
for repo in "${repos[@]}"; do
echo "== $repo =="
gh run list -R "$repo" --event schedule --limit 20
done
7. run 履歴から workflow ID を取得する
停止するときは workflow 名より workflow ID を使う方が安全です。
理由は、同じ名前の workflow が複数存在することがあるためです。
gh run list \
-R OWNER/REPO \
--event schedule \
--limit 100 \
--json workflowDatabaseId,workflowName \
--jq '.[] | select(.workflowDatabaseId != null) | [.workflowDatabaseId, .workflowName] | @tsv' \
| sort -u
出力例:
165629470 Test Suite
165641572 Security Audit
169535038 Security Audit
171484537 Optimized CI/CD Pipeline
ここで Security Audit が 2 件あります。名前ではなく ID で止めるべき理由が分かります。
8. run 履歴だけでは不十分
ここが重要です。
gh run list --event schedule は、あくまで「過去に実行された run の履歴」を見ています。
次のような workflow は見落とす可能性があります。
- YAML に
schedule:はあるが、まだ実行履歴がない - 最近は失敗していないが、将来実行される scheduled workflow
- run 履歴の取得件数に入らなかった workflow
- 一度も完走していない、または別の理由で履歴確認から漏れた workflow
したがって、正確には active workflow の YAML を確認して schedule: が残っていないかを見る 必要があります。
9. active な scheduled workflow を検出する
以下は、複数リポジトリに対して active workflow の YAML を確認し、schedule: が残っているものを出力するスクリプトです。
repos=(
"OWNER/REPO1"
"OWNER/REPO2"
"OWNER/REPO3"
)
for repo in "${repos[@]}"; do
echo "== $repo =="
gh workflow list -R "$repo" --all --limit 1000 --json id,name,path,state \
--jq '.[] | select(.state == "active") | [.id, .name, .path] | @tsv' |
while IFS=$'\t' read -r id name path; do
yaml="$(gh workflow view "$id" -R "$repo" --yaml 2>/dev/null || true)"
yaml_without_comments="$(printf '%s\n' "$yaml" | sed 's/[[:space:]]*#.*$//')"
if printf '%s\n' "$yaml_without_comments" | grep -Eq '(^|[[:space:]{,])schedule[[:space:]]*:'; then
printf 'ACTIVE schedule remains: repo=%s id=%s path=%s name=%s\n' \
"$repo" "$id" "$path" "$name"
fi
done
done
出力例:
== OWNER/REPO1 ==
ACTIVE schedule remains: repo=OWNER/REPO1 id=171172891 path=.github/workflows/enhanced-security-scanning.yml name=.github/workflows/enhanced-security-scanning.yml
ACTIVE schedule remains: repo=OWNER/REPO1 id=171233734 path=.github/workflows/monitoring-observability.yml name=.github/workflows/monitoring-observability.yml
== OWNER/REPO2 ==
ACTIVE schedule remains: が出たものは、まだ active 状態で定期実行が残っています。
注意点として、この検出は実務向けの簡易検出です。YAML を厳密に parse したい場合は yq などを使ってください。ただし、通常の GitHub Actions workflow 棚卸しではこの程度でも十分に役立ちます。
10. workflow を停止する
workflow ID が分かっている場合は、次で止めます。
gh workflow disable WORKFLOW_ID -R OWNER/REPO
例:
gh workflow disable 171172891 -R OWNER/REPO
gh workflow disable 171233734 -R OWNER/REPO
停止後、--all を付けて確認します。
gh workflow list -R OWNER/REPO --all
期待する状態:
NAME STATE ID
.github/workflows/enhanced-security-scanning.yml disabled_manually 171172891
.github/workflows/monitoring-observability.yml disabled_manually 171233734
disabled_manually になっていれば手動停止済みです。
11. workflow disable の注意点
gh workflow disable は、schedule だけを止めるコマンドではありません。
workflow 全体を止めます。
たとえば次の workflow があるとします。
on:
push:
pull_request:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
この workflow を gh workflow disable すると、以下すべてが止まります。
pushpull_requestscheduleworkflow_dispatch
開発停止リポジトリなら問題になりにくいですが、まだ保守しているリポジトリでは注意が必要です。
12. 定期実行だけ止める場合
CI は残したいが、定期実行だけ止めたい場合は YAML を編集します。
変更前:
on:
push:
branches: [main]
pull_request:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
変更後:
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
完全に手動実行だけ残すなら:
on:
workflow_dispatch:
この方法なら、workflow 自体は active のままですが、cron による定期実行は止まります。
13. 複数リポジトリの scheduled workflow を一括停止する
開発停止リポジトリ群で、active な scheduled workflow をまとめて止めたい場合のスクリプトです。
まずは dry-run で確認します。
#!/usr/bin/env bash
set -euo pipefail
repos=(
"OWNER/REPO1"
"OWNER/REPO2"
"OWNER/REPO3"
)
apply="${APPLY:-0}"
for repo in "${repos[@]}"; do
echo "== $repo =="
gh workflow list -R "$repo" --all --limit 1000 --json id,name,path,state \
--jq '.[] | select(.state == "active") | [.id, .name, .path] | @tsv' |
while IFS=$'\t' read -r id name path; do
yaml="$(gh workflow view "$id" -R "$repo" --yaml 2>/dev/null || true)"
yaml_without_comments="$(printf '%s\n' "$yaml" | sed 's/[[:space:]]*#.*$//')"
if printf '%s\n' "$yaml_without_comments" | grep -Eq '(^|[[:space:]{,])schedule[[:space:]]*:'; then
if [[ "$apply" == "1" ]]; then
echo "disable: $repo / $id / $path / $name"
gh workflow disable "$id" -R "$repo"
else
echo "would disable: $repo / $id / $path / $name"
fi
fi
done
done
dry-run:
bash disable-scheduled-workflows.sh
実行:
APPLY=1 bash disable-scheduled-workflows.sh
14. 停止確認
一括停止後、再度 active workflow に schedule: が残っていないか確認します。
repos=(
"OWNER/REPO1"
"OWNER/REPO2"
"OWNER/REPO3"
)
for repo in "${repos[@]}"; do
echo "== $repo =="
gh workflow list -R "$repo" --all --limit 1000 --json id,name,path,state \
--jq '.[] | select(.state == "active") | [.id, .name, .path] | @tsv' |
while IFS=$'\t' read -r id name path; do
yaml="$(gh workflow view "$id" -R "$repo" --yaml 2>/dev/null || true)"
yaml_without_comments="$(printf '%s\n' "$yaml" | sed 's/[[:space:]]*#.*$//')"
if printf '%s\n' "$yaml_without_comments" | grep -Eq '(^|[[:space:]{,])schedule[[:space:]]*:'; then
printf 'ACTIVE schedule remains: repo=%s id=%s path=%s name=%s\n' \
"$repo" "$id" "$path" "$name"
fi
done
done
何も出なければ、active 状態の scheduled workflow は残っていません。
出力例:
== OWNER/REPO1 ==
== OWNER/REPO2 ==
== OWNER/REPO3 ==
これは正常です。
15. 翌日確認
gh workflow disable をしても、過去の run 履歴は残ります。
そのため、次のような表示が残っていても異常ではありません。
X Security Audit Security Audit main schedule 12345678901 1m33s about 1 day ago
見るべきなのは、停止後の時刻より新しい schedule run が増えていないかです。
for repo in "${repos[@]}"; do
echo "== $repo =="
gh run list \
-R "$repo" \
--event schedule \
--limit 10 \
--json createdAt,status,conclusion,workflowName,databaseId,url \
--jq '.[] | [.createdAt, .status, .conclusion, .workflowName, .databaseId, .url] | @tsv'
done
停止後より新しい createdAt の run がなければ、定期実行は止まっています。
16. UI から止める方法
GitHub の Web UI でも停止できます。
Repository
→ Actions
→ 左側の workflow を選択
→ 右上の「...」
→ Disable workflow
少数の workflow だけ止めるなら UI でも十分です。
複数リポジトリを棚卸しする場合は、gh コマンドの方が現実的です。
17. GitHub Actions 以外の自動化:Dependabot
GitHub の自動化は Actions だけではありません。
代表例が Dependabot です。
Dependabot は依存パッケージや GitHub Actions の参照 version を確認し、更新 Pull Request を作成します。
設定ファイルは通常これです。
.github/dependabot.yml
例:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
開発停止リポジトリで Dependabot PR も不要なら、次の対応を検討します。
-
.github/dependabot.ymlを削除する - 対象 ecosystem を削除する
-
open-pull-requests-limit: 0を設定する - GitHub の repository settings 側で Dependabot 設定を見直す
Actions の schedule と Dependabot の schedule は別物です。混同しないでください。
18. 使うコマンドの整理
| 目的 | コマンド |
|---|---|
| schedule run の履歴を見る | gh run list -R OWNER/REPO --event schedule |
| workflow 一覧を見る | gh workflow list -R OWNER/REPO |
| disabled workflow も含めて見る | gh workflow list -R OWNER/REPO --all |
| workflow YAML を見る | gh workflow view WORKFLOW_ID -R OWNER/REPO --yaml |
| workflow を止める | gh workflow disable WORKFLOW_ID -R OWNER/REPO |
| workflow を再開する | gh workflow enable WORKFLOW_ID -R OWNER/REPO |
| workflow を手動実行する | gh workflow run WORKFLOW_ID -R OWNER/REPO |
19. 判断基準
開発停止リポジトリでは、原則として次の判断でよいです。
| 状況 | 推奨対応 |
|---|---|
| 完全に開発停止 | scheduled workflow を disable |
| CI も不要 | workflow 全体を disable |
| push / PR の CI は残したい | YAML から schedule だけ削除 |
| 手動実行だけ残したい |
workflow_dispatch だけ残す |
| Dependabot PR も不要 |
dependabot.yml を削除または制限 |
| 外部サービスを叩いている | 早めに disable |
| 課金 API / cloud を使っている | 最優先で disable |
20. よくある落とし穴
run 履歴と workflow 定義を混同する
gh run list は過去の実行履歴です。
.github/workflows/*.yml は今後の実行定義です。
履歴が残っているからといって、今も動いているとは限りません。逆に、履歴に出ていなくても YAML に schedule: が残っていれば、将来動く可能性があります。
gh workflow disable は schedule だけを止めるわけではない
workflow 全体が止まります。
CI を残したい場合は YAML を編集します。
workflow 名は重複する
Security Audit のような名前は複数存在できます。
停止は ID でやる方が安全です。
disabled workflow は普通の list では見えない
確認時は --all を付けます。
gh workflow list -R OWNER/REPO --all
Dependabot は GitHub Actions とは別
以下は別系統です。
.github/workflows/*.yml → GitHub Actions
.github/dependabot.yml → Dependabot
21. まとめ
開発停止リポジトリで GitHub Actions の定期実行が失敗し続けている場合、見るべきポイントは次の順番です。
1. gh run list --event schedule で過去の schedule run を確認
2. workflowDatabaseId を取得
3. gh workflow disable WORKFLOW_ID で停止
4. gh workflow list --all で disabled_manually を確認
5. active workflow の YAML を見て schedule が残っていないか確認
6. 翌日、停止後の新しい schedule run が増えていないか確認
特に重要なのは、run 履歴だけで判断しないことです。
最終確認では、active な workflow の YAML に schedule: が残っていないことを確認するのが確実です。
参考
- Understanding GitHub Actions - GitHub Docs
- Workflow syntax for GitHub Actions - GitHub Docs
- Events that trigger workflows - GitHub Docs
- Disabling and enabling a workflow - GitHub Docs
- gh run list - GitHub CLI Manual
- gh workflow list - GitHub CLI Manual
- gh workflow view - GitHub CLI Manual
- gh workflow disable - GitHub CLI Manual
- About Dependabot version updates - GitHub Docs
- Configuring Dependabot version updates - GitHub Docs