Skip to content

Commit 39773d5

Browse files
committed
More improvements to skill + adjust README
1 parent f8d2fb6 commit 39773d5

2 files changed

Lines changed: 110 additions & 56 deletions

File tree

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,15 @@ Linear Release is a CLI tool that integrates your CI/CD pipeline with [Linear's
2828
- Scans commits for Linear issue identifiers (e.g., `ENG-123`)
2929
- Detects pull request references in commit messages
3030
- Creates and updates releases in Linear
31-
- Tracks deployment stages (staging, production, etc.)
31+
- Tracks deployment stages for scheduled releases
32+
33+
## Pipeline Types
34+
35+
Linear Release supports two pipeline styles, configured in Linear:
36+
37+
**Continuous**: Every deployment creates a completed release. Use `sync` after each deploy — the release is created already completed.
38+
39+
**Scheduled**: An ongoing release collects changes over time, then moves through stages (e.g. "code freeze", "qa") before completion. Useful for release trains. Use `sync` to add issues, `update` to move between stages, and `complete` to finalize.
3240

3341
## Installation
3442

@@ -77,6 +85,10 @@ chmod +x linear-release
7785
LINEAR_ACCESS_KEY=<your-key> ./linear-release sync
7886
```
7987

88+
### AI-assisted setup
89+
90+
Use the [Linear Release setup skill](./skills/linear-release-setup/SKILL.md) to generate CI configuration tailored to your project. It supports GitHub Actions, GitLab CI, CircleCI, and other platforms, and walks you through continuous vs. scheduled pipelines, monorepo path filtering, and more.
91+
8092
## Commands
8193

8294
### `sync`

skills/linear-release-setup/SKILL.md

Lines changed: 97 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ Look for existing CI configuration files:
2929
Gather the following information (skip questions you can infer from the codebase):
3030

3131
1. **CI platform** — if not auto-detected, ask which platform they use
32-
2. **Pipeline type** — continuous (every merge creates a completed release) or scheduled (releases go through stages like staging → production)
32+
2. **Pipeline type** — continuous (every deploy creates a completed release) or scheduled (a release train where an ongoing release collects changes, then gets completed later)
3333
3. **Monorepo?** — if the repo has multiple apps/services, ask which paths to track (e.g. `apps/web/**`)
34-
4. **Deployment stages** — for scheduled pipelines, ask what stages they use (e.g. staging, production)
35-
5. **Release naming** — whether they want custom names/versions (e.g. `v1.2.0`) or the default (short commit SHA)
34+
35+
For scheduled pipelines, also ask:
36+
37+
4. **Branch model** — which branches trigger releases? Just `main`, or `main` + release branches (e.g. `release/*`)? This determines what branch patterns the CI workflow should trigger on.
38+
5. **Release versioning** — how do they version releases? Calendar-based (e.g. `2026.05`), semver (e.g. `1.2.0`), or default (short commit SHA)? And where does the version come from — a CI variable, a file in the repo, a git tag? This determines how `--release-version` gets passed to each command.
39+
6. **Release stages** — what stages do releases move through before completion (e.g. "code freeze", "qa")?
3640

3741
### Step 3: Generate the CI configuration
3842

@@ -46,34 +50,55 @@ Tell the user to add the `LINEAR_ACCESS_KEY` secret to their CI environment:
4650
- **GitLab CI**: Settings → CI/CD → Variables
4751
- **CircleCI**: Project Settings → Environment Variables
4852

49-
The access key is created in Linear under Settings → Releases → Pipelines.
53+
The access key is created in Linear from the pipeline's settings page. Each pipeline has its own access key.
5054

5155
## Key Concepts
5256

57+
### Release Pipelines
58+
59+
A **release pipeline** represents a deployment lane — e.g. "iOS", "Android", "Web", "EU Region". Each environment or product you ship independently should be its own pipeline. Pipelines are configured in Linear.
60+
5361
### Pipeline Types
5462

55-
**Continuous pipelines**: Every merge to the main branch creates a completed release. Use a single `sync` command — releases are created in the completed stage automatically.
63+
**Continuous pipelines**: Every successful deployment creates a new completed release automatically. Use a single `sync` command — the release is created in the completed stage.
64+
65+
Example: every merge to `main` triggers a deploy, and `sync` creates a completed release with all the issues from the new commits.
66+
67+
**Scheduled pipelines**: There's an ongoing "current" release that collects changes over time. You later move it through stages and complete it. Useful for release trains (e.g. monthly releases, mobile app releases with a review period).
68+
69+
- `sync` — adds issues to the current started release (or creates one)
70+
- `update --stage=<stage>` — moves the release to a stage (e.g. "code freeze", "qa")
71+
- `complete` — marks the release as done; Linear can then prepare the next started release
72+
73+
A typical scheduled flow follows a release branch cut: `main` collects changes into the next release, a release branch (e.g. `release/2026.05`) is cut for stabilization, and `main` switches to the next version. Always pass `--release-version` in scheduled pipelines so each branch targets the correct release.
74+
75+
### Release Stages
76+
77+
Stages are optional steps a release moves through in a **scheduled** pipeline. They represent phases of the release process, not deployment environments. Examples:
78+
79+
- "in progress" — actively collecting changes
80+
- "code freeze" — no more changes going in
81+
- "in review" — release is being tested/reviewed
82+
- "qa" — final quality assurance pass
5683

57-
**Scheduled pipelines**: Releases go through deployment stages (e.g. stagingproduction). Use multiple commands:
84+
Different deployment environments (staging, production) should be separate pipelines, not stages.
5885

59-
- `sync` — creates a release or adds issues to the current release
60-
- `update --stage=<stage>` — moves the release to a deployment stage
61-
- `complete` — marks the release as done
86+
Stages can be **frozen** in Linear. When a release is in a frozen stage, `sync` without an explicit `--release-version` will skip that release and target the next one instead. This acts as a safety net for code freezes: even if a merge lands while the release is frozen, the issues go into the next release. However, always prefer passing `--release-version` explicitly for predictable behavior — frozen stages are a fallback, not a substitute for explicit version targeting.
6287

6388
### Commands Reference
6489

6590
| Command | Purpose | Key flags |
6691
| ---------- | ---------------------------------- | ------------------------------------------------ |
6792
| `sync` | Create/update release from commits | `--name`, `--release-version`, `--include-paths` |
68-
| `update` | Move release to a deployment stage | `--stage` (required), `--release-version` |
93+
| `update` | Move release to a stage | `--stage` (required), `--release-version` |
6994
| `complete` | Mark release as complete | `--release-version` |
7095

7196
All commands support `--json` for structured output.
7297

7398
### Requirements
7499

75100
- **Full git history**: The checkout step must use `fetch-depth: 0` (or equivalent full clone) so Linear Release can scan commits between releases.
76-
- **`LINEAR_ACCESS_KEY`**: Pipeline access key from Linear, stored as a CI secret.
101+
- **`LINEAR_ACCESS_KEY`**: Per-pipeline access key from Linear, stored as a CI secret.
77102

78103
### Path Filtering (Monorepos)
79104

@@ -84,7 +109,7 @@ linear-release sync --include-paths="apps/mobile/**"
84109
linear-release sync --include-paths="apps/mobile/**,packages/shared/**"
85110
```
86111

87-
Patterns use Git pathspec glob syntax, relative to the repository root.
112+
Patterns use Git pathspec glob syntax, relative to the repository root. Path filters can also be configured in the pipeline settings in Linear. If both are set, the CLI `--include-paths` flag takes precedence.
88113

89114
## GitHub Actions Patterns
90115

@@ -115,11 +140,15 @@ jobs:
115140
116141
#### Scheduled Pipeline
117142
143+
Each branch must target the correct release version. A common pattern is to derive it from the branch name for release branches (e.g. `release/2026.05` → `2026.05`) and use a CI variable for `main`.
144+
118145
```yaml
119146
name: Linear Release
120147
on:
121148
push:
122-
branches: [main]
149+
branches:
150+
- main
151+
- "release/**"
123152
workflow_dispatch:
124153
inputs:
125154
action:
@@ -131,12 +160,12 @@ on:
131160
- update
132161
- complete
133162
stage:
134-
description: "Deployment stage (for update)"
163+
description: "Release stage (for update, e.g. code freeze)"
135164
required: false
136165
type: string
137166
release_version:
138-
description: "Release version (optional)"
139-
required: false
167+
description: "Release version"
168+
required: true
140169
type: string
141170
142171
jobs:
@@ -147,11 +176,22 @@ jobs:
147176
with:
148177
fetch-depth: 0
149178
150-
# On push: sync issues to the current release
179+
# Derive release version from branch name or CI variable
180+
- name: Set release version
181+
if: github.event_name == 'push'
182+
run: |
183+
if [[ "$GITHUB_REF_NAME" == release/* ]]; then
184+
echo "RELEASE_VERSION=${GITHUB_REF_NAME#release/}" >> "$GITHUB_ENV"
185+
else
186+
echo "RELEASE_VERSION=${{ vars.RELEASE_VERSION }}" >> "$GITHUB_ENV"
187+
fi
188+
189+
# On push: sync issues to the release for this branch
151190
- uses: linear/linear-release-action@v0
152191
if: github.event_name == 'push'
153192
with:
154193
access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
194+
release_version: ${{ env.RELEASE_VERSION }}
155195
156196
# Manual: run the specified action
157197
- uses: linear/linear-release-action@v0
@@ -203,17 +243,6 @@ jobs:
203243

204244
## GitLab CI Patterns
205245

206-
### Setup
207-
208-
All GitLab CI patterns use this base setup to download the binary:
209-
210-
```yaml
211-
.linear-release-setup: &linear-release-setup
212-
before_script:
213-
- curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
214-
- chmod +x linear-release
215-
```
216-
217246
### Continuous Pipeline
218247

219248
```yaml
@@ -236,50 +265,59 @@ linear-release-sync:
236265

237266
### Scheduled Pipeline
238267

268+
Set `RELEASE_VERSION` as a CI/CD variable per branch so `main` and release branches target different releases.
269+
239270
```yaml
240271
.linear-release-setup: &linear-release-setup
241272
before_script:
242273
- curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
243274
- chmod +x linear-release
244275
245-
# Runs on every merge to add issues to the current release
276+
# Runs on every merge to add issues to the release for this branch
246277
linear-release-sync:
247278
<<: *linear-release-setup
248279
stage: deploy
249280
script:
250-
- ./linear-release sync
281+
- ./linear-release sync --release-version="$RELEASE_VERSION"
251282
variables:
252283
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
253284
GIT_DEPTH: 0
254285
rules:
255286
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
287+
- if: $CI_COMMIT_BRANCH =~ /^release\//
256288
257-
# Trigger manually to move the release to a deployment stage
289+
# Trigger manually to move the release to a stage (e.g. "code freeze", "qa")
258290
linear-release-update:
259291
<<: *linear-release-setup
260292
stage: deploy
261293
script:
262-
- ./linear-release update --stage="$STAGE"
294+
- ./linear-release update --release-version="$RELEASE_VERSION" --stage="$STAGE"
263295
variables:
264296
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
297+
RELEASE_VERSION: ""
265298
STAGE: ""
266299
GIT_DEPTH: 0
267300
rules:
268301
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
269302
when: manual
303+
- if: $CI_COMMIT_BRANCH =~ /^release\//
304+
when: manual
270305
271306
# Trigger manually to complete the release
272307
linear-release-complete:
273308
<<: *linear-release-setup
274309
stage: deploy
275310
script:
276-
- ./linear-release complete
311+
- ./linear-release complete --release-version="$RELEASE_VERSION"
277312
variables:
278313
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
314+
RELEASE_VERSION: ""
279315
GIT_DEPTH: 0
280316
rules:
281317
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
282318
when: manual
319+
- if: $CI_COMMIT_BRANCH =~ /^release\//
320+
when: manual
283321
```
284322

285323
### With Path Filtering (Monorepo)
@@ -326,6 +364,8 @@ The `LINEAR_ACCESS_KEY` environment variable must be set in CircleCI project set
326364

327365
### Scheduled Pipeline
328366

367+
Pass `RELEASE_VERSION` as a pipeline parameter or environment variable so each branch targets the correct release.
368+
329369
```yaml
330370
version: 2.1
331371
@@ -342,14 +382,16 @@ jobs:
342382
chmod +x linear-release
343383
- run:
344384
name: Sync release
345-
command: ./linear-release sync
385+
command: ./linear-release sync --release-version="$RELEASE_VERSION"
346386
347387
linear-release-update:
348388
docker:
349389
- image: cimg/base:current
350390
parameters:
351391
stage:
352392
type: string
393+
release_version:
394+
type: string
353395
steps:
354396
- checkout
355397
- run:
@@ -359,11 +401,14 @@ jobs:
359401
chmod +x linear-release
360402
- run:
361403
name: Update release stage
362-
command: ./linear-release update --stage="<< parameters.stage >>"
404+
command: ./linear-release update --release-version="<< parameters.release_version >>" --stage="<< parameters.stage >>"
363405
364406
linear-release-complete:
365407
docker:
366408
- image: cimg/base:current
409+
parameters:
410+
release_version:
411+
type: string
367412
steps:
368413
- checkout
369414
- run:
@@ -373,35 +418,31 @@ jobs:
373418
chmod +x linear-release
374419
- run:
375420
name: Complete release
376-
command: ./linear-release complete
421+
command: ./linear-release complete --release-version="<< parameters.release_version >>"
377422
378423
workflows:
379-
# Sync on every push to main
424+
# Sync on every push to main or release branches
380425
release-sync:
381426
jobs:
382427
- linear-release-sync:
383428
filters:
384429
branches:
385-
only: main
430+
only:
431+
- main
432+
- /^release\/.*/
386433
387-
# Trigger stage updates and completion via CircleCI API
434+
# Trigger via CircleCI API with pipeline parameters for release_version and stage
388435
release-update:
389436
jobs:
390437
- linear-release-update:
391-
stage: staging
392-
- hold-production:
393-
type: approval
394-
requires:
395-
- linear-release-update
396-
- linear-release-update:
397-
stage: production
398-
requires:
399-
- hold-production
438+
stage: << pipeline.parameters.stage >>
439+
release_version: << pipeline.parameters.release_version >>
400440
- hold-complete:
401441
type: approval
402442
requires:
403443
- linear-release-update
404444
- linear-release-complete:
445+
release_version: << pipeline.parameters.release_version >>
405446
requires:
406447
- hold-complete
407448
```
@@ -420,16 +461,17 @@ chmod +x linear-release
420461
export LINEAR_ACCESS_KEY="<your-key>"
421462
422463
# 4. Run the appropriate command
423-
./linear-release sync # Continuous: on every merge
424-
./linear-release sync --name="v1.2.0" # With custom name
425-
./linear-release update --stage="staging" # Scheduled: move to stage
426-
./linear-release complete # Scheduled: finalize release
427-
./linear-release sync --include-paths="apps/web/**" # Monorepo: filter by path
464+
./linear-release sync # Continuous: on every deploy
465+
./linear-release sync --name="v1.2.0" # With custom name
466+
./linear-release sync --release-version="2026.05" # Scheduled: sync with explicit version
467+
./linear-release update --release-version="2026.05" --stage="code freeze" # Scheduled: move to a stage
468+
./linear-release complete --release-version="2026.05" # Scheduled: finalize release
469+
./linear-release sync --include-paths="apps/web/**" # Monorepo: filter by path
428470
```
429471

430472
### Checklist
431473

432474
- [ ] Full clone / `fetch-depth: 0` — shallow clones will miss commits between releases
433-
- [ ] `LINEAR_ACCESS_KEY` set as a secret environment variable
475+
- [ ] `LINEAR_ACCESS_KEY` set as a secret environment variable (one per pipeline)
434476
- [ ] Correct binary for the runner platform (`linux-x64`, `darwin-arm64`, or `darwin-x64`)
435-
- [ ] Runs on merges to the main/default branch
477+
- [ ] Triggers on the correct branches (`main` for continuous; `main` + `release/*` for scheduled)

0 commit comments

Comments
 (0)