0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

初めてのCI/CD。チェックが失敗したままマージしても、公開は止められた(GitHub Actions)

0
Last updated at Posted at 2026-11-04

1. はじめに

前回の記事では、GitHubにpushすると、GitHub ActionsがCloudflare Workersへ自動で公開するしくみを作りました。

ただ、このしくみには弱点があります。mainにpushすると、中身に間違いがあっても、そのまま公開されてしまいます。

今回の検証は小さな静的ページなので、それでも大きな問題にはなりません。でも、仕事で扱う大きな動的ページでは、そうはいきません。公開する前に、自動で確かめるしくみが必要だと思いました。

そこで今回は、公開の前にHTMLをチェックして、間違いがあれば公開しないようにしました。さらに、わざとHTMLを壊して、本当に公開が止まるのかを確かめています。

イベント・on:・ランナー・既定値の説明は、前回の記事に書いたので省略します。この記事では、前回と違うところだけを説明します。

なお、記事の内容は、断りがない限り自分の環境で動かして確かめていますが、CI/CDは初心者です。間違いなどがあれば、コメントで教えていただけるとうれしいです。

2. 作ったもの

プルリクエストを作るとチェックだけが動き、mainにマージするとチェックのあとに公開されるしくみです。

check.ymlには入口が2つあります。プルリクエストの道は、マージする前に結果を知るためのものです。mainの道は、公開の前の関所です。

3. 手順

環境は前回と同じです。無料プランのPrivateリポジトリを使っています。チェックはGitHub Actionsの中で動くので、自分のPCにNode.jsは入れていません。

ファイルは2つ足し、1つ変えました。

tobaru-net-test/
├─ .htmlvalidate.json        … チェックのルール(新規)
└─ .github/
    └─ workflows/
        ├─ check.yml         … チェックの指示書(新規)
        └─ deploy.yml        … チェックを呼ぶように変更

(1) チェックのルールを決める

HTMLのチェックにはhtml-validateを使いました。ルールを自分で作らなくても、できあいのrecommendedがあります。

.htmlvalidate.jsonです。

{
  "extends": ["html-validate:recommended"]
}

(2) check.ymlを書く

name: Check

on:
  # mainに向けたプルリクエスト
  pull_request:
    branches: [main]
  # ほかのワークフローから uses: で呼ばれたとき
  workflow_call:

jobs:
  html:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      # ランナーにファイルを取り出す
      - uses: actions/checkout@v5

      # public/ の中の .html を調べる
      - name: Validate HTML
        run: npx --yes html-validate@11.18.0 public/

(3) deploy.ymlを変える

変えたのは、checkジョブの追加とneeds: checkだけです。

jobs:
  # 公開の前の関所。中身は check.yml
  check:
    uses: ./.github/workflows/check.yml

  deploy:
    # check が成功したときだけ動く
    needs: check
    runs-on: ubuntu-latest
    # これ以降は前回と同じ

4. 試してみた

結果を先に書くと、チェックが赤のとき、マージは止まりませんでしたが、公開は止まりました。

やったこと 結果
そのままのページでプルリクエストを作る 赤
指摘されたところを直して、同じブランチにpush 緑
緑のままマージ check→deployと動き、公開された
</main>を消して、赤のままマージ マージはできたが、deployは実行されず、公開中のページは変わらなかった

(1) 壊す前に、もう赤になった

ブランチをpushしただけでは、何も動きません。check.ymlの条件はプルリクエストで、deploy.ymlの条件はmainへのpushだからです。プルリクエストを作ると、Check / htmlが動き始めました。

01_pr-running.png

わざと壊すのは、この次の予定でした。ところが、何も壊していないのに赤になりました。

02_check-failed.png

ログを開くと、原因が書いてあります。

03_validate-log.png

index.htmlの1行目の<!doctype html>が、小文字だと指摘されています。ブラウザでは正しく表示されていますが、recommendedのdoctype-styleというルールは大文字を求めます。

(2) 直してpushすると、緑になった

<!DOCTYPE html>に直して、同じブランチにpushしました。プルリクエストを作り直さなくても、チェックは自動で動き直します。

04_check-passed.png

(3) 緑のままマージすると、公開された

マージするとmainへのpushが起きて、deploy.ymlが動きます。checkのあとにdeployが動き、公開中のページも<!DOCTYPE html>に変わりました。

05_graph-success.png

(4) 赤のままマージしても、公開は止まった

いよいよ本番です。別のブランチで</main>を消して、プルリクエストを作りました。チェックは赤になりましたが、Merge pull requestのボタンは押せます。

06_failed-but-mergeable.png

あえてマージすると、checkが赤になり、deployはスキップされました。0秒なのは、一度も始まっていないからです。

07_graph-skipped.png

このときmainのコードからは</main>が消えていましたが、https://test.tobaru.netには</main>が残っていました。コードは壊れたが、公開中のページは守られたということです。

検証のあとは、壊した変更をgit revertで取り消して、もう一度プルリクエストからマージしました。チェックは緑で、公開も通っています。

5. なぜ公開が止まるのか

公開を止めているのは、deploy.ymlのneeds: checkです。画面の設定は何も変えていません。

(1) 赤と緑は、何で決まるの?

コマンドの終了コードで決まります。0なら成功、0以外なら失敗です。

4章のログの最後にも、Process completed with exit code 1.とあります。Actionsは「DOCTYPE should be uppercase」という文章を読んでいるのではありません。公式ドキュメントにも、ステップの成功と失敗は終了コードに基づいて報告されると書かれています(Workflow syntax)。

つまり、間違いがあるときに0以外で終わるコマンドなら、何でもチェックとして使えます。

