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
2 changes: 2 additions & 0 deletions .github/workflows/release-prepare.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ concurrency:
jobs:
semantic-release:
runs-on: ubuntu-latest
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { runCli as runCliImpl } from "../../src/cli/run.ts";
import { runCli as runCliImpl } from "@/cli/run.ts";

/**
* Canonical CLI entrypoint for workspace package consumers.
Expand Down
4 changes: 2 additions & 2 deletions packages/db/tests/smoke.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { expect, test } from "bun:test";

import { createDbClient } from "../src/client.ts";
import { createDbClient } from "@/client.ts";
import {
githubConnections,
linearAssigneeMappings,
linearConnections,
linearSyncSubscriptions,
linearWebhookEvents,
} from "../src/schema/core.ts";
} from "@/schema/core.ts";

test("db package exports createDbClient", () => {
expect(typeof createDbClient).toBe("function");
Expand Down
5 changes: 5 additions & 0 deletions packages/db/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
"target": "ESNext",
"module": "Preserve",
"moduleResolution": "bundler",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@tests/*": ["tests/*"]
},
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true,
Expand Down
2 changes: 1 addition & 1 deletion services/auth-broker/tests/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from "bun:test";

import { resolveConfig } from "../src/config.ts";
import { resolveConfig } from "@/config.ts";

type EnvMap = Record<string, string | undefined>;

Expand Down
5 changes: 5 additions & 0 deletions services/auth-broker/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
"target": "ESNext",
"module": "Preserve",
"moduleResolution": "bundler",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@tests/*": ["tests/*"]
},
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true,
Expand Down
2 changes: 1 addition & 1 deletion src/cli/prerequisites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ export function getCommandPrerequisiteContracts(input: {
}): readonly CommandPrerequisiteContract[] {
const command = normalizePrerequisiteCommand({ command: input.command });
return COMMAND_PREREQUISITE_CONTRACTS.filter((contract) =>
contract.commands.includes(command)
contract.commands.some((candidate) => candidate === command)
);
}

Expand Down
125 changes: 89 additions & 36 deletions src/control-plane/extensions/linear/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ type LinearProjectIssuePage = {
readonly endCursor?: string;
};

type LinearProjectsPage = {
readonly projects: readonly LinearProject[];
readonly hasNextPage: boolean;
readonly endCursor?: string;
};

export type LinearClient = {
readonly getViewer: () => Promise<
LinearRequestResult<{
Expand All @@ -145,6 +151,10 @@ export type LinearClient = {
readonly listProjects: (input?: {
readonly first?: number;
}) => Promise<LinearRequestResult<readonly LinearProject[]>>;
readonly listProjectsPage: (input?: {
readonly first?: number;
readonly after?: string;
}) => Promise<LinearRequestResult<LinearProjectsPage>>;
readonly getProject: (input: {
readonly projectId: string;
}) => Promise<LinearRequestResult<LinearProject | null>>;
Expand Down Expand Up @@ -306,6 +316,70 @@ export function createLinearClient(input: {
};
};

async function listProjectsPage(
input: { readonly first?: number; readonly after?: string } = {}
): Promise<LinearRequestResult<LinearProjectsPage>> {
const first = normalizePositiveInt({
value: input.first,
fallback: DEFAULT_PAGE_SIZE,
});
const after = input.after?.trim();
const result = await request<{
readonly projects?: unknown;
}>({
query: [
"query LinearProjects($first: Int!, $after: String) {",
" projects(first: $first, after: $after) {",
" pageInfo {",
" hasNextPage",
" endCursor",
" }",
" nodes {",
" id",
" name",
" teams {",
" nodes {",
" id",
" key",
" name",
" }",
" }",
" }",
" }",
"}",
].join("\n"),
variables: {
first,
...(after ? { after } : {}),
},
});
if (!result.ok) {
return result;
}
const projects = parseProjectsPage(result.data.projects);
if (!projects) {
return {
ok: false,
status: 500,
error: "Linear projects payload missing pagination metadata.",
};
}
return { ok: true, data: projects };
}

async function listProjects(
input: { readonly first?: number } = {}
): Promise<LinearRequestResult<readonly LinearProject[]>> {
const page = await listProjectsPage(input);
if (!page.ok) {
return page;
}
return {
ok: true,
data: page.data.projects,
};
}

return {
getViewer: async () => {
const result = await request<{
Expand Down Expand Up @@ -339,39 +413,8 @@ export function createLinearClient(input: {
};
},

listProjects: async (input = {}) => {
const first = normalizePositiveInt({
value: input.first,
fallback: DEFAULT_PAGE_SIZE,
});
const result = await request<{
readonly projects?: unknown;
}>({
query: [
"query LinearProjects($first: Int!) {",
" projects(first: $first) {",
" nodes {",
" id",
" name",
" teams {",
" nodes {",
" id",
" key",
" name",
" }",
" }",
" }",
" }",
"}",
].join("\n"),
variables: { first },
});
if (!result.ok) {
return result;
}
const projects = parseProjectsConnection(result.data.projects);
return { ok: true, data: projects };
},
listProjects,
listProjectsPage,

getProject: async ({ projectId }) => {
const id = projectId.trim();
Expand Down Expand Up @@ -1451,11 +1494,15 @@ function parseViewer(value: unknown): {
};
}

function parseProjectsConnection(value: unknown): LinearProject[] {
function parseProjectsPage(value: unknown): LinearProjectsPage | null {
if (!isRecord(value)) {
return [];
return null;
}
const nodes = Array.isArray(value.nodes) ? value.nodes : [];
const pageInfo = isRecord(value.pageInfo) ? value.pageInfo : null;
if (!(pageInfo && typeof pageInfo.hasNextPage === "boolean")) {
return null;
}
const out: LinearProject[] = [];
for (const node of nodes) {
const parsed = parseProject(node);
Expand All @@ -1464,7 +1511,13 @@ function parseProjectsConnection(value: unknown): LinearProject[] {
}
out.push(parsed);
}
return out;
return {
projects: out,
hasNextPage: pageInfo.hasNextPage,
...(typeof pageInfo.endCursor === "string"
? { endCursor: pageInfo.endCursor }
: {}),
};
}

function parseUser(value: unknown): LinearUser | null {
Expand Down
Loading
Loading