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
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ linear-release complete

# Completes the release with the specified version
linear-release complete --release-version="1.2.0"

# Sets a custom name when completing the release
linear-release complete --name="Release 1.2.0"
```

### `update`
Expand All @@ -131,6 +134,9 @@ linear-release update --stage="in review"

# Updates the release with the specified version
linear-release update --stage="in review" --release-version="1.2.0"

# Sets a custom name when updating the release
linear-release update --stage="in review" --name="Release 1.2.0"
```

## Configuration
Expand All @@ -143,16 +149,16 @@ linear-release update --stage="in review" --release-version="1.2.0"

### CLI Options

| Option | Commands | Description |
| ------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name` | `sync` | Custom release name. Whenever `sync` is called with `--name`, the value is applied to the targeted release — both newly created releases and existing ones get the provided name. Ignored (with warning) for `complete` and `update`. |
| `--release-version` | `sync`, `complete`, `update` | Release version identifier. For `sync`, defaults to short commit hash. For `complete` and `update`, if omitted, targets the most recent started release. |
| `--stage` | `update` | Target deployment stage (required for `update`) |
| `--include-paths` | `sync` | Filter commits by changed file paths |
| `--json` | `sync`, `complete`, `update` | Output result as JSON |
| `--quiet` | `sync`, `complete`, `update` | Only print errors |
| `--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`, if omitted, targets the most recent started release. |
| `--stage` | `update` | Target deployment stage (required for `update`) |
| `--include-paths` | `sync` | Filter commits by changed file paths |
| `--json` | `sync`, `complete`, `update` | Output result as JSON |
| `--quiet` | `sync`, `complete`, `update` | Only print errors |
| `--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 @@ -216,7 +222,6 @@ Path patterns can also be configured in your pipeline settings in Linear. If bot
- **Unexpected release was updated/completed**: pass `--release-version` explicitly so the command does not target the latest started/planned release.
- **No release created by `sync`**: if no commits match the computed range (or path filters), `sync` returns `{"release":null}`.
- **Stage update fails**: verify stage name exactly. If stage names normalize to the same value, use the exact stage name to avoid ambiguity.
- **`--name` seems ignored**: `--name` only applies to `sync`; `complete` and `update` ignore it and print a warning.
- **Operation timed out**: the CLI aborts after 60 seconds by default. For large repositories or slow networks, increase the limit with `--timeout=120`.

## License
Expand Down
8 changes: 4 additions & 4 deletions src/args.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ describe("parseCLIArgs", () => {
expect(() => parseCLIArgs(["--unknown-flag"])).toThrow();
});

it("returns warning when --name is used with update", () => {
it("returns no warning when --name is used with update", () => {
const result = parseCLIArgs(["update", "--name", "Release 1.2.0"]);
expect(getCLIWarnings(result)).toEqual(['--name is ignored for "update" command; it only applies to "sync"']);
expect(getCLIWarnings(result)).toEqual([]);
});

it("returns warning when --name is used with complete", () => {
it("returns no warning when --name is used with complete", () => {
const result = parseCLIArgs(["complete", "--name", "Release 1.2.0"]);
expect(getCLIWarnings(result)).toEqual(['--name is ignored for "complete" command; it only applies to "sync"']);
expect(getCLIWarnings(result)).toEqual([]);
});

it("returns no warning when --name is used with sync", () => {
Expand Down
10 changes: 2 additions & 8 deletions src/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@ export function parseCLIArgs(argv: string[]): ParsedCLIArgs {
};
}

export function getCLIWarnings(args: ParsedCLIArgs): string[] {
const warnings: string[] = [];

if (args.releaseName && args.command !== "sync") {
warnings.push(`--name is ignored for "${args.command}" command; it only applies to "sync"`);
}

return warnings;
export function getCLIWarnings(_args: ParsedCLIArgs): string[] {
return [];
}
28 changes: 19 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Commands:
update Update the deployment stage of a release

Options:
--name=<name> Custom release name (sync only)
--name=<name> Custom release name
--release-version=<version> Release version identifier
--stage=<stage> Deployment stage (required for update)
--include-paths=<paths> Filter commits by file paths (comma-separated globs)
Expand Down Expand Up @@ -87,9 +87,7 @@ if (jsonOutput) {

const logEnvironmentSummary = () => {
if (releaseName) {
if (command === "sync") {
info(`Using custom release name: ${releaseName}`);
}
info(`Using custom release name: ${releaseName}`);
}
if (releaseVersion) {
info(`Using custom release version: ${releaseVersion}`);
Expand Down Expand Up @@ -246,6 +244,7 @@ async function completeCommand(): Promise<{
const commitSha = currentCommit.commit;

const result = await completeRelease({
name: releaseName,
version: releaseVersion,
commitSha,
});
Expand Down Expand Up @@ -283,6 +282,7 @@ async function updateCommand(): Promise<{
result = await updateReleaseByPipeline({
stage: stageName,
version: releaseVersion,
name: releaseName,
});
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
Expand Down Expand Up @@ -430,11 +430,15 @@ async function syncRelease(
return response.data.releaseSyncByAccessKey.release;
}

async function completeRelease(options: { version?: string | null; commitSha?: string | null }): Promise<{
async function completeRelease(options: {
name?: string | null;
version?: string | null;
commitSha?: string | null;
}): Promise<{
success: boolean;
release: { id: string; name: string; version?: string; url?: string } | null;
}> {
const { version, commitSha } = options;
const { name, version, commitSha } = options;

const response = await apiRequest<AccessKeyCompleteReleaseResponse>(
`
Expand All @@ -452,6 +456,7 @@ async function completeRelease(options: { version?: string | null; commitSha?: s
`,
{
input: {
name,
version,
commitSha,
},
Expand All @@ -461,7 +466,11 @@ async function completeRelease(options: { version?: string | null; commitSha?: s
return response.data.releaseCompleteByAccessKey;
}

async function updateReleaseByPipeline(options: { stage?: string; version?: string | null }): Promise<{
async function updateReleaseByPipeline(options: {
stage?: string;
version?: string | null;
name?: string | null;
}): Promise<{
success: boolean;
release: {
id: string;
Expand All @@ -471,11 +480,12 @@ async function updateReleaseByPipeline(options: { stage?: string; version?: stri
stageName: string;
} | null;
}> {
const { stage, version } = options;
const { stage, version, name } = options;
const versionInput = version ? `, version: "${version}"` : "";
const stageInput = stage ? `, stage: "${stage}"` : "";
const nameInput = name ? `, name: "${name}"` : "";

const inputParts = [versionInput, stageInput]
const inputParts = [versionInput, stageInput, nameInput]
.filter(Boolean)
.map((s) => s.slice(2))
.join(", ");
Expand Down
Loading