Category: guide
GitHub Actions Advanced — Matrix, Cache, Reusable Workflows
GitHub Actions ขั้นสูง: matrix builds, dependency caching, reusable workflows, environment secrets, และ workflow triggers
สารบัญ
Matrix Builds — ทดสอบหลาย environments
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
name: Test (Node ${{ matrix.node }}, OS ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
node: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
fail-fast: false # ไม่ cancel jobs อื่นถ้า 1 ตัว fail
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
Matrix กับ Include/Exclude
strategy:
matrix:
node: [18, 20]
include:
# เพิ่ม combination พิเศษ
- node: 22
experimental: true
exclude:
# ลบ combination ที่ไม่ต้องการ
- node: 18
os: windows-latest
Dependency Caching
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm' # ✓ shorthand: cache npm automatically
- run: npm ci # ใช้ cache ถ้ามี package-lock.json ไม่เปลี่ยน
- name: Cache build output
uses: actions/cache@v4
with:
path: .next/cache # หรือ dist/, .astro/, etc.
key: ${{ runner.os }}-nextjs-${{ hashFiles('package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('package-lock.json') }}-
${{ runner.os }}-nextjs-
Cache Key Strategy
# Cache key ที่ดี: OS + hash ของ lockfile + hash ของ source
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
# restore-keys: fallback เมื่อ exact key ไม่ match
restore-keys: |
${{ runner.os }}-npm-
Reusable Workflows
สร้าง workflow template ที่ workflows อื่น call ได้:
# .github/workflows/build-and-test.yml (reusable)
name: Build and Test (Reusable)
on:
workflow_call:
inputs:
node-version:
required: false
type: string
default: '20'
run-e2e:
required: false
type: boolean
default: false
secrets:
NPM_TOKEN:
required: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run build
- run: npm test
- if: inputs.run-e2e
run: npm run test:e2e
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# .github/workflows/deploy.yml (caller)
name: Deploy
on:
push:
branches: [main]
jobs:
test:
uses: ./.github/workflows/build-and-test.yml
with:
node-version: '22'
run-e2e: true
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
deploy:
needs: test # รอ test pass ก่อน
runs-on: ubuntu-latest
steps:
- run: echo "Deploying..."
Environments และ Secrets
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # ต้องกด approve ใน GitHub UI ถ้าตั้ง protection rules
steps:
- run: |
echo "Deploying to staging"
echo "URL: ${{ vars.DEPLOY_URL }}" # environment variable (ไม่ sensitive)
env:
API_KEY: ${{ secrets.STAGING_API_KEY }} # secret (sensitive)
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://panupongws.com # แสดงใน GitHub deployment
steps:
- run: echo "Deploying to production"
env:
API_KEY: ${{ secrets.PROD_API_KEY }}
Conditional Steps
steps:
- name: Deploy
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: npm run deploy
- name: Notify Slack (on failure)
if: failure()
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-d '{"text": "Build failed on ${{ github.ref }}"}'
- name: Run only on PRs
if: github.event_name == 'pull_request'
run: npm run size-limit
# Contexts ที่ useful:
# github.ref — refs/heads/main
# github.event_name — push, pull_request, schedule
# github.actor — ชื่อ user ที่ trigger
# runner.os — Linux, Windows, macOS
# job.status — success, failure, cancelled
Workflow Triggers ที่ใช้บ่อย
on:
# Push ไปยัง specific branches
push:
branches: [main, 'release/**']
paths-ignore: ['docs/**', '**.md'] # skip ถ้าแก้แค่ docs
# PR สู่ main
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
# Schedule (cron)
schedule:
- cron: '0 2 * * 1' # ทุกวันจันทร์ 02:00 UTC
# Manual trigger พร้อม input
workflow_dispatch:
inputs:
environment:
description: 'Deploy target'
required: true
type: choice
options: [staging, production]
dry-run:
type: boolean
default: false
# เมื่อ release ถูกสร้าง
release:
types: [published]
Artifacts — แชร์ไฟล์ระหว่าง Jobs
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 3
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- run: rsync -r dist/ user@server:/var/www/
Concurrency Control
# ยกเลิก run เก่าถ้ามี run ใหม่ของ branch เดียวกัน
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# หรือ per-environment: ป้องกัน 2 deploys รันพร้อมกัน
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false # รอให้เสร็จ ไม่ cancel
Permissions (Least Privilege)
permissions:
contents: read # อ่าน repo เท่านั้น (default ปลอดภัยกว่า)
actions: read
jobs:
deploy:
permissions:
contents: read
deployments: write # ต้องการสร้าง deployment
id-token: write # ต้องการสำหรับ OIDC (AWS/GCP auth)