Belajar GitHub Actions - Troubleshooting, Debugging & Custom Action Development
Episode 19 of 21

Belajar GitHub Actions - Troubleshooting, Debugging & Custom Action Development

Workflow yang gagal bukan akhir dunia bila tahu cara membaca jejaknya. Di episode ini kita membuka debug logging, masuk langsung ke runner lewat SSH interaktif dengan tmate, lalu membangun custom action berbasis TypeScript maupun container Docker.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Di episode 18 kita mengotomasi release management dan semantic versioning. Saat pipeline makin kompleks, satu hal pasti terjadi: workflow gagal pada jam 2 pagi. Kemampuan men-debug dan memperbaiki pipeline sama pentingnya dengan kemampuan membangunnya. Di episode ini kita belajar membaca jejak kegagalan, membuka debug logging, masuk ke runner secara interaktif, lalu memproduksi custom action sendiri supaya logika yang berulang bisa dikemas dan dipakai ulang.

Di episode ini kita membahas:

  1. Troubleshooting workflow yang gagal: debug logging dan interactive SSH debugging.
  2. Pengembangan TypeScript custom action dengan @actions/core dan @actions/github.
  3. Pengembangan Docker container custom action.

Strategi Men-debug Workflow yang Gagal

Pendekatan berjenjang, mulai dari yang termurah:

  1. Baca log langkah. Klik step yang gagal di tab Actions, perhatikan perintah terakhir sebelum exit code non-zero.
  2. Re-run. Gunakan "Re-run failed jobs" untuk menjalankan ulang hanya job yang gagal — menghemat menit runner.
  3. Aktifkan debug logging. Log yang lebih detail untuk job yang sulit dipahami.
  4. Masuk ke runner. SSH interaktif ketika log pun tidak cukup.

Debug Logging: ACTIONS_RUNNER_DEBUG & ACTIONS_STEP_DEBUG

Dua repository secret memicu log yang jauh lebih detail:

SecretEfek
ACTIONS_RUNNER_DEBUGLog diagnosa runner: pemilihan job, download action, eksekusi step
ACTIONS_STEP_DEBUGLog tambahan per step, termasuk ekspor variabel dan konteks action

Set kedua secret bernilai true di repository Settings → Secrets and variables → Actions. Log tambahan muncul sebagai baris ##[debug] pada setiap step. Setelah selesai men-debug, hapus secret atau ubah nilainya kembali ke false — log debug membuat log membengkak dan memperlambat pipeline.

Interactive SSH Debugging dengan mxschmitt/action-tmate

Ketika log tidak cukup — misalnya error hanya muncul saat interaksi tertentu — kita bisa menyambungkan diri langsung ke runner yang sedang hidup lewat SSH menggunakan mxschmitt/action-tmate@v3. Tambahkan step sementara ke workflow:

debug.yml - SSH interaktif ke runner dengan tmate
name: Debug Runner
 
on: workflow_dispatch
 
jobs:
  debug:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout kode
        uses: actions/checkout@v4
 
      - name: Buka sesi SSH interaktif
        uses: mxschmitt/action-tmate@v3
        with:
          timeout-minutes: 30

Saat step ini berjalan, log menampilkan alamat SSH tmate seperti ssh alice@proxy.tmate.io. Dari laptop, kalian bisa masuk lalu menjalankan ls, ps aux, atau perintah lain langsung di runner untuk mengamati kondisi nyata. Layar mencetak status session sehingga kalian tahu kapan runner siap.

Warning

tmate membuka akses shell penuh ke runner bagi siapa pun yang memegang alamat SSH. Hanya aktifkan pada workflow sementara, jangan pernah dibiarkan di branch main, dan jangan gunakan di repository public dengan self-hosted runner.

Kalau sudah beres, hapus step tmate dari workflow — kalau tidak, setiap run akan berhenti menunggu koneksi sampai timeout.

Kapan Perlu Membuat Custom Action?

Tanda-tanda logika perlu dikemas menjadi action:

  • Snippet yang sama disalin di banyak step di banyak workflow (melanggar prinsip DRY).
  • Logika memerlukan bahasa pemrograman nyata, bukan rangkaian perintah bash yang rapuh.
  • Organisasi ingin berbagi logika build ke banyak repository.

Ada tiga jenis custom action: JavaScript/TypeScript, Docker container, dan composite. Di episode ini kita fokus ke dua yang pertama; composite sudah dibahas di episode 11.

TypeScript Custom Action

Action TypeScript dikompilasi menjadi satu file dist/index.js yang dijalankan langsung oleh runner dengan runtime Node.js. Karena tidak perlu build image, eksekusinya cepat — cocok untuk logika pemrosesan.

action.yml untuk TypeScript

Setiap action wajib punya action.yml di root repository action:

action.yml - metadata action TypeScript
name: 'Compute Next Version'
description: 'Menghitung versi berikutnya dari commit message Conventional Commits'
author: 'Arman'
inputs:
  release-type:
    description: 'Jenis rilis: patch, minor, atau major'
    required: true
  prefix:
    description: 'Prefix versi, misal v'
    required: false
    default: 'v'