(2) needs:がないと、どうなるの?

checkとdeployが同時に動くので、チェックが赤でも公開されるはずです(ここは試していません)。

ジョブは既定で並列に動きます。上から順に書いてあっても、順番はつきません。needs:を書くと、次の決まりが効きます。

If a job fails or is skipped, all jobs that need it are skipped

必要としているジョブが失敗すると、そのジョブはスキップされます。この決まりのおかげで、deployが赤を判断する処理は一切書いていません。

(3) なぜcheck.ymlを別のファイルにしたの?

プルリクエストとmainの両方で、同じチェックを使いたかったからです。

ただ、needs:は同じファイルの中のジョブしか指定できません。そこでcheck.ymlのon:にworkflow_callを書いて、ほかのワークフローから呼べるようにしました(公式ドキュメント)。deploy.ymlのcheckジョブは、それをuses:で呼んでいるだけです。

deploy.ymlの中にジョブとしてcheckがあるので、needs: checkと書けます。

プルリクエストのときのチェックと、マージのときのチェックは別の実行です。公開を止めているのは、マージのときの結果です。

(4) なぜマージは止まらなかったの?

無料プランのPrivateリポジトリでは、マージを止めるルールが効かないからです。

GitHubには、チェックが緑にならないとマージできなくする設定があります。ただ、SettingsのRulesetsを開くと、次の警告が出ていました。

08_rulesets-warning.png

古い形式のBranch protection ruleも同じです。ルールは作れますが、リポジトリをTeamなどの組織アカウントに移すまで適用されません。

09_branch-protection-warning.png

だから、止めているものを分けて考える必要があります。

しくみ 止めるもの 今回の環境
Rulesets・Branch protection rule マージ 効かない
needs: check 公開 効く

needs:では、mainのコードが壊れることは防げません。防げるのは公開だけです。それでも、ワークフローのファイルに書くだけなので、無料プランでも使えます。

6. 前回と違うところ

しくみ自体は前回と同じで、イベントが起きたらon:に合うワークフローが動きます。初めて出てきたものだけを説明します。

(1) pull_requestは、いつ動くの?

types:を書かなければ、opened・synchronize・reopenedの3つで動きます(公式ドキュメント)。

名前 いつ
opened プルリクエストを作った
synchronize ブランチに新しいcommitをpushした
reopened 閉じたプルリクエストを開き直した

4章の(2)で、pushしただけでチェックが動き直したのはsynchronizeのおかげです。これも前回と同じ、書かなかったときの既定値です。

(2) uses:のactions/checkout@v5は何?

持ち主/リポジトリ@バージョンの形で、GitHub上で公開されている部品を借りる書き方です。actions/checkoutは、GitHubが公開しているgithub.com/actions/checkoutのことです。

前回のcloudflare/wrangler-action@v4も、同じ形です。

(3) なぜcheckoutが必要なの?

ランナーは毎回新しく用意され、リポジトリのファイルは入っていないからです。この行がないと、調べるpublic/がありません。

プルリクエストのときに取り出されるのは、ブランチの先頭ではありません。actions/checkoutは既定で、イベントの対象のcommitを取り出します(action.yml)。pull_requestの場合、それはrefs/pull/番号/mergeです。

つまり、「mainにマージしたらこうなる」という仮のcommitを調べています。ブランチ単体では問題がなくても、マージ後に壊れる場合に気づけます。

(4) run:は何?

ランナーのシェルでコマンドを実行する書き方です。今回のコマンドはこれだけです。

npx --yes html-validate@11.18.0 public/
部分 意味
npx npmのパッケージを取ってきて実行する。package.jsonがなくても動く
--yes インストールの確認に答える人がいないので、先に「はい」と渡す
@11.18.0 バージョンを固定する。新版のルール追加で、ある日突然赤にならないように
public/ 調べるフォルダ。中の.htmlをすべて調べる

プルリクエストで変更したファイルだけを調べるのではありません。実際、4章の(1)の赤は、プルリクエストで変更していないindex.htmlで出たものです。

今回は小さなページ1つなので、全部調べても問題ありません。規模が大きくなって時間がかかるようになったら、変更したファイルだけに絞ることも検討が必要かもしれません。

Node.jsを入れる手順はありません。GitHubのランナーには最初からNode.jsが入っています。

7. ほかの言語のチェックツール

今回はHTMLだけですが、言語が変わってもチェックの入れ方は同じです。run:に書くコマンドが変わるだけです。

対象 ツール チェックするもの
HTML html-validate(今回使った) 文法・書き方
HTML HTMLHint 書き方
HTML lychee リンク切れ
JavaScript / TypeScript ESLint 書き方
TypeScript tsc 型
Python Ruff 書き方
Python mypy 型
共通 Prettier 整形
共通 gitleaks コードに混ざったパスワードなど

こうしたツールには、今回のrecommendedのようにできあいのルールが用意されているものが多くあります。自分で作り込む必要があるのは、アプリの動きを確かめるテストの中身くらいです。

8. まとめ

プルリクエストの時点で間違いに気づけて、うっかりマージしてしまっても、公開中のページは守られます。この2つを実際に確かめられたので、今回の検証は成功だと思います。

今回分かったことを並べると、次の3つです。

  • 赤と緑を決めるのは、コマンドの終了コード。Actionsは出力の文章を読んでいない
  • ジョブは既定で並列に動く。needs:を書くと、相手が失敗したときにスキップされる
  • 無料プランのPrivateリポジトリではマージは止められない。それでも、公開はneeds:で止められる

次は、プルリクエストを作るとAIがレビューしてくれるしくみを試す予定です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?