Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 35 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,26 +163,27 @@ The provider is detected from the remote hostname, or on GitLab CI from the job

### CLI Options

| Option | Commands | Description |
| ---------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name` | `sync`, `complete`, `update` | Custom release name. For `sync`, the value is applied to the targeted release — both newly created releases and existing ones get the provided name. For `complete` and `update`, sets the name on the targeted release. |
| `--release-version` | `sync`, `complete`, `update` | Release version identifier. For `sync`, defaults to short commit hash. For `complete` and `update`, selects an existing release with that version (errors if none exists); does not change a release's version. If omitted, targets the most recent started release. |
| `--description` | `sync`, `complete`, `update` | Release description. Pass an empty string to clear an existing description. |
| `--stage` | `update` | Target deployment stage (required for `update`) |
| `--include-paths` | `sync` | Filter commits by changed file paths |
| `--include-subjects` | `sync` | Filter commits whose subject (first line) matches a regex |
| `--issue-pattern` | `sync` | Extract issue identifiers captured by group 1 from commit subjects |
| `--link` | `sync`, `complete`, `update` | Add a link to the targeted release. Use `--link "https://example.com"` or `--link "Label=https://example.com"`; repeat the flag to add multiple links. |
| `--document` | `sync`, `complete`, `update` | Attach a document. `--document "Title=...markdown..."`; repeat for multiple docs. Existing documents with the same title on the release are updated. |
| `--document-file` | `sync`, `complete`, `update` | Same as `--document` but reads the body from a file: `--document-file "Title=path/to/file.md"`. Use `-` to read from stdin. |
| `--release-notes` | `sync`, `complete`, `update` | Set the release notes for this release. Inline markdown. If combined with `--release-notes-file`, the last flag wins. |
| `--release-notes-file` | `sync`, `complete`, `update` | Same as `--release-notes` but reads from a file. Use `-` for stdin. |
| `--base-ref` | `sync` | Override the scan base. Exclusive: scans `<base-ref>..HEAD`. |
| `--json` | `sync`, `complete`, `update` | Output result as JSON on stdout. Logs are emitted as JSON Lines (one object per line) on stderr. |
| `--dry-run` | `sync`, `complete`, `update` | Scan commits and call read-only Linear APIs (e.g. recent releases, pipeline settings), but skip the create/update mutations. Logs the action that would have been taken. No release is created or modified. |
| `--quiet` | `sync`, `complete`, `update` | Suppress info-level output. Warnings and errors are still printed. |
| `--verbose` | `sync`, `complete`, `update` | Print detailed progress including debug diagnostics |
| `--timeout` | `sync`, `complete`, `update` | Max duration in seconds before aborting (default: 60) |
| Option | Commands | Description |
| --------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name` | `sync`, `complete`, `update` | Custom release name. For `sync`, the value is applied to the targeted release — both newly created releases and existing ones get the provided name. For `complete` and `update`, sets the name on the targeted release. |
| `--release-version` | `sync`, `complete`, `update` | Release version identifier. For `sync`, defaults to short commit hash. For `complete` and `update`, selects an existing release with that version (errors if none exists); does not change a release's version. If omitted, targets the most recent started release. |
| `--description` | `sync`, `complete`, `update` | Release description. Pass an empty string to clear an existing description. |
| `--stage` | `update` | Target deployment stage (required for `update`) |
| `--include-paths` | `sync` | Filter commits by changed file paths |
| `--include-subjects` | `sync` | Filter commits whose subject (first line) matches a regex |
| `--issue-pattern` | `sync` | Extract issue identifiers captured by group 1 from commit subjects |
| `--no-branch-ref-detection` | `sync` | Disable issue attribution from Git branch refs; keep commit-message and PR/MR detection |
| `--link` | `sync`, `complete`, `update` | Add a link to the targeted release. Use `--link "https://example.com"` or `--link "Label=https://example.com"`; repeat the flag to add multiple links. |
| `--document` | `sync`, `complete`, `update` | Attach a document. `--document "Title=...markdown..."`; repeat for multiple docs. Existing documents with the same title on the release are updated. |
| `--document-file` | `sync`, `complete`, `update` | Same as `--document` but reads the body from a file: `--document-file "Title=path/to/file.md"`. Use `-` to read from stdin. |
| `--release-notes` | `sync`, `complete`, `update` | Set the release notes for this release. Inline markdown. If combined with `--release-notes-file`, the last flag wins. |
| `--release-notes-file` | `sync`, `complete`, `update` | Same as `--release-notes` but reads from a file. Use `-` for stdin. |
| `--base-ref` | `sync` | Override the scan base. Exclusive: scans `<base-ref>..HEAD`. |
| `--json` | `sync`, `complete`, `update` | Output result as JSON on stdout. Logs are emitted as JSON Lines (one object per line) on stderr. |
| `--dry-run` | `sync`, `complete`, `update` | Scan commits and call read-only Linear APIs (e.g. recent releases, pipeline settings), but skip the create/update mutations. Logs the action that would have been taken. No release is created or modified. |
| `--quiet` | `sync`, `complete`, `update` | Suppress info-level output. Warnings and errors are still printed. |
| `--verbose` | `sync`, `complete`, `update` | Print detailed progress including debug diagnostics |
| `--timeout` | `sync`, `complete`, `update` | Max duration in seconds before aborting (default: 60) |

