forked from
mitchellh.com/tack
Stitch any CI into Tangled
1# Buildkite
2
3For [Buildkite](https://buildkite.com), every Tangled pipeline trigger
4fans out into one Buildkite build per workflow on the pipeline that
5workflow configures. Buildkite must be configured with a webhook
6back to Tack to communicate status updates.
7
8## Setting up Buildkite
9
10This must happen before configuring tack within Buildkite.
11
12### 1. Create one or more pipelines
13
14In your Buildkite org, **Pipelines → New pipeline**:
15
16* Repository: any URL (the agent only needs to be able to clone it).
17* Steps: whatever you want.
18
19Note the pipeline slug from the URL
20(`https://buildkite.com/<org>/<pipeline-slug>`); your workflow YAML
21will reference it.
22
23### 2. Create an API access token
24
25Tack uses a single API token to create builds, list jobs, and fetch
26logs. Generate one at
27<https://buildkite.com/user/api-access-tokens> with these scopes:
28
29| Scope | Used for |
30| ------------------- | ------------------------------------------------- |
31| `read_organizations`| Sanity-checking the configured org slug |
32| `write_builds` | `POST .../builds` when a Tangled trigger arrives |
33| `read_builds` | Resolving build → jobs for the `/logs` endpoint |
34| `read_build_logs` | Streaming job logs back to the Tangled appview |
35
36Restrict the token to the specific organization(s) tack will spawn
37into.
38
39### 3. Configure a notification webhook
40
41Builds report their state back to tack through Buildkite's
42notification service.
43
44In your Buildkite org, **Settings → Notification Services → Add →
45Webhook**:
46
47* **Webhook URL:** `https://<your-tack-host>/webhooks/buildkite`
48* **Token / Secret:** any high-entropy string. You'll set the same
49 value in `TACK_BUILDKITE_WEBHOOK_SECRET`.
50* **Events:** `build.scheduled`, `build.running`, `build.finished`
51 (job-level events are ignored).
52* **Pipelines:** the pipelines tack will fire builds on.
53
54Buildkite supports two header schemes for authenticating webhooks and
55Tack supports both:
56
57| Header scheme | `TACK_BUILDKITE_WEBHOOK_MODE` | Notes |
58| ----------------------- | ----------------------------- | -------------------------------------------- |
59| `X-Buildkite-Token` | `token` (default) | Secret is sent verbatim in the header |
60| `X-Buildkite-Signature` | `signature` | HMAC-SHA256 of `<timestamp>.<body>`; safer |
61
62## Configure Tack
63
64| Env var | Description |
65| ------------------------------- | ------------------------------------------------------------------------------ |
66| `TACK_BUILDKITE_TOKEN` | Buildkite API token (enables Buildkite mode) |
67| `TACK_BUILDKITE_ORG` | Default Buildkite organization slug (workflows may override via YAML) |
68| `TACK_BUILDKITE_WEBHOOK_SECRET` | Shared secret for `/webhooks/buildkite` auth |
69| `TACK_BUILDKITE_WEBHOOK_MODE` | `token` (default) or `signature` — must match the notification service |
70
71The pipeline a workflow runs against is **not** an environment
72variable. It lives inside the workflow YAML so each repo can target
73its own pipeline without an operator round-trip.
74
75## Configuring your Tangled workflows
76
77Tack's configuration lives under a `tack:` namespace so the workflow body
78can grow other top-level keys without colliding.
79
80Only `pipeline` is required:
81
82```yaml
83tack:
84 buildkite:
85 # Required: which Buildkite pipeline this workflow fires.
86 pipeline: my-pipeline-slug
87
88 # Optional: org override. Defaults to TACK_BUILDKITE_ORG. The
89 # API token must have access to whichever org you target.
90 org: another-org
91
92 # Optional: forwarded verbatim to the Buildkite create-build
93 # API. Omit to use Buildkite's default (false).
94 clean_checkout: true
95```
96
97When the trigger is a pull request, tack auto-populates Buildkite's
98`pull_request_base_branch` from the PR target so step-level branch
99filters work without extra config.
100
101### What tack injects into every build
102
103Regardless of what the workflow YAML adds on top, tack always
104provides the following so your Buildkite pipeline can recover the
105Tangled identity of the build:
106
107| Channel | Key | Value |
108| ----------- | -------------------- | ---------------------------------------- |
109| `env` | `TACK_KNOT` | knot hostname the pipeline came from |
110| `env` | `TACK_PIPELINE_RKEY` | rkey of the originating pipeline record |
111| `env` | `TACK_WORKFLOW` | workflow name (typically a YAML filename) |
112| `env` | `TACK_WORKFLOW_RAW` | the workflow's raw YAML body |
113| `meta_data` | `tack:knot` | same as `TACK_KNOT` |
114| `meta_data` | `tack:pipeline_rkey` | same as `TACK_PIPELINE_RKEY` |
115| `meta_data` | `tack:workflow` | same as `TACK_WORKFLOW` |
116
117A common pattern is for the Buildkite pipeline's root step to do a
118`pipeline upload` against a workflow-specific YAML file based on
119`$TACK_WORKFLOW`, e.g.:
120
121```yaml
122# Buildkite pipeline.yml
123steps:
124 - label: ":pipeline: dispatch ${TACK_WORKFLOW}"
125 command: "buildkite-agent pipeline upload .buildkite/${TACK_WORKFLOW}"
126```