Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

34 linesCodeBlameRaw
1/**
2 * A new work item's choices, as the site's New work item has them
3 * (apps/web/app/routes/workspace/work/new.tsx): the repositories of its
4 * own workspace it may land in, and the one it is filed from, ticked as
5 * a target to start with.
6 *
7 * Kept free of React Native imports so `npm test` runs it under Node.
8 */
9
10/** A workspace's project as the API answers: only its repository, `owner/name`, when it has one. */
11export type ProjectRepo = { repository: string | null };
12
13/** The repositories of a workspace's projects, `owner/name`, each once, in the order given. Another workspace's are left out. */
14export function workspaceRepos(workspace: string, projects: readonly ProjectRepo[]): string[] {
15 const own = workspace.toLowerCase();
16 const seen = new Map<string, string>();
17 for (const project of projects) {
18 const path = project.repository;
19 if (!path || path.split("/")[0]?.toLowerCase() !== own) continue;
20 if (!seen.has(path.toLowerCase())) seen.set(path.toLowerCase(), path);
21 }
22 return [...seen.values()];
23}
24
25/**
26 * The repository a new item is filed from, `owner/name`, from a link's
27 * `repo` (`web` or `acme/web`): only one of this workspace, else none.
28 */
29export function originOf(workspace: string, repo: string | null | undefined): string | null {
30 const parts = (repo ?? "").split("/").filter(Boolean);
31 if (parts.length === 1) return `${workspace}/${parts[0]}`;
32 if (parts.length === 2 && parts[0]!.toLowerCase() === workspace.toLowerCase()) return `${workspace}/${parts[1]}`;
33 return null;
34}