outputs:
  version:
    description: 'Versi yang dihitung'
runs:
  using: node20
  main: dist/index.js
branding:
  icon: 'tag'
  color: 'purple'

Skeleton main.ts

Kode sumber ditulis TypeScript, memakai @actions/core untuk input/output dan @actions/github untuk akses konteks GitHub:

src/main.ts - skeleton action TypeScript
import * as core from '@actions/core'
import * as github from '@actions/github'
 
async function run(): Promise<void> {
  try {
    const releaseType = core.getInput('release-type')
    const prefix = core.getInput('prefix')
    const ref = github.context.ref
 
    const version = computeVersion(releaseType, ref)
    core.setOutput('version', `${prefix}${version}`)
  } catch (error) {
    core.setFailed(error instanceof Error ? error.message : 'Terjadi error')
  }
}
 
function computeVersion(releaseType: string, ref: string): string {
  return `1.${releaseType === 'minor' ? 1 : 0}.0`
}
 
run()

Penjelasan:

  • core.getInput() membaca input yang dideklarasikan di action.yml; core.setOutput() menulis output yang bisa dibaca workflow pemanggil.
  • github.context memberi akses ke konteks seperti repository, ref, dan actor.
  • core.setFailed() membuat action selesai dengan status gagal dan pesan yang jelas.

Kompilasi & Distribusi

Runner Node.js menjalankan dist/index.js, jadi kode sumber harus dikompilasi sebelum di-commit. Bangun dengan esbuild, lalu commit hasilnya:

Build action ke dist
npm install --save-dev esbuild typescript @types/node
npx esbuild src/main.ts --bundle --platform=node --target=node20 \
  --outfile=dist/index.js
git add dist/index.js
git commit -m "chore: build dist"

Karena action dipakai lewat tag atau SHA commit, dist/index.js harus selalu ter-update dan ter-commit — kalau lupa, action akan berjalan dengan kode lama. Bundling dengan esbuild merangkum @actions/core dan @actions/github ke dalam satu file, jadi konsumen action tidak perlu npm install apa pun.

Tip

Pasang eslint untuk memeriksa kode action, dan pastikan file dist di-build pada setiap perubahan source. Banyak tim membungkus kompilasi ke dalam workflow CI action itu sendiri agar tidak pernah lupa.

Docker Container Custom Action

Action Docker dijalankan di dalam container — bebas memilih bahasa dan dependensi, tanpa khawatir versi runtime di runner. Cocok untuk tool yang butuh image sendiri (misalnya gcloud atau kubectl versi tertentu). Kelemahannya: eksekusi lebih lambat karena harus build atau pull image dulu.

action.yml untuk Docker Container

action.yml - action berbasis Docker
name: 'Run Cloud Migrations'
description: 'Menjalankan skema migrasi database di cloud'
inputs:
  environment:
    description: 'Target environment'
    required: true
runs:
  using: docker
  image: Dockerfile
  env:
    ENVIRONMENT: ${{ inputs.environment }}

Dockerfile & Entrypoint

Image dibangun dari Dockerfile, lalu container menjalankan entrypoint:

Dockerfile untuk action container
FROM alpine:3.20
 
RUN apk add --no-cache python3 py3-pip
COPY entrypoint.sh /entrypoint.sh
 
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh - logika action
#!/bin/sh
set -euo pipefail
 
echo "Menjalankan migrasi untuk environment: ${INPUT_ENVIRONMENT}"
python3 /app/migrate.py --env "${INPUT_ENVIRONMENT}"

Penjelasan:

  • Input diakses lewat variabel lingkungan berprefix INPUT_ dalam huruf besar: input environment menjadi INPUT_ENVIRONMENT.
  • set -euo pipefail menghentikan container saat ada error, yang membuat action gagal dengan benar.
  • Entrypoint harus executable (chmod +x), dan pastikan tidak ada CRLF pada file — set core.autocrlf di git untuk menghindari error not found misterius.

Penutup

Di episode ini kita membahas troubleshooting dan custom action development:

  • Debug logging membuka ##[debug] berkat secret ACTIONS_RUNNER_DEBUG dan ACTIONS_STEP_DEBUG.
  • tmate memberi akses SSH interaktif ke runner untuk investigasi mendalam.
  • TypeScript action dikompilasi ke dist/index.js dengan @actions/core dan @actions/github.
  • Docker container action membungkus tool dalam image dan menerima input lewat prefix INPUT_.

Semua puzzle otomasi sudah lengkap: trigger, job, artifact, secret, deploy, rilis, dan kini custom action. Di episode 20, episode pamungkas, kita merangkai semuanya menjadi studi kasus pipeline CI/CD produksi lengkap end-to-end. Sampai jumpa!

Belajar GitHub Actions - Troubleshooting, Debugging & Custom Action Development | Belajar GitHub Actions