### Command Targeting

Expand Down Expand Up @@ -269,6 +270,20 @@ linear-release sync --issue-pattern='\b([A-Z]+-\d+)\b'

Identifiers that do not exist in the workspace are ignored server-side, so the broad recipe is safe but can be noisy (for example, it also matches `UTF-8`). Reverting a commit whose issues were linked only through `--issue-pattern` does not un-link them, just as with the built-in subject patterns.

### Disable branch ref detection

By default, `sync` can extract issue identifiers from Git branch refs pointing at regular commits in the scan. Those refs can include unrelated branches created from shipped commits without any new work.

Use `--no-branch-ref-detection` to ignore these refs:

```bash
linear-release sync --no-branch-ref-detection
```

Issue identifiers in commit messages, source branches recorded in merge messages, PR/MR references, and `--issue-pattern` detection remain enabled. The flag applies to both added and reverted issue attribution.

This disables all attribution from branch refs, including legitimate fast-forward merges whose issue key exists only in the branch name. Those workflows need an issue identifier in the commit message or a PR/MR reference that Linear can resolve. Omitting the flag preserves existing behavior.

### Release Links

`--link` attaches external URLs to the release — a GitHub release page, a CI run, a deployment dashboard.
Expand Down
5 changes: 5 additions & 0 deletions src/args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ describe("parseCLIArgs", () => {
expect(parseCLIArgs([]).issuePattern).toBeNull();
});

it("detects branch refs by default and allows opting out", () => {
expect(parseCLIArgs([]).detectBranchRefs).toBe(true);
expect(parseCLIArgs(["sync", "--no-branch-ref-detection"]).detectBranchRefs).toBe(false);
});

it("returns --issue-pattern as the raw pattern string", () => {
expect(parseCLIArgs(["--issue-pattern", "\\[([A-Z]+-\\d+)\\]"]).issuePattern).toBe("\\[([A-Z]+-\\d+)\\]");
});
Expand Down
3 changes: 3 additions & 0 deletions src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type ParsedCLIArgs = {
includePaths: string[];
includeSubjects: string | null;
issuePattern: string | null;
detectBranchRefs: boolean;
links: ReleaseLink[];
documents: ReleaseDocumentSpec[];
releaseNotes?: ReleaseNoteSpec;
Expand Down Expand Up @@ -137,6 +138,7 @@ export function parseCLIArgs(argv: string[]): ParsedCLIArgs {
"include-paths": { type: "string" },
"include-subjects": { type: "string" },
"issue-pattern": { type: "string" },
"no-branch-ref-detection": { type: "boolean", default: false },
link: { type: "string", multiple: true },
document: { type: "string", multiple: true },
"document-file": { type: "string", multiple: true },
Expand Down Expand Up @@ -249,6 +251,7 @@ export function parseCLIArgs(argv: string[]): ParsedCLIArgs {
: [],
includeSubjects,
issuePattern,
detectBranchRefs: !values["no-branch-ref-detection"],
links,
documents,
releaseNotes,
Expand Down
Loading
Loading