GitHub Actionsは、GitHubが提供する継続的インテグレーション/継続的デリバリー(CI/CD)プラットフォームです。リポジトリへのプッシュやプルリクエストをトリガーに、テストの実行、ビルド、デプロイを自動化できます。本記事では、Node.jsプロジェクトにおけるGitHub Actionsワークフローの作成方法から、複数バージョンでのマトリックステスト、キャッシュによる高速化、npm publishやDocker buildの自動化まで、実践的なCI/CDパイプラインの構築方法を解説します。
実行環境#
| 項目 |
バージョン |
| Node.js |
20.x LTS以上 |
| npm |
10.x以上 |
| OS |
Windows/macOS/Linux |
前提条件#
- JavaScriptの基礎知識があること
- Node.jsの基本API(
package.json、npmコマンド)を理解していること
- GitHubリポジトリの操作経験があること
GitHub Actionsの基本概念#
GitHub Actionsを理解するために、まず基本的な用語と概念を整理します。
ワークフロー、ジョブ、ステップの関係#
flowchart TB
subgraph Workflow["Workflow(.github/workflows/*.yml)"]
subgraph Job1["Job: build"]
Step1A["Step: Checkout"]
Step1B["Step: Setup Node.js"]
Step1C["Step: Install dependencies"]
Step1D["Step: Run tests"]
Step1A --> Step1B --> Step1C --> Step1D
end
subgraph Job2["Job: deploy"]
Step2A["Step: Deploy to production"]
end
Job1 --> Job2
end
| 用語 |
説明 |
| Workflow |
.github/workflowsディレクトリに配置するYAMLファイル。CI/CD全体の定義 |
| Job |
ワークフロー内で実行される一連のステップ。並列または順次実行が可能 |
| Step |
ジョブ内の個々のタスク。アクションの実行またはシェルコマンドの実行 |
| Action |
再利用可能なワークフローの構成要素。actions/checkoutなどのマーケットプレイス公開アクション |
| Runner |
ワークフローを実行するサーバー。GitHubホステッドまたはセルフホステッド |
ワークフローファイルの基本構造#
.github/workflows/ci.ymlとして配置する基本的なワークフローファイルの構造を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# ワークフローの名前(GitHub Actionsタブに表示される)
name: Node.js CI
# トリガー条件の定義
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
# ジョブの定義
jobs:
build:
# 実行環境の指定
runs-on: ubuntu-latest
# ジョブで実行するステップ
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
|
基本的なNode.js CIワークフロー#
実用的なNode.js CIワークフローを段階的に構築していきます。
シンプルなテスト実行ワークフロー#
最小構成のCIワークフローです。プッシュとプルリクエスト時にテストを自動実行します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
# .github/workflows/ci.yml
name: Node.js CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Install dependencies
run: npm ci
- name: Run build
run: npm run build --if-present
- name: Run tests
run: npm test
|
npm ciはnpm installと異なり、package-lock.jsonに基づいて厳密に依存関係をインストールします。CI環境ではこちらの使用が推奨されます。
トリガーイベントの詳細設定#
ワークフローのトリガー条件は柔軟にカスタマイズできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
on:
# プッシュ時のトリガー
push:
branches:
- main
- 'release/**' # release/v1.0などのブランチ
paths:
- 'src/**' # srcディレクトリ配下の変更時のみ
- 'package.json'
paths-ignore:
- '**.md' # Markdownファイルの変更は除外
- 'docs/**'
# プルリクエスト時のトリガー
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
# 手動実行
workflow_dispatch:
inputs:
environment:
description: 'Deploy environment'
required: true
default: 'staging'
type: choice
options:
- staging
- production
# スケジュール実行(UTC時刻)
schedule:
- cron: '0 0 * * 1' # 毎週月曜日の00:00 UTC
|
マトリックス戦略による複数バージョンテスト#
Node.jsプロジェクトでは、複数のNode.jsバージョンでテストを実行することが重要です。マトリックス戦略を使用すると、異なるバージョン・OS環境での並列テストが可能になります。
複数Node.jsバージョンでのテスト#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
# .github/workflows/ci.yml
name: Node.js CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
# 1つのジョブが失敗しても他のジョブを継続
fail-fast: false
matrix:
node-version: ['18.x', '20.x', '22.x']
steps:
- uses: actions/checkout@v5
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
|
このワークフローは、Node.js 18.x、20.x、22.xの3つのバージョンで並列にテストを実行します。
クロスプラットフォームテスト#
OSとNode.jsバージョンの組み合わせでテストする場合は、複数のマトリックス軸を定義します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: ['18.x', '20.x']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
|
特定の組み合わせを除外・追加#
excludeとincludeを使用して、マトリックスの組み合わせを調整できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: ['18.x', '20.x', '22.x']
exclude:
# Windows + Node.js 18の組み合わせを除外
- os: windows-latest
node-version: '18.x'
include:
# 特定の組み合わせを追加(実験的なバージョン)
- os: ubuntu-latest
node-version: '23.x'
experimental: true
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental || false }}
steps:
- uses: actions/checkout@v5
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
|
キャッシュによるCI高速化#
依存関係のキャッシュは、CIパイプラインの実行時間を大幅に短縮できます。
setup-nodeアクションの組み込みキャッシュ#
actions/setup-node@v4には依存関係キャッシュ機能が組み込まれています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Setup Node.js with cache
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm' # npm, yarn, pnpmに対応
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
|
cache: 'npm'を指定するだけで、~/.npmキャッシュディレクトリが自動的にキャッシュされます。
actions/cacheによる詳細なキャッシュ制御#
より細かいキャッシュ制御が必要な場合は、actions/cacheを直接使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-modules-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-modules-
- name: Install dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm ci
- name: Run tests
run: npm test
|
キャッシュの仕組みと効果#
flowchart LR
subgraph FirstRun["初回実行"]
A1["npm ci 実行"] --> A2["node_modules 生成"]
A2 --> A3["キャッシュ保存"]
end
subgraph SecondRun["2回目以降"]
B1["キャッシュキー確認"] --> B2{"キャッシュ<br>ヒット?"}
B2 -->|Yes| B3["キャッシュ復元"]
B2 -->|No| B4["npm ci 実行"]
B3 --> B5["npm ci スキップ"]
end
| 項目 |
キャッシュなし |
キャッシュあり |
| 依存関係インストール時間 |
30秒〜2分 |
5〜10秒 |
| ネットワーク通信 |
毎回ダウンロード |
キャッシュから復元 |
| 課金時間 |
長い |
短い |
Lintとテストの統合#
実務では、テストだけでなくLintやフォーマットチェックもCIに組み込みます。
包括的なCIワークフロー#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Check formatting
run: npm run format:check
test:
name: Test
runs-on: ubuntu-latest
needs: lint # lintジョブが成功した後に実行
strategy:
matrix:
node-version: ['18.x', '20.x', '22.x']
steps:
- uses: actions/checkout@v5
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Upload coverage
if: matrix.node-version == '20.x'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
fail_ci_if_error: false
build:
name: Build
runs-on: ubuntu-latest
needs: test # testジョブが成功した後に実行
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 7
|
ジョブ間の依存関係#
flowchart LR
A["lint"] --> B["test"]
B --> C["build"]needsキーワードを使用することで、ジョブ間の実行順序を制御できます。needs: lintを指定すると、lintジョブが成功した場合にのみtestジョブが実行されます。
npm publishの自動化#
パッケージをnpmレジストリに自動公開するワークフローを構築します。
リリース時の自動公開#
GitHubでリリースを作成した際に自動的にnpmに公開するワークフローです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
# .github/workflows/publish.yml
name: Publish Package
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
- name: Publish to npm
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
npm認証トークンの設定手順#
npmへの公開には認証トークンが必要です。以下の手順で設定します。
- npmにログインし、Access Tokensページ(https://www.npmjs.com/settings/~/tokens)にアクセス
- 「Generate New Token」をクリックし、「Automation」タイプを選択
- 生成されたトークンをコピー
- GitHubリポジトリの「Settings」→「Secrets and variables」→「Actions」→「New repository secret」を選択
- 名前を
NPM_TOKEN、値に先ほどのトークンを設定
GitHub Packagesへの公開#
npmレジストリではなくGitHub Packagesに公開する場合は、以下のように設定します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
# .github/workflows/publish-gpr.yml
name: Publish to GitHub Packages
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://npm.pkg.github.com'
scope: '@your-username'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Publish to GitHub Packages
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
package.jsonには以下の設定が必要です。
1
2
3
4
5
6
|
{
"name": "@your-username/your-package",
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
}
|
Docker buildの自動化#
Node.jsアプリケーションをDockerイメージとしてビルド・プッシュするワークフローを構築します。
GitHub Container Registryへのプッシュ#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
tags:
- 'v*'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Log in to Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
|
Node.js用のDockerfile例#
上記ワークフローで使用するDockerfileの例です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
# ビルドステージ
FROM node:20-alpine AS builder
WORKDIR /app
# 依存関係のインストール
COPY package*.json ./
RUN npm ci --only=production
# ソースコードのコピーとビルド
COPY . .
RUN npm run build
# 実行ステージ
FROM node:20-alpine AS runner
WORKDIR /app
# セキュリティ: non-rootユーザーで実行
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 appuser
# 本番用ファイルのコピー
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 3000
CMD ["node", "dist/index.js"]
|
Docker Hubへの公開#
Docker Hubにイメージを公開する場合は、以下のように設定します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
# .github/workflows/docker-hub.yml
name: Docker Hub Publish
on:
release:
types: [published]
jobs:
push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: your-dockerhub-username/your-app
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
|
環境変数とSecretsの管理#
CI/CD環境での機密情報と環境設定の管理方法を解説します。
Secretsの設定と使用#
GitHubリポジトリのSecretsには、APIキーやトークンなどの機密情報を安全に保存できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Deploy
run: |
curl -X POST ${{ secrets.DEPLOY_URL }} \
-H "Authorization: Bearer ${{ secrets.DEPLOY_TOKEN }}"
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
|
環境(Environments)の活用#
GitHub Environmentsを使用すると、本番環境用のSecretsと承認ワークフローを設定できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v5
- name: Deploy to staging
run: npm run deploy
env:
DEPLOY_URL: ${{ secrets.DEPLOY_URL }}
deploy-production:
runs-on: ubuntu-latest
needs: deploy-staging
environment:
name: production
url: https://your-app.com
steps:
- uses: actions/checkout@v5
- name: Deploy to production
run: npm run deploy:prod
env:
DEPLOY_URL: ${{ secrets.DEPLOY_URL }}
|
環境変数の優先順位#
環境変数は以下の優先順位で解決されます。
| 優先度 |
定義場所 |
スコープ |
| 高 |
ステップ内のenv |
該当ステップのみ |
| 中 |
ジョブ内のenv |
該当ジョブ内全ステップ |
| 低 |
ワークフロー全体のenv |
全ジョブ・全ステップ |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
env:
NODE_ENV: production # ワークフロー全体
jobs:
build:
env:
CI: true # ジョブ全体
steps:
- name: Test
run: npm test
env:
DEBUG: app:* # このステップのみ
|
実践的なワークフロー例#
ここまでの内容を統合した、実務で使用できる完全なCI/CDワークフローを示します。
完全なCI/CDパイプライン#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
release:
types: [published]
env:
NODE_VERSION: '20.x'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# 静的解析
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Check formatting
run: npm run format:check
# セキュリティ監査
security:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run security audit
run: npm audit --audit-level=high
# テスト(マトリックス)
test:
name: Test (Node.js ${{ matrix.node-version }})
runs-on: ubuntu-latest
needs: [lint, security]
strategy:
fail-fast: false
matrix:
node-version: ['18.x', '20.x', '22.x']
steps:
- uses: actions/checkout@v5
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test -- --coverage
- name: Upload coverage
if: matrix.node-version == '20.x' && github.event_name == 'push'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
# ビルド
build:
name: Build
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 7
# Dockerイメージのビルドとプッシュ
docker:
name: Docker Build & Push
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v5
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-output
path: dist/
- name: Log in to Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha,prefix=
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# npm公開(リリース時のみ)
publish:
name: Publish to npm
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'release'
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org'
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-output
path: dist/
- name: Install dependencies
run: npm ci
- name: Publish
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
パイプラインの実行フロー#
flowchart TB
subgraph Trigger["トリガー"]
Push["Push"]
PR["Pull Request"]
Release["Release"]
end
subgraph Parallel["並列実行"]
Lint["Lint & Format"]
Security["Security Audit"]
end
subgraph Matrix["マトリックステスト"]
Test18["Test Node 18.x"]
Test20["Test Node 20.x"]
Test22["Test Node 22.x"]
end
Build["Build"]
subgraph Deploy["デプロイ(条件付き)"]
Docker["Docker Push"]
Publish["npm Publish"]
end
Push --> Parallel
PR --> Parallel
Release --> Parallel
Parallel --> Matrix
Matrix --> Build
Build --> Docker
Build --> Publishトラブルシューティング#
GitHub Actionsでよく発生する問題と解決方法を紹介します。
キャッシュが効かない場合#
キャッシュキーの不一致が原因であることが多いです。
1
2
3
4
5
6
|
# 問題: package-lock.jsonのパスが間違っている
- uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
# ^^^^^^ ワイルドカードで確実にマッチ
|
npm ciが失敗する場合#
package-lock.jsonとpackage.jsonの不整合が原因です。
1
2
3
4
5
6
|
# ローカルで以下を実行してコミット
rm -rf node_modules
rm package-lock.json
npm install
git add package-lock.json
git commit -m "chore: regenerate package-lock.json"
|
権限エラーが発生する場合#
permissionsを明示的に指定します。
1
2
3
4
5
6
7
|
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # npm provenanceに必要
|
ワークフローのデバッグ#
デバッグログを有効にするには、リポジトリのSecretsに以下を設定します。
| Secret名 |
値 |
ACTIONS_RUNNER_DEBUG |
true |
ACTIONS_STEP_DEBUG |
true |
まとめ#
本記事では、GitHub Actionsを使用したNode.jsプロジェクトのCI/CD構築について解説しました。
| 項目 |
ポイント |
| ワークフロー基本 |
.github/workflows/にYAMLファイルを配置。トリガー、ジョブ、ステップで構成 |
| マトリックステスト |
複数Node.jsバージョン・OSでの並列テストが可能 |
| キャッシュ |
setup-nodeのcache: 'npm'またはactions/cacheで依存関係をキャッシュ |
| npm publish |
secrets.NPM_TOKENを設定し、registry-urlを指定して公開 |
| Docker build |
docker/build-push-actionでビルドとプッシュを自動化 |
| Secrets管理 |
リポジトリSecretsに機密情報を保存。Environmentsで環境ごとに分離 |
GitHub Actionsを活用することで、コードの品質担保からデプロイまでを完全に自動化できます。小さなワークフローから始め、プロジェクトの成長に合わせて段階的に拡張していくことをおすすめします。
参考リンク#