ข้ามไปยังเนื้อหา

CI กับ GitHub Actions

ถ้าคุณเคยตั้ง CI สำหรับ TypeScript project มาก่อน คุณเข้าใจโครงสร้างอยู่แล้ว: checkout code, ตั้ง language runtime, ติดตั้ง dependencies, รัน checks ฝั่ง Go แทบเหมือนกันเลย — แถมง่ายขึ้นในหลายจุดที่น่าพอใจ

สร้าง .github/workflows/ci.yml ใน repository ของคุณ:

name: Go CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
jobs:
test:
name: Test & Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.27"
cache: true # caches the module download cache
- name: Download dependencies
run: go mod download
- name: Verify dependencies
run: go mod verify
- name: Run go vet
run: go vet ./...
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
- name: Run tests
run: go test -race -coverprofile=coverage.out -covermode=atomic ./...
- name: Upload coverage report
uses: codecov/codecov-action@v4
with:
file: coverage.out
fail_ci_if_error: false
build:
name: Build Binary
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.27"
cache: true
- name: Build
run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o bin/app ./cmd/app
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: app-linux-amd64
path: bin/app

flags สำคัญใน test step:

  • -race เปิด Go race detector — จับ data races ใน concurrent code ด้วย runtime cost ~2–20x (ยอมรับได้ใน CI)
  • -coverprofile=coverage.out เขียน coverage data สำหรับอัปโหลด
  • -covermode=atomic จำเป็นสำหรับ coverage ที่แม่นยำเมื่อใช้ -race
name: Node CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Type-check
run: npx tsc --noEmit
- name: Lint
run: npx eslint src --ext .ts
- name: Test
run: npx jest --coverage
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci --omit=dev
- run: npm run build
TypeScript
# Node CI: needs setup-node + npm ci
# Type-check: tsc --noEmit (separate step)
# Lint: ESLint (separate step + config file)
# Test: Jest (separate step + config)
# Build: tsc/webpack output is JS files
steps:
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npx tsc --noEmit
- run: npx eslint src --ext .ts
- run: npx jest --coverage
- run: npm run build
Go
# Go CI: needs setup-go + go mod download
# Type-check: already part of go build/vet
# Lint: go vet + golangci-lint-action
# Test: go test -race (built-in)
# Build: single static binary
steps:
- uses: actions/setup-go@v5
with:
go-version: "1.27"
cache: true
- run: go mod download
- run: go vet ./...
- uses: golangci/golangci-lint-action@v6
- run: go test -race -coverprofile=coverage.out ./...
- run: CGO_ENABLED=0 GOOS=linux go build -o bin/app ./cmd/app

เซฟไฟล์นี้เป็น .github/workflows/ci.yml ใน repository ของคุณ Push ขึ้น branch แล้วดูที่ Actions tab — ไม่ต้องตั้งค่าอะไรในเครื่องเพื่อยืนยัน workflow

Terminal window
# Run all tests with race detector
go test -race ./...
# Run with coverage and write to file
go test -race -coverprofile=coverage.out -covermode=atomic ./...
# Print coverage summary to stdout
go tool cover -func=coverage.out
# Fail if coverage drops below a threshold (useful in CI)
go test ./... && go tool cover -func=coverage.out | tail -1 | awk '{if ($3+0 < 80) exit 1}'
# Run only tests matching a pattern
go test ./... -run TestUser
# Run tests with verbose output
go test -v ./...
flag `go test` ไหนเปิด concurrent race detector?
`go mod verify` ตรวจสอบอะไรใน CI pipeline?
ใน Go CI workflow ทำไมจึงใช้ `-covermode=atomic` ควบคู่กับ `-race`?
GitHub Action ไหนตั้งค่า Go toolchain ใน CI?