build-q (bq) 🚀
build-q (dibaca bq) adalah CLI Python zero-dependency untuk operasi docker buildx lokal & remote yang selaras dengan pipeline CI/CD (Jenkins X). Satu perintah pendek bq menggantikan docker buildx build yang panjang, dengan auto-detect Git, cicd/cicd.json, secret netrc, resource limit, dan idempotency check terhadap registry.
Selain build, bq menyediakan:
- Scaffolding CI/CD (
--init-jx,--init-legacy) - CI/CD Trigger (
--gh-action-init,--init-secrets,--cicd-trigger,--cicd-webhook) - Build Ops (
--fix-dockerfile,--init,--compose) - GitOps (
--bootstrap-k8s,--gitops-set-image,--set-image,--is-match-image) - Verifikasi (
--check,--repo-check,--doctor) - Fix (
--pr-fixrepo legacy template) - Interactive (
--tuiJev Agent Planner) - MCP Server (
--mcp— 18 tools untuk AI assistant via Model Context Protocol) - Credentials PocketBase IDP — login SSO GitHub
bq auth login(sejak v0.1.48),--pb-login,--pb-status, dll - Cloud build Docker Build Cloud (
--cloud, sejak v0.1.50)
Sejak v0.1.17 operasi GitHub berjalan native (tanpa gh CLI). Sejak v0.1.30 mendukung PocketBase fallback untuk cicd.json.
📚 Panduan Cepat untuk Pemula
Bagian ini untuk yang baru pertama kali pakai bq. Kalau sudah familiar, lanjut ke Instalasi.
Apa saja yang perlu di-install?
Sebelum pakai bq, siapkan tools berikut di laptop:
| Tools | Wajib? | Kegunaan | Cara install (macOS via Homebrew) |
|---|---|---|---|
| Python 3.7+ | ✅ Wajib | Runtime bq |
brew install python (biasanya sudah ada) |
| pipx | ✅ Rekomendasi | Install CLI Python secara terisolasi | brew install pipx && pipx ensurepath |
| Docker Desktop / Colima | ✅ Wajib | Docker engine + Buildx plugin | brew install --cask docker atau brew install colima docker docker-buildx |
| Git | ✅ Wajib | Auto-detect repo/branch | brew install git (biasanya sudah ada) |
GitHub CLI (gh) |
⚠️ Wajib untuk --clone, --remote, --gh-auth, --init-secrets, --gh-action-init |
Autentikasi GitHub, fetch token, clone repo | brew install gh && gh auth login |
| kubectl | ⚙️ Opsional | Fetch webhook token otomatis dari k8s (--init-secrets) |
brew install kubectl |
Cek versi setelah install:
python3 --version # >= 3.7
pipx --version
docker --version
docker buildx version
git --version
gh --version && gh auth status
kubectl version --client # opsional
Install bq (pemula, langkah demi langkah)
# 1. Install pipx (kalau belum ada)
brew install pipx
pipx ensurepath # tambahkan pipx ke PATH — restart terminal setelah ini
# 2. Install build-q
pipx install build-q
# 3. Verifikasi
bq --version # harus menampilkan versi terpasang
build-q --version # alias — sama saja
# 4. Bootstrap awal (buat config + Docker buildx builder)
bq --init
Setelah bq --init selesai, file config akan ada di ~/.build-q/.env dan Docker Buildx builder siap dipakai.
Upgrade ke versi terbaru
# Rekomendasi (pipx)
pipx upgrade build-q
# Kalau pakai pip biasa
pip install --upgrade build-q
# Pin versi tertentu (opsional)
pipx install --force build-q==0.1.11
# Cek versi yang sedang terpasang
bq --version
Tips: jika pipx upgrade bilang "already at latest" tapi kamu yakin ada rilis baru, refresh cache PyPI:
pipx install --force build-q # reinstall dari PyPI terbaru
Uninstall
pipx uninstall build-q # kalau install via pipx
pip uninstall build-q # kalau install via pip
rm -rf ~/.build-q # hapus config (opsional)
Alur 5 menit pertama (pemula)
# 1. Masuk ke folder service Go/.NET yang sudah ada Dockerfile
cd my-service
# 2. Preview command yang akan dijalankan (aman — tidak eksekusi)
bq --dry-run
# 3. Build tanpa push ke registry
bq --no-push
# 4. Build + push ke registry (mode default)
bq
Kalau muncul error builder not found → jalankan bq --init sekali dulu.
Kalau muncul error authentication required saat push → login ke Docker Hub / registry: docker login.
🛠 Fitur
Build & Push
-
Zero-dependency: hanya Python 3.7+ standard library.
-
Git auto-detection: nama repo & ref (branch/tag/short-SHA) dari Git.
-
Mode sumber kode: build lokal,
--clone(viaghCLI), atau--remote(Buildx Git context). -
Registry idempotency: cek image di registry sebelum build → skip bila sudah ada (bypass
--rebuild). -
Smart env mapping (ref → env) — INLINE dengan pipeline Tekton di
~/jenkins-x/pipeline(lighthousetriggers.yaml+webhook-server.py).bq(bq --clone/bq --compose) menyimpulkan environment otomatis dari nama ref, sama persis dengan case shell di pipeline. Nilai dipakai sebagai--build-arg BRANCH=(buildx) danENV=(compose):Ref (branch/tag) ENV IMAGE_TAG di pipeline v1.2.3,refs/tags/v*productionv1.2.3(basename ref)developdevelopshort SHA stagingstagingshort SHA sandboxsandboxshort SHA main,master, unknown, kosongstaging(fallback Tekton*))short SHA Perhatikan: push ke
main/masterTIDAK memicu production di JX — tagv*yang memicu. Override manual:--build-arg BRANCH=custom(buildx). -
Default netrc secret:
--secret id=netrc,src=$HOME/.netrcotomatis. -
Resource limit default: memory & CPU aman untuk laptop.
-
CI/CD alignment: baca
PORT/PORT2/PROJECT/IMAGEdaricicd/cicd.json. -
Dry run: pratinjau command tanpa eksekusi.
-
GitHub org shorthand: set
GITHUB_ORG=...di config → cukupbq <repo>bukanbq <owner>/<repo>. -
--remotefallback HTTPS: bilaSSH_AUTH_SOCKtidak tersetel,bqotomatis pindah ke HTTPS +GIT_AUTH_TOKEN(viagh auth token) untuk Buildx Git context — tidak perlu ssh-agent. -
--composemode: jalankanmake build ENV=...+make release ENV=...sebagai alternatifdocker buildx(cocok untuk repo yang alur build-nya via Makefile + docker compose).
Setup & Automation
--init: buat file config~/.build-q/.envdan auto-create Docker Buildx builder (bootstrap).- Template terpusat di gist: sejak
v0.1.14,--init-jx,--init-legacy, dan--gh-action-initfetch template dari gist mamatnurahmat (6 file). Cache lokal di~/.build-q/templates/(TTL 1 jam). Fallback ke bundled snapshot bila offline. Update / perbaikan template harus dilakukan di gist (viagh gist edit) — semua userbqotomatis dapat versi terbaru pada scaffold berikutnya. --init-jx: scaffoldMakefile+compose.yaml+Dockerfile(modern secret mount) +.github/workflows/trigger-ci.ymldaricicd/cicd.json. Auto-panggil--init-secretsbila git remote GitHub terdeteksi.--init-legacy: scaffoldMakefile+compose.yamluntuk pola legacy (Dockerfile pakaiARG GITHUB_USER/GITHUB_TOKEN— bukan BuildKit secret). Makefile auto-ambilgh auth tokenuntuk local dev. Dockerfile tidak di-overwrite — cocok untuk repo lama yang belum bisa migrasi ke secret mount.--gh-action-init: bootstrap standar.github/workflows/trigger-ci.ymlsebagai satu-satunya workflow — hapus semua workflow YAML lain di.github/workflows/, tulis ulang trigger-ci.yml, lalu set webhook secrets (WEBHOOK_TRIGGER_URL,WEBHOOK_TRIGGER_TOKEN).--init-secrets: set GitHub Actions secrets (WEBHOOK_TRIGGER_URL,WEBHOOK_TRIGGER_TOKEN) — auto-fetch token dari k8s secretwebhook-trigger-tokendi namespacejenkins-x, auto-detect target repo darigit remote.--fix-dockerfile: migrasi Dockerfile legacy menjadi modern. Deteksi & auto-fix:FROM ... as ...→AS(uppercase)- Hapus
ARG GITHUB_USER/ARG GITHUB_TOKEN RUN echo "machine github.com ..." > ~/.netrc && chmod ... && <cmd>→RUN --mount=type=secret,id=netrc,target=/root/.netrc \ ...- Baru: standalone
RUN echo ... > ~/.netrc(tanpa&& chmod && ...) → dihapus, lalu mount secret otomatis ditambahkan ke RUN line yang berisigo mod tidy/downloadataugo get. - Baru:
MAINTAINER foo(deprecated) →LABEL maintainer="foo" - Baru:
ENV KEY value(legacy) →ENV KEY=value - Backup asli disimpan ke
Dockerfile.bak.
--gh-auth: injeksi--build-arg GITHUB_USER+GITHUB_TOKENdarighCLI (workaround untuk Dockerfile legacy yang belum dimigrasi).- Auto-recover builder stale:
ensure_builderdeteksi endpoint rusak (misal socket Colima lama) dan recreate otomatis.
📦 Instalasi
pipx install build-q # rekomendasi (CLI global, virtualenv terisolasi)
# atau
pip install build-q
Dua entry point tersedia: build-q dan shorthand bq.
Upgrade ke versi terbaru:
pipx upgrade build-q
# atau
pip install --upgrade build-q
⚙️ Konfigurasi Awal (sekali saja)
bq --init # buat ~/.build-q/.env + create Docker buildx builder
bq --init --force # recreate config; builder tetap aman (cek dulu, buat bila tidak ada)
bq --config # tampilkan konfigurasi aktif
~/.build-q/.env
| Variable | Default | Keterangan |
|---|---|---|
BUILDER_NAME |
mybuilder |
Nama Docker Buildx builder |
REGISTRY_URL |
loyaltolpi |
Docker registry (Qoin default: loyaltolpi — Docker Hub org) |
DEFAULT_MEMORY |
4g |
Memory limit build |
DEFAULT_CPU_PERIOD |
100000 |
CPU period |
DEFAULT_CPU_QUOTA |
200000 |
CPU quota |
GIT_SSH_PREFIX |
git@github.com: |
Prefix SSH untuk --remote |
GITHUB_ORG |
(kosong) | Default org untuk shorthand bq <repo> |
WEBHOOK_TRIGGER_URL |
https://cicd-hw.qoin.id/trigger |
Endpoint webhook Jenkins X |
JX_KUBE_CONTEXT |
(kosong = current) | kubectl context untuk fetch token |
JX_KUBE_NAMESPACE |
jenkins-x |
Namespace secret |
JX_TOKEN_SECRET |
webhook-trigger-token |
Nama k8s secret berisi token |
GH_CLI |
false (sejak v0.1.22) |
false = jalur native (REST + git). true = fallback ke gh CLI (legacy) |
GITHUB_USER |
(kosong) | Username GitHub. Dipakai bila GH_CLI=false; bila kosong, di-fetch dari /user |
GITHUB_TOKEN |
(kosong) | Personal Access Token — WAJIB bila GH_CLI=false. Scope: repo, read:user, actions:write (untuk --init-secrets) |
DOCKERHUB_USER |
(kosong) | Username DockerHub (persiapan future docker login auto) |
DOCKERHUB_ORG |
(kosong) | Prefix image untuk rollout suggestion (mis. loyaltolpi). Fallback ke REGISTRY_URL bila kosong |
DOCKERHUB_TOKEN |
(kosong) | PAT DockerHub (untuk pemakaian manual) |
GITOPS_REPO |
Qoin-Digital-Indonesia/gitops |
Repo GitOps untuk suggestion gitops-set-image |
GITOPS_BRANCH |
main |
Branch target di repo GitOps |
GITOPS_INFRA |
cce |
cce (Huawei CCE) atau k8s (SLS). Override per-run: --infra |
NS_SUFFIX |
qoin |
Fallback global: ns = <env>-<suffix> bila --ns tidak diberikan dan cicd.PROJECT kosong. Sejak v0.1.22 cicd.PROJECT menang. |
PB_API_URL |
(kosong) | Endpoint PocketBase IDP (mis. https://cicd-hw.qoin.id/devops) |
PB_API_USER |
(kosong) | Username superuser PocketBase — legacy, fallback bila belum bq auth login |
PB_API_PASS |
(kosong) | Password superuser PocketBase — legacy |
PB_API |
false |
Set true untuk fetch secrets / cicd dari PocketBase. Tidak diset + sudah bq auth login → aktif otomatis |
ARGOCD_API_URL |
https://cicd-hw.qoin.id/argocd |
REST API ArgoCD — fallback --e2e saat kubectl gagal |
ARGOCD_TOKEN |
(kosong) | Token SSO ArgoCD; kosong → dibaca dari ARGOCD_AUTH_FILE (~/.pi/agent/auth.json) |
ARGOCD_AUTO_LOGIN |
true |
Token ArgoCD 401 → jalankan argocd-app token-login otomatis (terminal interaktif saja) |
Toggle native (tanpa gh CLI)
Default GH_CLI=true — bq tetap memakai gh CLI persis seperti sebelumnya, tidak ada breaking change. Untuk mengaktifkan jalur native (stdlib urllib + git):
GH_CLI=false
GITHUB_USER=your-login
GITHUB_TOKEN=ghp_xxx
Fitur yang dialihkan: fetch cicd.json, resolve commit SHA, ambil auth token, --gh-auth, --clone, --init-secrets. Untuk --init-secrets di mode native, install extra: pip install pynacl (dibutuhkan enkripsi libsodium sebelum PUT ke API).
Bila
~/.build-q/.envsudah ada dari versi sebelumnya, tambahkan tiga baris di atas secara manual — atau jalankanbq --init --forceuntuk regenerate (perhatikan config lain akan direset ke default).
🚀 Rollout suggestions pasca-build
Sejak v0.1.18, setelah build sukses (atau --dry-run), bq menampilkan dua perintah siap copy-paste yang membungkus tools eksternal set-image (imperative — kubectl set image + rollout status) dan gitops-set-image (declarative — patch YAML di repo GitOps lalu push).
Contoh output:
✅ Build completed successfully.
📤 Rollout suggestions (copy-paste ke terminal):
# 1) Hot-patch cluster (imperative, cepat)
set-image staging-qoin qoinhub-mono-webadmin 76e23f3
# 2) Via GitOps (declarative, ArgoCD sync)
gitops-set-image Qoin-Digital-Indonesia/gitops main \
cce/staging-qoin/qoinhub-mono-webadmin_deployment.yaml \
loyaltolpi/qoinhub-mono-webadmin:76e23f3
ℹ️ ns fallback: staging-qoin — override dengan --ns <name>
Tip: --ns <name> | --infra {cce|k8s} | --gitops-path <path>
Flag override runtime:
| Flag | Default | Keterangan |
|---|---|---|
--ns NAME |
<env>-<NS_SUFFIX> |
Namespace target. env dihitung dari branch (staging→staging, main→staging fallback, tag v*→production) |
--infra {cce,k8s} |
GITOPS_INFRA di .env |
Path template jadi {infra}/{ns}/{app}_deployment.yaml |
--gitops-path PATH |
(auto) | Bypass template — path YAML eksplisit |
Suggestion hanya print, tidak mengeksekusi. Cocok untuk review sebelum apply.
🔎 bq --check — verifikasi kesiapan repo (sejak v0.1.22)
Cek repo remote tanpa clone: apakah artifact CI/CD, image registry, dan file GitOps sudah sesuai ekspektasi.
bq --check ngenwal-be-saasidentityserver4client-manager staging --remote
Output:
🔍 Checking Qoin-Digital-Indonesia/ngenwal-…-manager @ staging
📦 Repository access:
✅ ref 'staging' → e82836bcad4c
🧩 CICD config:
✅ cicd/cicd.json (212 bytes)
• IMAGE = ngenwal-…-manager
• PROJECT = ngenwal
• PORT = 6770
🧱 Init artifacts (jx-init):
✅ Makefile
✅ compose.yaml
✅ Dockerfile
✅ .github/workflows/trigger-ci.yml
📦 Registry:
⚠️ loyaltolpi/ngenwal-…:e82836b — NOT BUILT
🎯 GitOps:
✅ Qoin-Digital-Indonesia/gitops@main:cce/staging-ngenwal/ngenwal-…_deployment.yaml
📊 Summary: 2/2 wajib lulus, 1 warning
Exit code 0 bila semua wajib lulus (repo/ref + cicd config), 1 bila ada yang miss. Warning (missing artifact / image belum ada) tidak menggagalkan.
Bila ditemukan artifact OUTDATED, --check mencetak suggestion bq --pr-fix … di akhir output.
🩹 bq --pr-fix <repo> <ref> — one-shot fix (sejak v0.1.24)
Untuk repo yang init-nya OUTDATED (deteksi via --check), satu perintah menyelesaikan seluruh siklus fix:
bq --pr-fix ngenwal-be-snapconvert-manager master
# Preflight → clone → branch fix/jx-init-<ts> → regenerate 4 file →
# commit → push → set 2 repo secrets → open PR → cleanup
Prasyarat di ~/.build-q/.env:
GH_CLI=false+GITHUB_TOKEN(scope:repo,workflow,actions:write,read:user). Tanpaworkflow, push ke branch yang mengubah.github/workflows/*akan ditolak GitHub.WEBHOOK_TRIGGER_URL+WEBHOOK_TRIGGER_TOKEN(auto-fetched dari k8s pada preflight bila kosong; disimpan untuk run selanjutnya)- Package
pynacl(untuk enkripsi repo secret):pip install pynacl
Flag override:
| Flag | Default | Keterangan |
|---|---|---|
--pr-branch NAME |
fix/jx-init-<timestamp> |
Nama branch fix eksplisit |
--keep-workdir |
(delete) | Jangan hapus /tmp/bq-pr-fix-… setelah selesai |
--dry-run |
(execute) | Stop sebelum push/set-secret/open-PR. Workdir dipertahankan untuk inspeksi. |
Deduplikasi: bila PR untuk branch fix sudah ada (open), print URL PR eksisting alih-alih buat baru.
Contoh minimal untuk Qoin:
BUILDER_NAME=cloud-loyaltolpi
REGISTRY_URL=loyaltolpi
GITHUB_ORG=Qoin-Digital-Indonesia
WEBHOOK_TRIGGER_URL=https://cicd-hw.qoin.id/trigger
🚀 Panduan Penggunaan
1. Build dari direktori lokal
Auto-detect nama repo & branch dari git:
cd my-service
bq # build + push (default)
bq --no-push # build tanpa push
bq --dry-run # preview command saja
bq my-service staging # eksplisit repo/ref
2. Build dari repo remote tanpa clone
# Dengan GITHUB_ORG di config → shorthand
bq plus-be-paymentlink-manager staging --remote
# Tanpa GITHUB_ORG → sertakan owner
bq Qoin-Digital-Indonesia/plus-be-paymentlink-manager staging --remote
# URL SSH/HTTPS penuh juga OK
bq git@github.com:owner/repo.git v1.0.0 --remote
Catatan
--remote: bilaSSH_AUTH_SOCKtidak tersetel (tidak jalaninssh-agent),bqotomatis fallback ke HTTPS +GIT_AUTH_TOKENsecret (viagh auth token) supaya Buildx Git context tetap bisa jalan tanpa perlu bootstrap ssh-agent.
3. Build dengan clone via gh CLI
bq --clone plus-be-paymentlink-manager staging
bq --clone plus-be-paymentlink-manager staging --clean # hapus folder setelah build
4. Preview command (dry-run)
bq --dry-run
bq plus-be-paymentlink-manager staging --remote --no-image-check --dry-run
5. Paksa rebuild (bypass image check)
bq plus-be-paymentlink-manager staging --remote --rebuild
Build di host remote (
DOCKER_CONTEXT)? Lihat VERIFY-REMOTE-BUILD.md untuk cara membuktikan bahwadocker buildbenar-benar dieksekusi di VM remote (viassh://), bukan di laptop lokal.
6. Bootstrap CI/CD service baru (Jenkins X — modern, secret mount)
mkdir my-new-service && cd my-new-service
mkdir cicd && cat > cicd/cicd.json <<EOF
{"IMAGE":"my-new-service","PROJECT":"qoinplus","PORT":"8080"}
EOF
bq --init-jx # scaffold Makefile/compose/Dockerfile/workflow
git init && git remote add origin git@github.com:Qoin-Digital-Indonesia/my-new-service.git
bq --init-secrets # set webhook secrets di GitHub (auto-detect repo)
git add . && git commit -m "chore: bootstrap CI/CD"
git push -u origin main # trigger Jenkins X pipeline via GitHub Actions
7. Bootstrap CI/CD service legacy (Dockerfile pakai ARG GITHUB_USER/TOKEN)
Kalau Dockerfile di repo lama belum bisa dimigrasi ke --mount=type=secret, pakai --init-legacy. Makefile-nya akan auto-ambil gh auth token untuk local dev.
cd my-old-service # Dockerfile-nya masih pakai ARG GITHUB_USER/TOKEN
bq --init-legacy # scaffold Makefile + compose.yaml (Dockerfile TIDAK ditimpa)
gh auth login # sekali saja
make build ENV=staging # token auto-diambil dari `gh auth token`
make release ENV=staging
8. Bootstrap GitHub Actions trigger sebagai satu-satunya workflow
Berguna kalau repo punya banyak workflow lama yang tidak dipakai lagi:
cd existing-repo
bq --gh-action-init # hapus workflow lain + tulis trigger-ci.yml + set webhook secrets
bq --gh-action-init --token xxxx # skip kubectl fetch, pakai token eksplisit
9. Migrasi Dockerfile legacy (ARG-based netrc → secret mount)
cd my-old-service
bq --fix-dockerfile # migrasi ./Dockerfile (backup ke .bak)
bq --fix-dockerfile path/to/Dockerfile
bq --no-push --rebuild # test build hasil migrasi
Yang di-fix otomatis:
FROM x as y→FROM x AS yARG GITHUB_USER/TOKENdihapusRUN echo "machine github.com ..." > ~/.netrc && chmod ... && <cmd>→RUN --mount=type=secret,id=netrc,...- Standalone
RUN echo ... > ~/.netrc→ dihapus, secret mount otomatis nempel diRUN go mod tidy/download/get MAINTAINER foo→LABEL maintainer="foo"ENV KEY value→ENV KEY=value
10. Workaround Dockerfile legacy tanpa migrasi (--gh-auth)
bq plus-be-service staging --remote --rebuild --gh-auth
# → inject GITHUB_USER dari `gh api user` + GITHUB_TOKEN dari `gh auth token`
11. Setup secrets Jenkins X untuk repo existing
cd existing-repo
bq --init-secrets # auto-detect dari git
bq --init-secrets Qoin-Digital-Indonesia/foo-service # eksplisit
bq --init-secrets foo-service --token xxxx # skip kubectl
12. Mode --compose (build via make build && make release)
Untuk repo yang alur build-nya sudah pakai Makefile + docker compose (mis. hasil --init-jx / --init-legacy). ENV= disimpulkan dari ref — lihat tabel Smart env mapping di atas:
# auto-detect: repo & ref dari git di direktori aktif
bq --compose # branch `develop` → ENV=develop
bq --compose my-service staging # ENV=staging
bq --compose my-service v1.2.3 # ENV=production
bq --compose my-service main # ENV=production
bq --compose --dry-run # preview command
# gabung dengan --clone (clone dulu, cd, lalu make build+release)
bq --clone Qoin-Digital-Indonesia/foo staging --compose # ENV=staging
bq --clone Qoin-Digital-Indonesia/foo v1.2.3 --compose # ENV=production
Registry idempotency di --compose: tag yang di-probe mengikuti aturan Makefile — git describe --tags --exact-match || git rev-parse --short HEAD. Jadi kalau HEAD di tag v1.2.3, bq cek registry/image:v1.2.3 (bukan short commit) — sama dengan tag yang di-push make release, sehingga early skip berfungsi benar.
13. Bootstrap manifest K8s ke repo GitOps (--bootstrap-k8s, sejak v0.1.29)
Satu perintah untuk bootstrap service baru ke Kubernetes lewat GitOps:
fetch cicd/cicd.json dari repo source (atau PocketBase sebagai fallback) → deteksi stack (dotnet vs default) →
render 3 file YAML (Secret, Deployment, Service) sesuai standar Qoin CCE →
update kustomization.yaml → commit → push → open PR ke repo GitOps (deduplicated).
Opsional apply Secret langsung ke cluster + auto-recreate Deployment saat
selector drift.
bq --bootstrap-k8s <repo> <ref> \
--gitops-repo Qoin-Digital-Indonesia/gitops \
--gitops-branch develop \
--path-yaml cce/develop-qoin \
--apply-secret --kube-context hw-dev
Workflow
flowchart TD
A[bq --bootstrap-k8s repo ref] --> B{Preflight<br/>GH_CLI=false<br/>GITHUB_TOKEN}
B -->|OK| C[Derive env dari ref<br/>develop/staging/production<br/>+ namespace dari path-yaml]
B -->|Missing| Z1[Abort]
C --> D[Fetch cicd/cicd.json<br/>dari source@ref via REST]
D --> E{Detect stack}
E -->|Probe appsettings.Env.json| F1[stack=dotnet]
E -->|Probe .env.env| F2[stack=default]
E -->|Probe .env| F2
E -->|Probe .env.example| F3[stack=default<br/>WARNING: template]
E -->|None| Z2[Abort: no config file]
F1 --> G[Build render ctx:<br/>APP, ENV, NAMESPACE, PROJECT,<br/>ROLE, NODEPOOL, IMAGE_FULL, PORT,<br/>IMAGE_PULL_SECRET, CONFIG_B64]
F2 --> G
F3 --> G
G --> H[Clone gitops shallow<br/>gitops@gitops-branch]
H --> I[Create branch<br/>bootstrap/app-env-ts]
I --> J[Render 3 YAML<br/>via templates gist + ctx]
J --> K[Update kustomization.yaml<br/>append 2 entries idempotent]
K --> L{--apply-secret?}
L -->|Yes + non-prod| M[kubectl apply Secret<br/>hanya jika belum ada]
L -->|Yes + production| M2[SKIP: production PR-only]
L -->|No| N
M --> N{--force-recreate-deploy?}
M2 --> N
N -->|Yes + selector drift| O[kubectl delete deploy<br/>ArgoCD selfHeal re-create]
N -->|No / no drift| P
O --> P{Git diff?}
P -->|Empty| Q1[Skip PR:<br/>Already up-to-date]
P -->|Has changes| Q2[Commit + Push + Open PR]
Q2 --> R[Return PR URL]
File yang di-generate
Semua file masuk ke {path-yaml}/ di repo GitOps:
| File | Isi | Selector consistency |
|---|---|---|
file-config-{app}_secret_sops.yaml |
Secret SOPS-encrypted (age) — data key .env (default) atau appsettings.{env}.json (dotnet), base64 dari source config. Nama file match .gitignore exception !**/*_secret_sops.yaml di repo gitops. |
— |
{app}_deployment.yaml |
Deployment — labels 4-tuple {app, env, project, role}, RollingUpdate, imagePullSecrets: regcred, nodeSelector: cce.cloud.com/cce-nodepool={nodepool}, tz-config volume, mount secret file-config-{app} ke /.env atau /app/appsettings.{env}.json |
matchLabels = template.labels (4-tuple exact) |
{app}_services.yaml |
Service — ClusterIP, targetPort: http, port dari cicd.PORT |
selector.app = {app} (subset — match pod 4-tuple) |
kustomization.yaml |
Append 3 entries (file-config-{app}_secret_sops.yaml + _services.yaml + _deployment.yaml) di resources: list |
— |
Selector Deployment ↔ Service dijamin match — placeholder {{APP}} tunggal di
template, satu render → tidak mungkin drift by construction.
Deteksi CICD Config (Waterfall)
Cek data CICD berurutan (bila gagal lanjut ke langkah berikutnya):
cicd/cicd.jsondi source repo via GitHub API.cicd.jsondi root source repo.- PocketBase collection
repo(sejak v0.1.30). Repo tanpacicd.jsonbisa di-bootstrap selama terdaftar di PocketBase dengan data CICD.
Deteksi stack (fallback berurutan)
Cek berurutan dari repo source {repo}@{ref} via GitHub REST:
appsettings.{DotnetEnv}.json(mis.appsettings.Development.json) → dotnet.env.{env}(mis..env.staging) → default (Go/Node/Rust).env→ default.env.example→ default (⚠️ template placeholder — value dummy)
Override via --stack dotnet atau --stack default.
Env derivation & guardrail production
Env otomatis dari <ref>:
| Ref | Env | Dotnet ASPNETCORE_ENVIRONMENT |
|---|---|---|
develop |
develop |
development |
staging |
staging |
staging |
sandbox |
sandbox |
sandbox |
main / master / tag v* |
production |
production |
Override via --env NAME (contoh: --env staging walau source ref main).
Guardrail env=production:
--apply-secret→ REFUSE (production wajib GitOps PR-only)--force-recreate-deploy→ REFUSE (production wajib manual blue-green/canary)
Flag lengkap
| Flag | Default | Keterangan |
|---|---|---|
--gitops-repo OWNER/REPO |
(wajib) | Target repo GitOps |
--gitops-branch BRANCH |
(wajib) | Base branch untuk PR |
--path-yaml PATH |
(wajib) | Folder tujuan di GitOps (mis. cce/develop-qoin). Segmen terakhir default jadi namespace. |
--namespace NAME |
(dari path-yaml) | Override K8s namespace di manifest (decouple dari path-yaml — untuk cross-env: gitops di cce/staging-qoin/ tapi apply ke production-qoin) |
--nodepool NAME |
{namespace}-{service|manager} |
Override cce-nodepool selector (mis. production-nodepool-service) |
--env NAME |
dari ref | Override env label (bypass derivation) |
--stack {dotnet,default} |
auto-detect | Paksa stack pilihan |
--replicas N |
2 |
Replicas Deployment |
--image-pull-secret NAME |
regcred |
Nama imagePullSecret di Deployment |
--apply-secret |
off | kubectl apply Secret ke cluster bila belum ada (opt-in). Refuse env=production. |
--kube-context NAME |
current | kubectl context untuk --apply-secret / --force-recreate-deploy |
--force-recreate-deploy |
off | Delete Deployment lama bila selector.matchLabels drift (K8s selector IMMUTABLE). Butuh --kube-context. Refuse env=production. |
--dry-run |
(execute) | Skip push/PR — workdir dipertahankan |
--keep-workdir |
(delete) | Jangan hapus workdir /tmp/bq-bootstrap-… |
Idempotency
Semua step aman di-run berulang:
- Secret
--apply-secret→ skip bila sudah ada di cluster - YAML render → identical content = 0 git diff = 0 commit
- Kustomization update → skip bila 2 entry sudah include
- Force-recreate → skip bila selector match / Deployment belum ada
- Bila tidak ada diff sama sekali → print "already up-to-date" dan exit 0 tanpa PR
- PR dedup: bila branch fix sudah ada PR-nya (same
head.ref), cetak PR eksisting.
Contoh use case
A. Bootstrap develop-qoin (standar single-target):
bq --bootstrap-k8s pay-be-topup-manager develop \
--gitops-repo gitops --gitops-branch develop \
--path-yaml cce/develop-qoin \
--apply-secret --kube-context hw-dev
B. Bootstrap dengan source ref berbeda dari env (mis. sandbox → develop namespace):
bq --bootstrap-k8s plus-be-rusttransaction-module sandbox \
--gitops-repo gitops --gitops-branch develop \
--path-yaml cce/develop-qoin --env develop \
--apply-secret --kube-context hw-dev
C. Cross-env special case: gitops di staging-qoin/ tapi target ns production-qoin:
bq --bootstrap-k8s plus-be-rustcreateordersnap-manager sandbox \
--gitops-repo gitops --gitops-branch staging \
--path-yaml cce/staging-qoin \
--namespace production-qoin \
--nodepool production-nodepool-service \
--env staging \
--apply-secret --kube-context hw-pro-q
D. Recreate saat migrasi label schema (selector drift):
bq --bootstrap-k8s foo develop \
--gitops-repo gitops --gitops-branch develop \
--path-yaml cce/develop-qoin \
--kube-context hw-dev \
--force-recreate-deploy
# → detect selector 1-tuple → delete deploy → ArgoCD selfHeal apply spec baru
Failure modes (dari incident nyata)
| Gejala | Penyebab | Fix |
|---|---|---|
Pod ImagePullBackOff — unexpected media type text/html |
Anonymous Docker Hub pull kena rate limit karena tidak ada imagePullSecrets |
Sejak v0.1.29 template sudah include regcred; override via --image-pull-secret NAME |
ArgoCD sync=OutOfSync — spec.selector: field is immutable |
Deployment awal punya selector 1-tuple, template baru 4-tuple | Pakai --force-recreate-deploy (non-prod). Prod: manual blue-green |
Pod crash saat startup — Environment variable X is required |
Source config .env.example = template placeholder |
Patch Secret manual dgn value real: kubectl edit secret file-config-<app>-<env>, lalu kubectl rollout restart deploy/<app> |
PR konflik kustomization.yaml |
PR lain merged duluan menambah baris di posisi sama | Close PR + re-run bq --bootstrap-k8s (idempotent — akan render dari staging HEAD terbaru) |
cicd config tidak ada di repo maupun PocketBase |
Repo tidak ada cicd.json dan belum terdaftar di PocketBase | Tambah data di PocketBase via UI admin atau API PATCH. |
14. Fitur-fitur Tambahan
A. PocketBase IDP (--pb-*, v0.1.27+)
--pb-login: Authentikasi ke PocketBase API, fetch credentials, cache lokal (15m). Zero-local-config workflow.--pb-status,--pb-pull,--pb-logoutuntuk manajemen session.
B. Manual Webhook Trigger & Verify
--cicd-trigger <repo> <ref>: POST synthetic payload dengan HMAC signature (fetch webhook token viakubectl). Bypass manual GitHub UI.--cicd-webhook <repo>: Verifikasi webhookcicd-hw.qoin.id/hookterpasang di repo GitHub (REST API).
C. Kesiapan Repo & Tools
--check: Cek 7 aspek repo sebelum CI dijalankan (cicd.json, github webhook, github secrets, artifacts).--repo-check <repo> <ref>: Cek config CICD khusus dari PocketBase IDP (verifikasi data sebelum--bootstrap-k8s).--doctor: Diagnostics local pre-flight (cek binariesdocker buildx,gh,git, token validity, dan kubectl context).
D. GitOps & Live Patching
--gitops-set-image <gitops> <branch> <yaml> <image>: Declarative update image tag di file deployment YAML dan commit+push otomatis.--set-image <ns> <deploy> <image>: Imperative hot-patch K8s live deployment +--watch.--is-match-image <ns> <deploy> <gitops> <branch> <yaml>: Drift check antara image live cluster vs spec di GitOps repo.
E. TUI Planner (Jev System One)
--tui: Buka Jev Agent Planner — katalog tool/provider/pattern dibaca dari PocketBase (build_q_tools,build_q_providers,build_q_patterns), cache lokal TTL 1 jam di~/.build-q/.tui-cache.json. Fallback bootstrap minimum bila PB down + cache kosong.--tui-pull: Refresh cache katalog dari PocketBase (manual).--tui-sync <seed.json>: Upload katalog seed JSON ke PocketBase (upsert by unique field).--tui-ls: Tampilkan ringkasan katalog aktif (tools per-category, providers, patterns).- Di dalam TUI:
/e2e REPO REF(analisa CI/CD end-to-end, lihat bagian 16),/e2e --sim [SKENARIO],/refresh,/set KEY(input tersembunyi). Riwayat input tersimpan, satu error tidak lagi mematikan sesi, dan setiap eksekusi tercatat di~/.build-q/.tui-audit.log.
15. MCP Server — AI Assistant Integration (--mcp, sejak v0.1.44)
Sejak v0.1.46, bq menyediakan MCP (Model Context Protocol) server yang meng-expose seluruh kapabilitas CLI sebagai tools terstruktur untuk AI assistant (Claude Code, Claude Desktop, atau MCP client lain). AI bisa langsung memanggil Dockerfile scanning, K8s anomaly detection, pipeline trigger, GitOps operations, dan lainnya — tanpa perlu construct command string atau parse stdout.
Instalasi MCP
# Baru install
pipx install 'build-q[mcp]'
# Sudah punya bq, tambahkan MCP dependency
pipx inject build-q mcp
Quick Start — Claude Code
Tambahkan konfigurasi MCP server di settings Claude Code:
// .claude/settings.json
{
"mcpServers": {
"bq": {
"command": "bq",
"args": ["--mcp"]
}
}
}
Setelah ini, Claude Code akan otomatis mendeteksi 18 tools dari bq dan bisa memanggilnya saat user bertanya tentang Dockerfile, K8s manifest, build image, dan sebagainya.
Quick Start — Claude Desktop
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"bq": {
"command": "bq",
"args": ["--mcp"]
}
}
}
Transport Modes
| Mode | Flag | Kegunaan |
|---|---|---|
| stdio (default) | bq --mcp |
Claude Code, Claude Desktop — komunikasi via stdin/stdout |
| SSE | bq --mcp --mcp-transport sse --mcp-port 3001 |
Remote access via HTTP Server-Sent Events |
# Stdio (default, untuk Claude Code / Desktop)
bq --mcp
# SSE (untuk remote / web client)
bq --mcp --mcp-transport sse --mcp-port 3001
# SSE expose ke network (hati-hati — akses terbuka)
bq --mcp --mcp-transport sse --mcp-port 3001 --mcp-host 0.0.0.0
Daftar Lengkap MCP Tools (18)
Tier 1 — Read-only (aman, tanpa side effect)
| Tool | CLI Equivalent | Deskripsi |
|---|---|---|
dockerfile_scan |
bq --fix-dockerfile --scan-only |
Scan Dockerfile lokal (22+ rules: security, performance, compliance) |
dockerfile_scan_remote |
bq --fix-dockerfile --remote-repo X |
Scan Dockerfile dari GitHub repo tanpa clone |
k8s_anomaly_scan |
bq --anomaly-scan |
Scan K8s manifest (10+ checks: replicas, imagePullSecret, resource limits, securityContext) |
build_doctor |
bq --doctor |
Preflight check (Docker, buildx, Git, credentials, builder) |
config_show |
bq --config |
Tampilkan konfigurasi aktif (sensitive values di-mask) |
pipeline_check |
bq --check |
Verifikasi repo readiness (ref, cicd.json, artifacts, image, GitOps) |
gitops_match_check |
bq --is-match-image |
Compare image live K8s vs GitOps YAML (drift detection) |
image_check |
— | Cek apakah image:tag sudah ada di Docker Hub |
webhook_status |
bq --cicd-webhook |
Cek apakah webhook CI/CD terinstall di repo |
docker_build_preview |
bq --dry-run |
Preview build command tanpa eksekusi |
Tier 2 — Local Action (modifikasi file lokal, reversible)
| Tool | CLI Equivalent | Deskripsi |
|---|---|---|
dockerfile_fix |
bq --fix-dockerfile |
Auto-fix Dockerfile issues (backup ke .bak) |
sops_encrypt |
bq --sops-encrypt |
Encrypt file dengan SOPS + age |
sops_decrypt |
bq --sops-decrypt |
Decrypt file SOPS |
Tier 3 — External Action (modifikasi state eksternal)
| Tool | CLI Equivalent | Deskripsi |
|---|---|---|
docker_build |
bq repo ref |
Build image via buildx + optional push ke registry |
pipeline_trigger |
bq --cicd-trigger |
Trigger Jenkins X pipeline via webhook |
gitops_set_image |
bq --gitops-set-image |
Update image tag di GitOps YAML + push |
gitops_bootstrap |
bq --bootstrap-k8s |
Bootstrap K8s manifest (Secret/Deployment/Service) + PR |
k8s_set_image |
bq --set-image |
Hot-patch deployment live di cluster |
MCP Resources (4)
Resources adalah konteks read-only yang AI bisa akses kapan saja:
| URI | Deskripsi |
|---|---|
bq://version |
Versi bq + daftar semua capabilities |
bq://config |
Konfigurasi aktif (token/password di-mask) |
bq://doctor |
Hasil preflight check |
bq://catalog |
Jev tool catalog (tools, providers, patterns) |
MCP Prompts (3)
Prompts adalah workflow templates yang membimbing AI menjalankan serangkaian tools:
| Prompt | Arguments | Workflow |
|---|---|---|
deploy-new-service |
repo, ref, env |
doctor → check → scan → build → bootstrap → verify |
scan-and-fix |
repo, ref |
scan Dockerfile remote → fix → scan K8s manifest → report |
rollout-update |
repo, ref, namespace |
image check → build → set-image (imperative/declarative) → verify |
Contoh Interaksi via Claude Code
User: "scan Dockerfile di repo pay-be-topup-manager untuk security issues"
Claude: (memanggil tool dockerfile_scan_remote)
→ repo: "Qoin-Digital-Indonesia/pay-be-topup-manager"
→ ref: "main"
→ Result: {exit_code: 1, issues: [{rule: "DF-SEC-01", ...}]}
User: "cek apakah image v1.2.3 sudah ada di registry"
Claude: (memanggil tool image_check)
→ image: "loyaltolpi/pay-be-topup-manager:v1.2.3"
→ Result: {exit_code: 0, data: {exists: true}}
User: "trigger pipeline untuk build develop"
Claude: (memanggil tool pipeline_trigger)
→ repo: "Qoin-Digital-Indonesia/pay-be-topup-manager"
→ ref: "develop"
→ Result: {exit_code: 0, stdout: "...triggered..."}
Audit Logging
Setiap tool call dicatat di ~/.build-q/.mcp-audit.log dalam format JSON:
{"ts":"2026-10-07 15:12:50","level":"INFO","msg":"tool=run_doctor exit_code=0 elapsed_ms=6878"}
{"ts":"2026-10-07 15:12:52","level":"INFO","msg":"tool=run_dockerfile_scan exit_code=2 elapsed_ms=0"}
Structured Response
Semua tool mengembalikan JSON terstruktur:
{
"exit_code": 0,
"stdout": "...",
"stderr": "",
"elapsed_ms": 123,
"data": { ... }
}
Jika error:
{
"exit_code": 2,
"error": "ValueError: path not found",
"error_type": "ValueError",
"elapsed_ms": 1
}
Verifikasi
# Cek MCP server berjalan
bq --version # build-q (bq) 0.1.46
# Cek help MCP flags
bq --help | grep mcp
# Test manual (jika punya MCP client SDK)
# Server akan menampilkan 18 tools, 4 resources, 3 prompts
Arsitektur
build_q/mcp/
├── __init__.py
├── _capture.py # stdout/stderr capture + ANSI strip + audit log
├── server.py # MCPServer entry point + typed tool wrappers
├── resources.py # 4 MCP resources (version, config, doctor, catalog)
├── prompts.py # 3 MCP prompts (deploy, scan-fix, rollout)
└── tools/
├── scan.py # dockerfile_scan, dockerfile_scan_remote, k8s_anomaly_scan, dockerfile_fix
├── infra.py # build_doctor, config_show
├── cicd.py # pipeline_check, gitops_match_check, image_check, webhook_status, pipeline_trigger
├── build.py # docker_build, docker_build_preview
├── gitops.py # gitops_set_image, gitops_bootstrap
├── k8s.py # k8s_set_image
└── sops.py # sops_encrypt, sops_decrypt
16. Analisa CI/CD End-to-End (--e2e, sejak v0.1.47)
"Commit saya kok belum live?" — bq --e2e menelusuri satu commit dari trigger sampai
ArgoCD dan menunjuk titik putus (tahap pertama yang gagal). Read-only.
bq --e2e pay-be-topup-manager develop # repo pendek → GITHUB_ORG
bq --e2e Qoin-Digital-Indonesia/pay-be-topup-manager v1.4.2
| Tahap | Yang dicek |
|---|---|
| Source | ref → commit, ENV & tag image yang diharapkan (aturan sama dgn Tekton), cicd.json |
| Trigger | GitHub Action trigger-ci.yml untuk commit tsb, webhook cicd-hw.qoin.id/hook |
| Pipeline | PipelineRun webhook-<repo>-* di JX_KUBE_CONTEXT — step gagal + 15 baris log terakhir, results build/GitOps |
| GitOps | tag di YAML branch ENV (develop/staging/sandbox), atau status PR ke main untuk tag v* |
| ArgoCD | Application di ARGOCD_KUBE_CONTEXT (default hw-pro-p): sync, health, image live, override kustomize |
Exit code: 0 sehat · 1 ada tahap gagal · 2 menunggu (PR/sync/pipeline) atau ada tahap
yang tidak bisa diperiksa (cluster tak terjangkau → verdict incomplete, tidak pernah "sehat").
Simulasi tanpa cluster — untuk demo, pelatihan, dan self-test:
bq --e2e --simulate list # 17 skenario (trigger gagal, build gagal, PR belum merge, OutOfSync, …)
bq --e2e --simulate # self-test semua skenario
bq --e2e --simulate pipeline-build-failed # laporan lengkap 1 skenario
Config baru di ~/.build-q/.env (opsional): ARGOCD_KUBE_CONTEXT=hw-pro-p, ARGOCD_NAMESPACE=argocd.
Cluster tak terjangkau (sejak v0.1.48): bila kubectl ke ARGOCD_KUBE_CONTEXT timeout, tahap
ArgoCD dibaca via REST API (ARGOCD_API_URL, token SSO yang sama dengan MCP argocd /
argocd-app). Token kedaluwarsa → argocd-app token-login dijalankan otomatis di terminal.
17. Login PocketBase devops — SSO GitHub (bq auth, sejak v0.1.48)
Login sekali dengan akun GitHub (Dex, sama dengan ArgoCD); token per-user disimpan di
~/.build-q/auth.json (perm 600) dan dipakai otomatis untuk semua request PocketBase —
tidak perlu lagi PB_API_USER/PB_API_PASS superuser di laptop.
bq auth login # SSO GitHub via browser (default)
bq auth login --no-browser # tampilkan URL saja
bq auth login --password # alternatif email/password akun devops_users
bq auth status # validasi token ke server
bq auth refresh # perpanjang token
bq auth logout # hapus token + cache secrets
# Ambil credential milik sendiri (isi saja ke stdout — arahkan ke file)
bq auth list # key yang boleh diakses (tanpa isi)
bq auth get KUBECONFIG_READONLY_HW_B64 > ~/.kube/config-readonly-hw
bq auth get GITHUB_TOKEN --scope github --env all # pilih scope/env bila key ambigu
bq auth get SOME_B64 --raw > file.b64 # tanpa decode base64
bq auth get otomatis men-decode value dengan key berakhiran _B64 atau ber-tag
base64. Pesan/error ditulis ke stderr, sehingga file tujuan hanya berisi credential.
- Token berlaku 5 hari, di-refresh otomatis bila sisa umur < 1 hari.
- Prioritas auth: token
bq auth login→ fallbackPB_API_USER/PB_API_PASS(legacy). - Secrets yang diterima mengikuti hak akses user di server (role
view/admin, credential berbasis owner). bq --doctordanbq --pb-statusmenampilkan identitas & sumber auth yang dipakai.
18. Build via Docker Build Cloud (--cloud, sejak v0.1.50)
Build & push image memakai Docker Build Cloud (produk Docker Hub, org loyaltolpi), dengan
builder cloud dari laptop. Tidak ada VM tambahan yang terlibat.
bq my-service develop --remote --cloud # build dari git (context = remote repo#ref)
bq my-service develop --remote --cloud --rebuild # paksa build walau image sudah ada
bq --cloud # folder kerja saat ini
bq my-service v1.2.3 --cloud --cloud-builder loyaltolpi/qoin-build
bq my-service develop --remote --cloud --dry-run # tampilkan perintah, tanpa kredensial
Skip otomatis: sebelum build, bq mengecek apakah image sudah ada di Docker Hub memakai
kredensial PocketBase Anda. Jika sudah ada, build di-skip. Build hanya berjalan lagi dengan
--rebuild. Dengan --clone/--remote, pengecekan dilakukan sebelum clone agar tidak membuang waktu.
Prasyarat
- buildx resmi ≥ v0.38.0 (yang punya driver
cloud). buildx bawaan OrbStack/Homebrew tidak punya driver itu (failed to find driver "cloud"). Pasang ke~/.build-q/bin/docker-buildx, atau setBQ_BUILDX_BIN/--cloud-buildx. - Akun Docker Hub yang punya akses ke org builder.
- Kredensial
DOCKERHUB_USER/DOCKERHUB_TOKENdi PocketBase (lihatbq auth).
Engine lokal bebas: docker login dan build dijalankan lewat buildx resmi; OrbStack,
Docker Desktop, atau colima sama-sama bisa dipakai.
Alurnya
- Cek image di Docker Hub (skip bila sudah ada, kecuali
--rebuild). - Cari buildx resmi (driver
cloudharus tersedia). - Ambil kredensial Docker Hub dari PocketBase (owner-only).
- Login ke
DOCKER_CONFIGsementara. Token dikirim lewat stdin, tidak masuk argumen. - Buat builder cloud
cloud-<org>-<name>bila belum ada. buildx build --builder <cloud> --pushdari context (remote gitrepo#ref, atau folder kerja).- Logout dan hapus config sementara.
Keamanan
- Token Docker tidak pernah muncul di argumen perintah atau log.
--build-arg GITHUB_*diambil dari environment, jadi nilainya tidak masuk argumen.- Secret
netrcdangithub_token/github_usertetap dipakai seperti build lokal biasa. - Di mode
--remote,GIT_AUTH_TOKENditeruskan sebagai secret untuk repo privat.
Konfigurasi (opsional)
| Env | Flag | Default |
|---|---|---|
CLOUD_BUILDER |
--cloud-builder |
loyaltolpi/qoin-build |
BQ_BUILDX_BIN |
--cloud-buildx |
~/.build-q/bin/docker-buildx |
19. Contoh full (customize secret, platform, build-arg)
bq plus-be-service staging \
--secret id=custom,src=/path/to/secret \
--platform linux/amd64 \
--no-push \
--build-arg BRANCH=custom-branch \
--build-arg FEATURE_FLAG=on
🔗 Perintah Lengkap
bq [<repo> [<ref>]] [OPTIONS]
Subcommands (mutually exclusive):
--init Buat ~/.build-q/.env + init Buildx builder
--init --force Recreate config
--config Tampilkan konfigurasi aktif
--init-jx Scaffold Makefile/compose/Dockerfile/workflow (modern secret mount)
--init-jx --force Overwrite file existing
--init-legacy Scaffold Makefile + compose.yaml pola legacy (ARG GITHUB_USER/TOKEN)
--init-legacy --force Overwrite file existing
--gh-action-init Bootstrap standar trigger-ci.yml (hapus workflow lain + set secrets)
--init-secrets [<repo>] Set GitHub Actions webhook secrets
--fix-dockerfile [PATH] Migrasi Dockerfile legacy ke secret mount (+ MAINTAINER/ENV/standalone netrc)
--pr-fix [<repo> <ref>] One-shot 11-step fix untuk repo legacy template (branch + commit + push + set secrets + PR).
--cicd-webhook [<repo>] Cek eksistensi webhook cicd-hw.qoin.id.
--cicd-trigger <repo> <ref> Manual trigger pipeline via webhook (simulasi GitHub event).
--check [<repo> <ref>] Cek readiness repo (7 aspek).
--repo-check <repo> <ref> Cek config CICD dari PocketBase tanpa clone.
--doctor Diagnostic local toolchain (git, docker, tokens).
--tui Buka Jev Agent Planner (TUI, katalog dari PocketBase).
--tui-pull Refresh TUI catalog cache dari PocketBase.
--tui-sync <seed.json> Upload katalog JSON ke PocketBase (upsert).
--tui-ls Ringkas katalog TUI aktif.
--e2e <repo> <ref> Analisa CI/CD end-to-end: trigger → Tekton → GitOps → ArgoCD (read-only).
--e2e --simulate [list|all|<skenario>]
Simulasi --e2e tanpa cluster/jaringan (demo & self-test).
--set-image <ns> <dp> <img> Hot-patch deployment live di K8s.
--gitops-set-image ... Update image di repo GitOps + push.
--is-match-image ... Cek drift image K8s live vs GitOps.
auth login|status|refresh|logout Login PocketBase devops (SSO GitHub) → ~/.build-q/auth.json.
auth list | auth get <KEY> > <lokasi> Daftar / ambil isi credential milik sendiri.
--cloud Build & push via Docker Build Cloud (buildx resmi), kredensial dari PB.
--pb-login/status/pull/logout PocketBase IDP operations.
--mcp Run MCP server (stdio transport). 18 tools untuk AI assistant.
--mcp --mcp-transport sse --mcp-port PORT
Run MCP server via SSE (HTTP) di PORT.
--mcp-host HOST Bind address untuk MCP SSE (default: 127.0.0.1).
--bootstrap-k8s <repo> <ref> \
--gitops-repo <r> --gitops-branch <b> --path-yaml <p>
Bootstrap Secret + Deployment + Service ke repo GitOps.
Opsional: --namespace, --nodepool, --env, --stack,
--replicas, --image-pull-secret, --apply-secret,
--kube-context, --force-recreate-deploy.
Build modes:
(default) Build dari direktori lokal via docker buildx
--clone <owner/repo> Clone via `gh` CLI, lalu build
--clone ... --clean Hapus folder clone setelah build
--remote Build via Buildx Git context (tanpa clone) — auto-fallback HTTPS bila SSH_AUTH_SOCK kosong
--compose Jalankan `make build ENV=... && make release ENV=...` (bukan buildx)
Build options:
--cicd PATH Path cicd.json (default: cicd/cicd.json)
--context DIR Build context (default: .)
-f, --dockerfile PATH Path Dockerfile (default: Dockerfile)
-t, --tag IMAGE:TAG Override image tag
--push / --no-push Push image (default: push)
--image-check / --rebuild Cek image di registry, skip bila ada (default: on)
--no-image-check Sama dengan --rebuild
--platform PLATFORM Target platform (default: linux/amd64)
--build-arg KEY=VALUE Build arg (dapat diulang)
--secret id=ID,src=PATH Secret build (dapat diulang; netrc otomatis)
--gh-auth Inject GITHUB_USER/TOKEN dari `gh` CLI
--token VALUE Webhook token (dengan --init-secrets / --gh-action-init)
--dry-run Preview command tanpa eksekusi
--version Tampilkan versi
📋 Requirements
- Python 3.10+
- Docker + Buildx plugin
- Git (opsional; wajib untuk auto-detect & mode local)
- GitHub CLI (
gh) — wajib untuk--clone,--remote,--gh-auth,--init-secrets,--gh-action-init - kubectl — opsional; hanya untuk
--init-secrets/--gh-action-init(fetch token otomatis dari cluster) - MCP SDK — opsional; hanya untuk
--mcp(pipx inject build-q mcp)
📄 Template Terpusat (Gist)
Sejak v0.1.14, template scaffolding hidup di gist publik, bukan hard-coded di package:
- URL gist: https://gist.github.com/mamatnurahmat/35cc4c36e7c7c2d236a1b5149cdbcfd9
- Raw base:
https://gist.githubusercontent.com/mamatnurahmat/<gist-id>/raw/<filename> - 6 file:
Makefile.modern,compose.yaml.modern,Dockerfile.modern,Makefile.legacy,compose.yaml.legacy,trigger-ci.yml
Alur load:
load_template(name)
├── 1. cache ~/.build-q/templates/<file> (TTL 3600s, fresh?) ─► pakai
├── 2. fetch dari gist raw URL ─► refresh cache + pakai
├── 3. cache lama (expired) ─► pakai (dengan warning)
└── 4. bundled snapshot di build_q/templates.py ─► pakai (warning)
Cara update template
Update HARUS via gist, jangan edit build_q/templates.py. _BUNDLED_* di file itu hanya snapshot offline-fallback.
# Clone gist untuk edit local
gh gist clone 35cc4c36e7c7c2d236a1b5149cdbcfd9 build-q-templates
cd build-q-templates
# Edit file yang ingin diubah (mis. Makefile.modern)
vim Makefile.modern
# Commit + push (gist adalah git repo — otomatis publish)
git commit -am "fix: adjust Makefile.modern IMAGE_TAG logic"
git push
# Verifikasi raw URL sudah kepakai
curl -s https://gist.githubusercontent.com/mamatnurahmat/35cc4c36e7c7c2d236a1b5149cdbcfd9/raw/Makefile.modern | head
Force refresh cache di sisi user
Kalau user ingin ambil template terbaru sebelum TTL expired:
rm -rf ~/.build-q/templates # hapus cache — next scaffold auto-fetch
# atau override TTL per-invocation:
BUILD_Q_GIST_TTL=0 bq --init-jx
Override gist source (advanced)
Untuk fork/private mirror, override via env vars:
export BUILD_Q_GIST_USER=your-org
export BUILD_Q_GIST_ID=abcd1234...
export BUILD_Q_GIST_TTL=7200 # 2 jam
export BUILD_Q_GIST_TIMEOUT=15 # 15 detik
bq --init-jx
Pipeline Tekton pakai gist yang SAMA (Opsi B strict)
Sejak ~/jenkins-x/pipeline versi terbaru, Tekton pipeline overlay Makefile/compose/Dockerfile dari gist ini SEBELUM make build. Hasilnya BYTE-IDENTICAL dengan bq --init-jx — jadi tidak ada drift antara build lokal bq --compose dan build pipeline JX.
Alur di pipeline (step sync-scaffold di .lighthouse/triggers.yaml):
- Early-skip:
docker manifest inspect— kalau image sudah ada, skip semuanya. - Validate:
cicd/cicd.jsonwajib ada (fail-fast kalau tidak). - Auto-detect mode:
ARG GITHUB_USER/TOKENdi Dockerfile → legacy (Dockerfile tidak di-overlay). Else → modern (semua 3 file di-overlay). - Fetch dari gist raw URL, render placeholder pakai
sed s|{{KEY}}|VALUE|gdengan 7 keys (IMAGE, PROJECT, PORT, CLUSTER, DEPLOYMENT, NODETYPE, ORG_REGISTRY) — sama persis denganrender()dibuild_q/templates.py. make build && make release(fail-fast, tanpa|| echo WARN).
BREAKING: repo yang customize Makefile / compose.yaml / Dockerfile (modern mode) akan di-overlay tiap build. Custom target Makefile HILANG. Kalau perlu kustomisasi, edit di gist saja (semua repo dapat perubahan otomatis).
Sinkronisasi bundled fallback (maintainer only)
Saat rilis bq baru, refresh _BUNDLED_* di build_q/templates.py agar offline user tetap dapat template terkini:
GID=35cc4c36e7c7c2d236a1b5149cdbcfd9
for f in Makefile.modern compose.yaml.modern Dockerfile.modern Makefile.legacy compose.yaml.legacy trigger-ci.yml; do
curl -s "https://gist.githubusercontent.com/mamatnurahmat/$GID/raw/$f" > "/tmp/$f"
done
# lalu paste isi ke masing-masing _BUNDLED_* di build_q/templates.py
🧭 Troubleshooting
| Gejala | Kemungkinan penyebab | Solusi |
|---|---|---|
builder "mybuilder" not found |
Buildx belum di-bootstrap | bq --init |
authentication required saat push |
Belum login registry | docker login (atau docker login <registry>) |
invalid empty ssh agent socket (mode --remote) |
SSH_AUTH_SOCK kosong |
Sudah auto-fallback ke HTTPS + gh auth token. Kalau tetap gagal → gh auth login |
gh: command not found |
GitHub CLI belum ter-install | brew install gh && gh auth login |
--init-secrets gagal fetch token |
Konteks kubectl salah / secret tidak ada | Set JX_KUBE_CONTEXT di ~/.build-q/.env, atau --token xxxx |
| Build sukses tapi image tidak muncul di registry | Salah REGISTRY_URL di config |
bq --config → verifikasi, lalu bq --init --force |
bq --version tidak berubah setelah upgrade |
pipx cache | pipx install --force build-q |
🚀 Development & Release
Ada dua cara rilis: (A) via GitHub Actions otomatis dari tag — direkomendasikan, dan (B) via Makefile lokal — cocok untuk hotfix/debug.
A. Auto-release via GitHub Actions (rekomendasi)
Workflow .github/workflows/pypi-release.yml dipicu oleh push tag v* (atau manual via workflow_dispatch) dan otomatis build + upload ke PyPI.
Flow rilis versi berikutnya:
# 1. Bump versi (patch) — auto-update pyproject.toml + build_q/__init__.py
python3 scripts/bump_version.py # bump patch (0.1.12 → 0.1.13)
# atau versi eksplisit:
python3 scripts/bump_version.py 0.2.0
# 2. Baca versi baru
VER=$(grep -m1 '^version = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')
echo "Releasing v$VER"
# 3. Commit bump
git add pyproject.toml build_q/__init__.py
git commit -m "release: v$VER"
# 4. Tag + push (tag inilah yang memicu workflow)
git tag "v$VER"
git push origin main "v$VER"
# 5. Pantau workflow
gh run watch --repo mamatnurahmat/build-q --exit-status
# atau lihat di browser:
gh run list --workflow=pypi-release.yml --repo mamatnurahmat/build-q --limit 3
Setelah workflow selesai (± 15 detik), package tersedia di:
- https://pypi.org/project/build-q//
- Upgrade user:
pipx upgrade build-q
Apa yang dilakukan workflow (lihat .github/workflows/pypi-release.yml):
- Checkout repo pada commit tag.
- Setup Python 3.12.
- Verifikasi tag — pastikan
v<X>cocok dengan version dipyproject.tomldanbuild_q/__init__.py. Bila mismatch, gagal (mencegah rilis "kosong"). - Install
build+twine. - Build sdist + wheel via
python -m build. - Validate dengan
twine check dist/*. - Upload via
twine upload --skip-existing— kalau versi sudah ada di PyPI, aman skip (idempoten). - Summary dengan link PyPI.
Autentikasi: workflow pakai GitHub Actions secret PYPI_API_TOKEN (username __token__). Token PyPI project-scoped ini di-set sekali via gh secret set. Cara set/rotate token:
# Metode andal — pakai env-file (JANGAN pakai --body - karena pipe stdin
# rawan corrupt untuk token panjang).
TMPFILE=$(mktemp) && chmod 600 "$TMPFILE"
python3 -c "
import configparser, os
c = configparser.ConfigParser()
c.read(os.path.expanduser('~/.pypirc'))
print('PYPI_API_TOKEN=' + c['pypi']['password'])
" > "$TMPFILE"
gh secret set -f "$TMPFILE" --repo mamatnurahmat/build-q
rm -f "$TMPFILE"
# Verifikasi:
gh secret list --repo mamatnurahmat/build-q
Manual trigger tanpa tag (misal untuk re-upload versi yang sudah ada di pyproject.toml — --skip-existing akan handle):
gh workflow run pypi-release.yml --repo mamatnurahmat/build-q
Cek/re-run workflow yang gagal:
gh run list --workflow=pypi-release.yml --repo mamatnurahmat/build-q --limit 5
gh run view <RUN_ID> --repo mamatnurahmat/build-q --log-failed
gh run rerun <RUN_ID> --failed --repo mamatnurahmat/build-q
B. Release manual via Makefile (lokal)
Cocok untuk hotfix cepat / troubleshoot. Baca kredensial dari ~/.pypirc lokal.
make build # build sdist + wheel ke dist/
make install # install lokal (pipx editable)
make release # bump patch, build, install, upload ke PyPI
make release V=1.0.0 # release versi spesifik
make clean # bersihkan artefak
Langkah make release:
scripts/bump_version.pybump patch dipyproject.toml+build_q/__init__.py.- Build sdist + wheel via
python3 -m build(fallback:pipx run --spec build pyproject-build). - Install lokal editable via
pipx install -e . --force. - Upload ke PyPI via
pipx run twine upload --skip-existing dist/*— kredensial dari~/.pypirc.
⚠️ Setelah
make release, jangan lupa commit + tag + push supaya history Git & GitHub Actions selaras dengan PyPI:VER=$(grep -m1 '^version = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/') git add pyproject.toml build_q/__init__.py git commit -m "release: v$VER" git tag "v$VER" && git push origin main "v$VER"Tag push tetap akan memicu workflow, tapi karena
--skip-existing, upload akan skip (idempoten).
Release troubleshooting
| Gejala | Penyebab | Solusi |
|---|---|---|
| Workflow gagal di step Verify tag matches | Tag v0.1.13 tapi pyproject.toml masih 0.1.12 |
Jalankan python3 scripts/bump_version.py 0.1.13 dulu, commit, re-tag |
Workflow gagal 403 Forbidden di upload |
Secret PYPI_API_TOKEN corrupt / kadaluwarsa |
Re-set secret via metode env-file di atas |
PyPI 400 File already exists |
Versi sudah pernah di-upload dari lokal | Sudah di-handle --skip-existing — workflow tetap hijau |
| Version di PyPI tidak berubah setelah tag | Tag lama di-hapus & re-push versi sama | PyPI TIDAK menerima re-upload versi yang sama — bump patch dulu |
📄 License
MIT
Metadata
Release files for build-q 0.1.50
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| build_q-0.1.50.tar.gz | 251.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| build_q-0.1.50-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 459.8 kB
Release files / build_q-0.1.50.tar.gz
| Download URL | build_q-0.1.50.tar.gz |
|---|---|
| Size | 251.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
98c818d3f96470c175b339278d73b0734532a5215ce7f2886ad3f03586d1a1ff
|
|
BLAKE2b-256 checksum How to use checksums |
2e9bb696a2ba9b61bbdf1a27dbbcb910284cba4b9be2811f8b0ba6ecbcddcd3c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / build_q-0.1.50-py3-none-any.whl
| Download URL | build_q-0.1.50-py3-none-any.whl |
|---|---|
| Size | 208.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
636d5cd18135ab39e60eab9d897506f501ebbeebacddbc5f8e92efef1a0b7fd1
|
|
BLAKE2b-256 checksum How to use checksums |
aac3a039981ed38a0223b95caea488cf9b9313f9eb95fab8113399a950577bc6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|