Skip to content

Commit b5db80a

Browse files
authored
Add skill to generate configuration (#14)
* Add skill to generate configuration * More improvements to skill + adjust README
1 parent e466533 commit b5db80a

8 files changed

Lines changed: 494 additions & 1 deletion

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`

examples/circleci-continuous.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Linear Release — CircleCI (Continuous Pipeline)
2+
#
3+
# Use when: Every deployment creates a completed release automatically.
4+
# Trigger: On every push to main.
5+
# Customize: Branch name, path filters (--include-paths).
6+
# Note: Set LINEAR_ACCESS_KEY in CircleCI project settings.
7+
8+
version: 2.1
9+
10+
jobs:
11+
linear-release-sync:
12+
docker:
13+
- image: cimg/base:current
14+
steps:
15+
- checkout
16+
- run:
17+
name: Download Linear Release
18+
command: |
19+
curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
20+
chmod +x linear-release
21+
- run:
22+
name: Sync release
23+
command: ./linear-release sync
24+
25+
workflows:
26+
release:
27+
jobs:
28+
- linear-release-sync:
29+
filters:
30+
branches:
31+
only: main

examples/circleci-scheduled.yml

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Linear Release — CircleCI (Scheduled)
2+
#
3+
# Use when: Releases follow a branch cut model. Main syncs without a version,
4+
# release branches derive version from CIRCLE_BRANCH.
5+
#
6+
# Trigger: Auto on push, API trigger for later stage transitions and completion.
7+
# Customize: Branch patterns, stage names, auto-promotion stage.
8+
# Note: Set LINEAR_ACCESS_KEY and CIRCLE_TOKEN in CircleCI project settings.
9+
#
10+
# Branch creation detection: CircleCI has no built-in signal, so auto-promotion
11+
# checks the API for previous pipelines on the branch.
12+
#
13+
# Monorepo: CircleCI doesn't support path filtering natively. Use the `path-filtering`
14+
# orb or split into separate workflows and use the API to conditionally trigger.
15+
16+
version: 2.1
17+
18+
# Pipeline parameters — passed via CircleCI API for manual stage transitions.
19+
# On normal pushes, defaults apply and only the sync workflows run.
20+
parameters:
21+
run-release-action:
22+
type: boolean
23+
default: false
24+
action:
25+
type: enum
26+
enum: ["update", "complete"]
27+
default: "update"
28+
stage:
29+
type: string
30+
default: ""
31+
release_version:
32+
type: string
33+
default: ""
34+
35+
jobs:
36+
linear-release-sync-main:
37+
docker:
38+
- image: cimg/base:current
39+
steps:
40+
- checkout
41+
- run:
42+
name: Download Linear Release
43+
command: |
44+
curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
45+
chmod +x linear-release
46+
- run:
47+
name: Sync release
48+
command: ./linear-release sync
49+
50+
linear-release-sync-release:
51+
docker:
52+
- image: cimg/base:current
53+
steps:
54+
- checkout
55+
- run:
56+
name: Download Linear Release
57+
command: |
58+
curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
59+
chmod +x linear-release
60+
- run:
61+
name: Derive version and sync
62+
command: |
63+
RELEASE_VERSION="${CIRCLE_BRANCH#release/}"
64+
./linear-release sync --release-version="$RELEASE_VERSION"
65+
- run:
66+
name: Auto-promote on branch creation
67+
command: |
68+
RELEASE_VERSION="${CIRCLE_BRANCH#release/}"
69+
# Check if this is the first pipeline on this branch (branch creation)
70+
PIPELINE_COUNT=$(curl -s -H "Circle-Token: $CIRCLE_TOKEN" \
71+
"https://circleci.com/api/v2/project/gh/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pipeline?branch=$CIRCLE_BRANCH" \
72+
| jq '.items | length')
73+
if [ "$PIPELINE_COUNT" -le 1 ]; then
74+
./linear-release update --release-version="$RELEASE_VERSION" --stage="code freeze"
75+
fi
76+
77+
linear-release-action:
78+
docker:
79+
- image: cimg/base:current
80+
steps:
81+
- checkout
82+
- run:
83+
name: Download Linear Release
84+
command: |
85+
curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
86+
chmod +x linear-release
87+
- run:
88+
name: Run release action
89+
command: |
90+
case "<< pipeline.parameters.action >>" in
91+
update)
92+
./linear-release update \
93+
--release-version="<< pipeline.parameters.release_version >>" \
94+
--stage="<< pipeline.parameters.stage >>"
95+
;;
96+
complete)
97+
./linear-release complete \
98+
--release-version="<< pipeline.parameters.release_version >>"
99+
;;
100+
esac
101+
102+
workflows:
103+
# On normal pushes — sync issues to the release
104+
release-sync-main:
105+
when:
106+
not: << pipeline.parameters.run-release-action >>
107+
jobs:
108+
- linear-release-sync-main:
109+
filters:
110+
branches:
111+
only: main
112+
113+
release-sync-release:
114+
when:
115+
not: << pipeline.parameters.run-release-action >>
116+
jobs:
117+
- linear-release-sync-release:
118+
filters:
119+
branches:
120+
only: /^release\/.*/
121+
122+
# Trigger via CircleCI API:
123+
# curl -X POST https://circleci.com/api/v2/project/gh/ORG/REPO/pipeline \
124+
# -H "Circle-Token: $CIRCLE_TOKEN" -H "Content-Type: application/json" \
125+
# -d '{"parameters": {"run-release-action": true, "action": "update", "stage": "qa", "release_version": "1.2.0"}}'
126+
release-action:
127+
when: << pipeline.parameters.run-release-action >>
128+
jobs:
129+
- linear-release-action
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Linear Release — GitHub Actions (Continuous Pipeline)
2+
#
3+
# Use when: Every deployment creates a completed release automatically.
4+
# Trigger: On every push to main.
5+
# Customize: Branch name, path filters (include_paths input).
6+
7+
name: Linear Release
8+
on:
9+
push:
10+
branches: [main]
11+
12+
jobs:
13+
linear-release:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- uses: linear/linear-release-action@v0
21+
with:
22+
access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Linear Release — GitHub Actions (Scheduled)
2+
#
3+
# Use when: Releases follow a branch cut model. Main collects changes into the
4+
# current release, a release branch is cut for stabilization, and branch creation
5+
# auto-promotes to "code freeze".
6+
#
7+
# Trigger: push to main (sync), push to release/* (sync + auto code freeze on
8+
# creation), or manual workflow_dispatch for later stages and completion.
9+
# Customize: Branch patterns, stage names, version derivation.
10+
#
11+
# Monorepo: GitHub Actions `paths` applies to all branches in a push trigger.
12+
# To path-filter main without filtering release branches, split into two files:
13+
# File 1 (main): add `paths: [...]` to the push trigger, keep only the main sync step.
14+
# File 2 (release): keep the release branch + workflow_dispatch logic as-is.
15+
# Add `include_paths` to the action in both files.
16+
17+
name: Linear Release
18+
on:
19+
push:
20+
branches:
21+
- main
22+
- "release/**"
23+
workflow_dispatch:
24+
inputs:
25+
action:
26+
description: "Release action"
27+
required: true
28+
type: choice
29+
options:
30+
- update
31+
- complete
32+
stage:
33+
description: "Release stage (for update, e.g. qa)"
34+
required: false
35+
type: string
36+
release_version:
37+
description: "Release version"
38+
required: true
39+
type: string
40+
41+
jobs:
42+
linear-release:
43+
runs-on: ubuntu-latest
44+
steps:
45+
- uses: actions/checkout@v4
46+
with:
47+
fetch-depth: 0
48+
49+
# Main branch: sync without --release-version (targets current started release)
50+
- uses: linear/linear-release-action@v0
51+
if: github.event_name == 'push' && !startsWith(github.ref_name, 'release/')
52+
with:
53+
access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
54+
55+
# Release branch: derive version from branch name
56+
- name: Set release version
57+
if: github.event_name == 'push' && startsWith(github.ref_name, 'release/')
58+
run: echo "RELEASE_VERSION=${GITHUB_REF_NAME#release/}" >> "$GITHUB_ENV"
59+
60+
# Release branch: sync with explicit version
61+
- uses: linear/linear-release-action@v0
62+
if: github.event_name == 'push' && startsWith(github.ref_name, 'release/')
63+
with:
64+
access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
65+
release_version: ${{ env.RELEASE_VERSION }}
66+
67+
# Branch creation: auto-promote to code freeze
68+
- uses: linear/linear-release-action@v0
69+
if: github.event_name == 'push' && startsWith(github.ref_name, 'release/') && github.event.created
70+
with:
71+
access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
72+
action: update
73+
stage: code freeze
74+
release_version: ${{ env.RELEASE_VERSION }}
75+
76+
# Manual: run the specified action (later stages, completion)
77+
- uses: linear/linear-release-action@v0
78+
if: github.event_name == 'workflow_dispatch'
79+
with:
80+
access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
81+
action: ${{ inputs.action }}
82+
stage: ${{ inputs.stage }}
83+
release_version: ${{ inputs.release_version }}

examples/gitlab-ci-continuous.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Linear Release — GitLab CI (Continuous Pipeline)
2+
#
3+
# Use when: Every deployment creates a completed release automatically.
4+
# Trigger: On every push to the default branch.
5+
# Customize: Branch rules, path filters (--include-paths).
6+
7+
.linear-release-setup: &linear-release-setup
8+
before_script:
9+
- curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
10+
- chmod +x linear-release
11+
12+
linear-release-sync:
13+
<<: *linear-release-setup
14+
stage: deploy
15+
script:
16+
- ./linear-release sync
17+
variables:
18+
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
19+
GIT_DEPTH: 0
20+
rules:
21+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

examples/gitlab-ci-scheduled.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Linear Release — GitLab CI (Scheduled)
2+
#
3+
# Use when: Releases follow a branch cut model. Main syncs without a version,
4+
# release branches derive version from branch name. Branch creation auto-promotes
5+
# to "code freeze" (detected via CI_COMMIT_BEFORE_SHA being all zeros).
6+
#
7+
# Trigger: Auto on push, manual for later stage transitions and completion.
8+
# Customize: Branch patterns, stage names, version derivation.
9+
#
10+
# Monorepo: Add `changes` filter to the main job's rules only (not release branch jobs):
11+
# rules:
12+
# - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
13+
# changes:
14+
# - "apps/mobile/**"
15+
# - "packages/shared/**"
16+
# Also add --include-paths to all sync commands.
17+
18+
.linear-release-setup: &linear-release-setup
19+
before_script:
20+
- curl -sL https://github.com/linear/linear-release/releases/latest/download/linear-release-linux-x64 -o linear-release
21+
- chmod +x linear-release
22+
23+
# Main branch: sync without --release-version (targets current started release)
24+
linear-release-sync-main:
25+
<<: *linear-release-setup
26+
stage: deploy
27+
script:
28+
- ./linear-release sync
29+
variables:
30+
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
31+
GIT_DEPTH: 0
32+
rules:
33+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
34+
35+
# Release branch: derive version from branch name and sync
36+
linear-release-sync-release:
37+
<<: *linear-release-setup
38+
stage: deploy
39+
script:
40+
- export RELEASE_VERSION="${CI_COMMIT_BRANCH#release/}"
41+
- ./linear-release sync --release-version="$RELEASE_VERSION"
42+
# Auto-promote on branch creation (first push to a new branch)
43+
- |
44+
if [ "$CI_COMMIT_BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then
45+
./linear-release update --release-version="$RELEASE_VERSION" --stage="code freeze"
46+
fi
47+
variables:
48+
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
49+
GIT_DEPTH: 0
50+
rules:
51+
- if: $CI_COMMIT_BRANCH =~ /^release\//
52+
53+
# Trigger manually for later stage transitions and completion
54+
linear-release-update:
55+
<<: *linear-release-setup
56+
stage: deploy
57+
script:
58+
- export RELEASE_VERSION="${CI_COMMIT_BRANCH#release/}"
59+
- ./linear-release update --release-version="$RELEASE_VERSION" --stage="$STAGE"
60+
variables:
61+
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
62+
STAGE: ""
63+
GIT_DEPTH: 0
64+
rules:
65+
- if: $CI_COMMIT_BRANCH =~ /^release\//
66+
when: manual
67+
68+
linear-release-complete:
69+
<<: *linear-release-setup
70+
stage: deploy
71+
script:
72+
- export RELEASE_VERSION="${CI_COMMIT_BRANCH#release/}"
73+
- ./linear-release complete --release-version="$RELEASE_VERSION"
74+
variables:
75+
LINEAR_ACCESS_KEY: $LINEAR_ACCESS_KEY
76+
GIT_DEPTH: 0
77+
rules:
78+
- if: $CI_COMMIT_BRANCH =~ /^release\//
79+
when: manual

0 commit comments

Comments
 (0)