GitHub Actions Advanced — DevOps

Fitur Advanced GitHub Actions Foundations Recap Sebelum masuk ke fitur advanced, pastikan kamu nyaman dengan fondasi workflow berikut: # Triggers — kapan…

Workflow di pelajaran GitHub Actions Dasar cuma punya satu job. Begitu catatan-api di-deploy lewat Actions, kamu butuh lima fitur lagi: matrix, cache, needs, environment, dan secrets. Bayangin dapur katering kita makin ramai. Satu resep dicicipi di beberapa kompor sekaligus (matrix), bumbu dasar dibuat sekali lalu disimpan di kulkas (cache), masakan baru boleh dikirim setelah semua cicipan lulus (needs), pengiriman ke pelanggan besar butuh tanda tangan kepala dapur (environment), dan kunci mobil pengantar disimpan di laci terkunci (secrets).

🧪 Tebakan cepat: matrix-nya node: [20, 22] dan os: [ubuntu-latest, macos-latest]. Berapa job test yang jalan, dan berurutan atau bersamaan? Tebak dulu, jawabannya ada di bagian "Matrix: satu job, banyak kombinasi".

Workflow catatan-api versi lengkap

Ini .github/workflows/ci.yml yang sama dengan di Lab: test di beberapa versi Node dan OS, lalu deploy ke web-1.

name: CI/CD

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    strategy:
      matrix:
        node: [20, 22]
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - uses: actions/cache@v4
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('package-lock.json') }}
      - run: npm ci
      - run: npm test

  deploy:
    needs: test
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/deploy.sh ${{ github.sha }}
        env:
          DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}

${{ ... }} adalah expression: GitHub mengganti isinya dengan nilai sebelum step jalan, misalnya ${{ matrix.node }} jadi 20.

Matrix: satu job, banyak kombinasi

strategy.matrix menjalankan job yang sama untuk setiap kombinasi nilai. Dua daftar berisi 2 dan 2 nilai menghasilkan 2 × 2 = 4 job, dan keempatnya jalan bersamaan (paralel), masing-masing di runner sendiri. Itu jawaban tebakannya.

# node os nama job di tab Actions
1 20 ubuntu-latest test (20, ubuntu-latest)
2 20 macos-latest test (20, macos-latest)
3 22 ubuntu-latest test (22, ubuntu-latest)
4 22 macos-latest test (22, macos-latest)

Urutannya: kunci pertama (node) di luar, kunci berikutnya di dalam, persis seperti dua loop bersarang. Kumpulan semua pasangan ini disebut cartesian product, dan itulah yang dibuat fungsi di latihannya. Satu kunci dengan satu nilai, misalnya php: ["8.3"], menghasilkan satu job. Tambah satu kunci c: [true] gak menambah job, tapi setiap kombinasi dapat c: true. Di dalam job, nilainya dibaca lewat ${{ matrix.node }} dan ${{ matrix.os }}.

Cache: jangan unduh ulang yang sama

Setiap job mulai dari runner kosong, jadi npm ci mengunduh ratusan paket setiap kali. actions/cache menyimpan folder di antara run:

Tiga run berturut-turut di job test (20, ubuntu-latest):

Run Yang terjadi Log actions/cache npm ci
1 pertama kali Cache not found for input keys: Linux-node20-... lalu Cache saved with key: ... 38 detik
2 push lagi, lockfile sama Cache restored from key: Linux-node20-... 6 detik
3 package-lock.json berubah Cache not found for input keys: ... (hash baru) 38 detik

Kenapa ~/.npm dan bukan node_modules? npm ci selalu menghapus node_modules sebelum memasang ulang, jadi cache node_modules terbuang percuma. Jalan pintasnya: actions/setup-node dengan cache: npm melakukan semua ini sendiri.

Satu aturan lagi: run di sebuah pull request bisa memakai cache dari main, tapi cache yang dibuat di pull request cuma berlaku untuk PR itu.

needs: deploy menunggu test

Tanpa needs, semua job jalan bersamaan. needs: test membuat deploy menunggu semua job matrix test lulus. Satu saja gagal, deploy dilewati. if: github.event_name == 'push' menambahkan syarat: deploy cuma untuk push ke main, gak pernah untuk pull request. Urutan lint, test, dan E2E dengan needs dibahas lebih dalam di pelajaran Testing di CI/CD Pipeline.

Environment: deploy butuh persetujuan

environment: production menghubungkan job ke environment bernama production. Di Settings, lalu Environments, lalu production, centang Required reviewers dan pilih siapa yang boleh menyetujui. Job deploy lalu berhenti dengan status Waiting dan pesan:

Waiting for review: production needs approval to start deploying changes.

Reviewer menekan "Review deployments", lalu "Approve and deploy", dan job-nya baru jalan. Inilah Continuous Delivery dari pelajaran Apa itu CI/CD, dalam bentuk GitHub Actions.

Secrets cuma untuk trigger tepercaya

Kunci SSH untuk masuk ke web-1 disimpan di Settings, lalu Secrets and variables, lalu Actions, dengan nama DEPLOY_SSH_KEY, lalu dibaca lewat context secrets: ${{ secrets.DEPLOY_SSH_KEY }}. Nilainya disamarkan jadi *** di log. Run yang dipicu push ke main atau PR dari branch di repo yang sama mendapat secret. Run dari PR dari fork (salinan repo milik orang lain) mendapat string kosong, karena kodenya belum kamu review. Cara menjaga secret lebih jauh ada di pelajaran CI/CD Pipeline Security.

⚠️ Jebakan yang sering ketemu

TL;DR: strategy.matrix menjalankan satu job untuk setiap kombinasi nilai (cartesian product, kunci pertama di luar), semuanya paralel: node: [20, 22] × os: [ubuntu-latest, macos-latest] = 4 job. actions/cache dengan path: ~/.npm dan key berisi hashFiles('package-lock.json') memulihkan unduhan npm (hit) atau menyimpannya di akhir job (miss), dan lockfile yang berubah memberi key baru. needs: test membuat deploy menunggu semua job test lulus, environment: production dengan Required reviewers membuatnya menunggu approval, dan secret dibaca dengan ${{ secrets.NAMA }}, disamarkan ***, dan kosong untuk PR dari fork.

Yang akan kamu pelajari