@detergent-software/conductor 1.2.1-dev.2 → 1.2.1-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +4 -0
  3. package/build/brief.js +2 -1
  4. package/build/brief.js.map +1 -1
  5. package/build/lib/providers/ado/code-host.js +230 -0
  6. package/build/lib/providers/ado/code-host.js.map +1 -0
  7. package/build/lib/providers/ado/http.js +95 -0
  8. package/build/lib/providers/ado/http.js.map +1 -0
  9. package/build/lib/providers/ado/pipelines.js +185 -0
  10. package/build/lib/providers/ado/pipelines.js.map +1 -0
  11. package/build/lib/providers/ado/trigger.js +99 -0
  12. package/build/lib/providers/ado/trigger.js.map +1 -0
  13. package/build/lib/providers/errors.js +23 -0
  14. package/build/lib/providers/errors.js.map +1 -0
  15. package/build/lib/providers/github/actions.js +86 -0
  16. package/build/lib/providers/github/actions.js.map +1 -0
  17. package/build/lib/providers/github/code-host.js +201 -0
  18. package/build/lib/providers/github/code-host.js.map +1 -0
  19. package/build/lib/providers/github/gh.js +15 -0
  20. package/build/lib/providers/github/gh.js.map +1 -0
  21. package/build/lib/providers/index.js +15 -0
  22. package/build/lib/providers/index.js.map +1 -0
  23. package/build/lib/providers/notes.js +22 -0
  24. package/build/lib/providers/notes.js.map +1 -0
  25. package/build/lib/providers/npm/stage.js +62 -0
  26. package/build/lib/providers/npm/stage.js.map +1 -0
  27. package/build/lib/providers/types.js +8 -0
  28. package/build/lib/providers/types.js.map +1 -0
  29. package/build/lib/providers/verdicts/pr.js +90 -0
  30. package/build/lib/providers/verdicts/pr.js.map +1 -0
  31. package/build/lib/providers/verdicts/runs.js +73 -0
  32. package/build/lib/providers/verdicts/runs.js.map +1 -0
  33. package/build/lib/providers/verdicts/stage.js +14 -0
  34. package/build/lib/providers/verdicts/stage.js.map +1 -0
  35. package/build/notes.js +1 -1
  36. package/build/notes.js.map +1 -1
  37. package/build/watchers/ado-api.js +2 -31
  38. package/build/watchers/ado-api.js.map +1 -1
  39. package/build/watchers/ado.js +36 -119
  40. package/build/watchers/ado.js.map +1 -1
  41. package/build/watchers/github.js +21 -48
  42. package/build/watchers/github.js.map +1 -1
  43. package/build/watchers/linear.js +2 -17
  44. package/build/watchers/linear.js.map +1 -1
  45. package/build/watchers/npm.js +1 -1
  46. package/build/watchers/npm.js.map +1 -1
  47. package/build/watchers/source.js +8 -2
  48. package/build/watchers/source.js.map +1 -1
  49. package/package.json +1 -1
@@ -0,0 +1,185 @@
1
+ // GENERATED from packages/providers by `pnpm sync-conductor`. Do not edit.
2
+ import { z } from 'zod';
3
+ import { adoRunUrl, adoUrl } from "./http.js";
4
+ import { parseTrigger, triggerFires } from "./trigger.js";
5
+ const definition = z.looseObject({
6
+ id: z.number(),
7
+ name: z.string(),
8
+ process: z.looseObject({ yamlFilename: z.string().optional() }).nullish(),
9
+ queueStatus: z.string().optional(),
10
+ repository: z.looseObject({ name: z.string().optional() }).nullish(),
11
+ triggers: z
12
+ .array(z.looseObject({ settingsSourceType: z.number().optional(), triggerType: z.string().optional() }))
13
+ .nullish(),
14
+ });
15
+ const build = z.looseObject({
16
+ _links: z.looseObject({ web: z.looseObject({ href: z.string() }).optional() }).optional(),
17
+ definition: z.looseObject({ id: z.number().optional(), name: z.string().optional() }),
18
+ id: z.number(),
19
+ queueTime: z.string().nullish(),
20
+ reason: z.string().nullish(),
21
+ result: z.string().nullish(),
22
+ sourceVersion: z.string().nullish(),
23
+ status: z.string(),
24
+ });
25
+ const timeline = z
26
+ .looseObject({
27
+ records: z.array(z.looseObject({
28
+ id: z.string(),
29
+ issues: z.array(z.looseObject({ message: z.string().optional(), type: z.string().optional() })).nullish(),
30
+ log: z.looseObject({ id: z.number() }).nullish(),
31
+ name: z.string().nullish(),
32
+ parentId: z.string().nullish(),
33
+ result: z.string().nullish(),
34
+ startTime: z.string().nullish(),
35
+ state: z.string().nullish(),
36
+ type: z.string().nullish(),
37
+ })),
38
+ })
39
+ .nullable();
40
+ const list = (item) => z.looseObject({ value: z.array(item) });
41
+ // A merge's batched run can queue a moment before the merge commit's own time.
42
+ const BATCH_SLACK_MS = 60_000;
43
+ // Azure Pipelines. It knows which pipelines a merge triggers: each pipeline's YAML trigger, read at
44
+ // the merge commit, against the merge's changed files.
45
+ export function adoPipelines(http) {
46
+ const get = async (repo, path) => http.json(adoUrl(repo, path));
47
+ const snapshot = (repo, b, pipeline, extra = {}) => ({
48
+ expected: null,
49
+ pipeline,
50
+ queued: b.queueTime ?? null,
51
+ reason: b.reason ?? null,
52
+ result: b.result ?? null,
53
+ run: b.id,
54
+ sourceVersion: b.sourceVersion ?? null,
55
+ state: buildState(b),
56
+ status: b.status,
57
+ url: b._links?.web?.href ?? adoRunUrl(repo, b.id),
58
+ ...extra,
59
+ });
60
+ const records = async (repo, id) => timeline.parse(await get(repo, `build/builds/${id}/timeline`))?.records ?? [];
61
+ return {
62
+ failureLog: async ({ id, repo }, { lines = 40 } = {}) => {
63
+ const b = build.parse(await get(repo, `build/builds/${id}`));
64
+ const all = await records(repo, id);
65
+ const failed = all
66
+ .filter((r) => r.result === 'failed' && r.type === 'Task')
67
+ .sort((a, b) => (a.startTime ?? '').localeCompare(b.startTime ?? ''));
68
+ const errors = (r) => (r.issues ?? []).filter((i) => i.type === 'error').flatMap((i) => (i.message ? [i.message] : []));
69
+ const tasks = failed.map((r) => ({ errors: errors(r), name: r.name ?? '?' }));
70
+ const logId = failed[0]?.log?.id;
71
+ let log = null;
72
+ if (logId !== undefined) {
73
+ // Each line starts with an ISO timestamp; dropped to keep the tail readable.
74
+ log = (await http.text(adoUrl(repo, `build/builds/${id}/logs/${logId}`)))
75
+ .split(/\r?\n/)
76
+ .map((line) => line.replace(/^\d{4}-\d\d-\d\dT[\d:.]+Z /, ''))
77
+ .filter((line) => line.trim())
78
+ .slice(-lines);
79
+ }
80
+ return {
81
+ log,
82
+ ...(tasks.length === 0
83
+ ? {
84
+ note: `no failed task in the timeline${all.some((r) => errors(r).length) ? `: ${all.flatMap(errors).slice(0, 10).join('; ')}` : ''}`,
85
+ }
86
+ : {}),
87
+ pipeline: b.definition.name ?? null,
88
+ result: b.result ?? null,
89
+ run: id,
90
+ tasks,
91
+ url: adoRunUrl(repo, id),
92
+ };
93
+ },
94
+ logs: async function* ({ id, repo }) {
95
+ const { value } = list(z.looseObject({ id: z.number() })).parse(await get(repo, `build/builds/${id}/logs`));
96
+ for (const { id: log } of value.sort((a, b) => b.id - a.id)) {
97
+ yield await http.text(adoUrl(repo, `build/builds/${id}/logs/${log}`));
98
+ }
99
+ },
100
+ run: async ({ id, repo }) => {
101
+ const b = build.parse(await get(repo, `build/builds/${id}`));
102
+ return snapshot(repo, b, { file: null, id: b.definition.id ?? null, name: b.definition.name ?? `run ${id}` });
103
+ },
104
+ runsForMerge: async (repo, merge, { base, git }) => {
105
+ const { value } = list(definition).parse(await get(repo, 'build/definitions?includeAllProperties=true&$top=1000'));
106
+ const pipelines = [];
107
+ for (const d of value) {
108
+ const yamlFilename = d.process?.yamlFilename;
109
+ // Azure Repos names are case-insensitive, and a profile may spell one differently.
110
+ const ours = d.repository?.name?.toLowerCase() === repo.repository.toLowerCase();
111
+ if (!ours || !yamlFilename || d.queueStatus === 'disabled')
112
+ continue;
113
+ const file = yamlFilename.replace(/^\//, '');
114
+ const yaml = await git.show(merge.sha, file);
115
+ // A trigger overridden in the pipeline's settings (settingsSourceType 1) isn't in the YAML.
116
+ const fromYaml = (d.triggers ?? []).every((t) => t.triggerType !== 'continuousIntegration' || t.settingsSourceType === 2);
117
+ const expected = yaml === null || !fromYaml ? null : triggerFires(parseTrigger(yaml), base, merge.changed);
118
+ pipelines.push({ expected, file, id: d.id, name: d.name });
119
+ }
120
+ if (pipelines.length === 0)
121
+ return [];
122
+ // By queue time, ascending from just before the merge: the default order is by finish time,
123
+ // which leaves queued and running builds off the first page.
124
+ const since = new Date(merge.mergedAt - 5 * 60_000).toISOString();
125
+ const query = `definitions=${pipelines.map((p) => p.id).join(',')}&branchName=refs/heads/${base}&queryOrder=queueTimeAscending&minTime=${since}&$top=200`;
126
+ const builds = list(build).parse(await get(repo, `build/builds?${query}`)).value;
127
+ const found = [];
128
+ for (const { expected, ...pipeline } of pipelines) {
129
+ const mine = builds
130
+ .filter((b) => b.definition.id === pipeline.id)
131
+ .sort((a, b) => Date.parse(a.queueTime ?? '') - Date.parse(b.queueTime ?? ''));
132
+ const exact = mine.find((b) => b.sourceVersion === merge.sha);
133
+ // Batched CI (`batch: true`) builds the newest commit once the previous run ends, so the run
134
+ // that carries the merge can be built from a later commit that contains it.
135
+ let batched;
136
+ if (!exact && expected === true) {
137
+ for (const b of mine) {
138
+ if (Date.parse(b.queueTime ?? '') < merge.mergedAt - BATCH_SLACK_MS || !b.sourceVersion)
139
+ continue;
140
+ if (await git.isAncestor(merge.sha, b.sourceVersion)) {
141
+ batched = b;
142
+ break;
143
+ }
144
+ }
145
+ }
146
+ const b = exact ?? batched;
147
+ if (!b) {
148
+ const state = expected === true ? 'not-queued' : expected === null ? 'unknown' : 'not-triggered';
149
+ found.push({ expected, pipeline, run: null, state, url: null });
150
+ continue;
151
+ }
152
+ const approvals = b.status === 'completed' ? [] : pendingApprovals(await records(repo, b.id));
153
+ found.push(snapshot(repo, b, pipeline, {
154
+ expected,
155
+ match: exact ? 'exact' : 'batched',
156
+ state: buildState(b, approvals),
157
+ ...(approvals.length > 0 ? { approvalStages: approvals } : {}),
158
+ }));
159
+ }
160
+ return found;
161
+ },
162
+ triggersKnown: true,
163
+ };
164
+ }
165
+ // The state of one build, as the run verdicts read it. ADO has no "cancelled" verdict of its own: a
166
+ // completed build that didn't succeed failed.
167
+ export function buildState(b, pendingApprovals = []) {
168
+ if (b.status === 'completed')
169
+ return b.result === 'succeeded' ? 'succeeded' : 'failed';
170
+ if (pendingApprovals.length > 0)
171
+ return 'waiting-for-approval';
172
+ return b.status === 'notStarted' ? 'queued' : 'running';
173
+ }
174
+ // The stages of a run's timeline that wait on an approval.
175
+ export function pendingApprovals(records) {
176
+ const byId = new Map(records.map((r) => [r.id, r]));
177
+ const stageOf = (record) => {
178
+ let current = record;
179
+ while (current && current.type !== 'Stage')
180
+ current = current.parentId ? byId.get(current.parentId) : undefined;
181
+ return current?.name ?? '?';
182
+ };
183
+ return records.filter((r) => r.type === 'Checkpoint.Approval' && r.state === 'inProgress').map(stageOf);
184
+ }
185
+ //# sourceMappingURL=pipelines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipelines.js","sourceRoot":"","sources":["../../../../src/lib/providers/ado/pipelines.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAgB,SAAS,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,UAAU,GAAG,CAAC,CAAC,WAAW,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;IACzE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;IACpE,QAAQ,EAAE,CAAC;SACR,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;SACvG,OAAO,EAAE;CACb,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,CAAC;IAC1B,MAAM,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE;IACzF,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;IACrF,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC5B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IACnC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;CACnB,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,CAAC;KACf,WAAW,CAAC;IACX,OAAO,EAAE,CAAC,CAAC,KAAK,CACd,CAAC,CAAC,WAAW,CAAC;QACZ,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;QACd,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE;QACzG,GAAG,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;QAChD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;QAC1B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;QAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;QAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;QAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;QAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;KAC3B,CAAC,CACH;CACF,CAAC;KACD,QAAQ,EAAE,CAAC;AAEd,MAAM,IAAI,GAAG,CAAsB,IAAO,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAKvF,+EAA+E;AAC/E,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,oGAAoG;AACpG,uDAAuD;AACvD,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,MAAM,GAAG,GAAG,KAAK,EAAE,IAAgB,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAEpF,MAAM,QAAQ,GAAG,CAAC,IAAgB,EAAE,CAAQ,EAAE,QAAkB,EAAE,QAA8B,EAAE,EAAe,EAAE,CAAC,CAAC;QACnH,QAAQ,EAAE,IAAI;QACd,QAAQ;QACR,MAAM,EAAE,CAAC,CAAC,SAAS,IAAI,IAAI;QAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI;QACxB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI;QACxB,GAAG,EAAE,CAAC,CAAC,EAAE;QACT,aAAa,EAAE,CAAC,CAAC,aAAa,IAAI,IAAI;QACtC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,KAAK;KACT,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,KAAK,EAAE,IAAgB,EAAE,EAAU,EAAE,EAAE,CACrD,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;IAEhF,OAAO;QACL,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,GAAG,EAAE,EAAuB,EAAE;YAC3E,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC;YAC7D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,GAAG;iBACf,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;iBACzD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;YACxE,MAAM,MAAM,GAAG,CAAC,CAAuB,EAAE,EAAE,CACzC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpG,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;YAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;YACjC,IAAI,GAAG,GAAoB,IAAI,CAAC;YAChC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,6EAA6E;gBAC7E,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC;qBACtE,KAAK,CAAC,OAAO,CAAC;qBACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;qBAC7D,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;qBAC7B,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;YACD,OAAO;gBACL,GAAG;gBACH,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;oBACpB,CAAC,CAAC;wBACE,IAAI,EAAE,iCAAiC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;qBACrI;oBACH,CAAC,CAAC,EAAE,CAAC;gBACP,QAAQ,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,IAAI,IAAI;gBACnC,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI;gBACxB,GAAG,EAAE,EAAE;gBACP,KAAK;gBACL,GAAG,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;aACzB,CAAC;QACJ,CAAC;QAED,IAAI,EAAE,KAAK,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;YACjC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;YAC5G,KAAK,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC5D,MAAM,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC;YACxE,CAAC;QACH,CAAC;QAED,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC;YAC7D,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,IAAI,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAChH,CAAC;QAED,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,KAAiB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAoC,EAAE,EAAE;YAC/F,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CACtC,MAAM,GAAG,CAAC,IAAI,EAAE,uDAAuD,CAAC,CACzE,CAAC;YACF,MAAM,SAAS,GAAgD,EAAE,CAAC;YAClE,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC;gBAC7C,mFAAmF;gBACnF,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;gBACjF,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,WAAW,KAAK,UAAU;oBAAE,SAAS;gBACrE,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAC7C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC7C,4FAA4F;gBAC5F,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,KAAK,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,uBAAuB,IAAI,CAAC,CAAC,kBAAkB,KAAK,CAAC,CAC/E,CAAC;gBACF,MAAM,QAAQ,GAAG,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC3G,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,CAAC;YACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YAEtC,4FAA4F;YAC5F,6DAA6D;YAC7D,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;YAClE,MAAM,KAAK,GAAG,eAAe,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,0BAA0B,IAAI,0CAA0C,KAAK,WAAW,CAAC;YAC1J,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;YAEjF,MAAM,KAAK,GAAkB,EAAE,CAAC;YAChC,KAAK,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,IAAI,SAAS,EAAE,CAAC;gBAClD,MAAM,IAAI,GAAG,MAAM;qBAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC;qBAC9C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;gBACjF,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC9D,6FAA6F;gBAC7F,4EAA4E;gBAC5E,IAAI,OAA0B,CAAC;gBAC/B,IAAI,CAAC,KAAK,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;oBAChC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;wBACrB,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,GAAG,cAAc,IAAI,CAAC,CAAC,CAAC,aAAa;4BAAE,SAAS;wBAClG,IAAI,MAAM,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC;4BACrD,OAAO,GAAG,CAAC,CAAC;4BACZ,MAAM;wBACR,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,CAAC;gBAC3B,IAAI,CAAC,CAAC,EAAE,CAAC;oBACP,MAAM,KAAK,GAAa,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC;oBAC3G,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;oBAChE,SAAS;gBACX,CAAC;gBACD,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC9F,KAAK,CAAC,IAAI,CACR,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE;oBAC1B,QAAQ;oBACR,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;oBAClC,KAAK,EAAE,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC;oBAC/B,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC/D,CAAC,CACH,CAAC;YACJ,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,aAAa,EAAE,IAAI;KACpB,CAAC;AACJ,CAAC;AAED,oGAAoG;AACpG,8CAA8C;AAC9C,MAAM,UAAU,UAAU,CAAC,CAAmC,EAAE,mBAAsC,EAAE;IACtG,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC;IACvF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,sBAAsB,CAAC;IAC/D,OAAO,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,gBAAgB,CAAC,OAAyC;IACxE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,CAAC,MAAgC,EAAE,EAAE;QACnD,IAAI,OAAO,GAAyC,MAAM,CAAC;QAC3D,OAAO,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChH,OAAO,OAAO,EAAE,IAAI,IAAI,GAAG,CAAC;IAC9B,CAAC,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,qBAAqB,IAAI,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC1G,CAAC"}
@@ -0,0 +1,99 @@
1
+ export function parseTrigger(yaml) {
2
+ const lines = yaml.split(/\r?\n/);
3
+ const start = lines.findIndex((line) => /^trigger\s*:/.test(line));
4
+ if (start === -1)
5
+ return { kind: 'all' }; // no trigger key: every branch, every path
6
+ const inline = stripComment((lines[start] ?? '').replace(/^trigger\s*:/, '')).trim();
7
+ const filter = {
8
+ branches: { exclude: [], include: [] },
9
+ kind: 'filter',
10
+ paths: { exclude: [], include: [] },
11
+ };
12
+ if (inline === 'none')
13
+ return { kind: 'none' };
14
+ if (inline.startsWith('['))
15
+ return { ...filter, branches: { exclude: [], include: listItems(inline) } };
16
+ if (inline)
17
+ return { kind: 'unknown' };
18
+ const sections = { branches: filter.branches, paths: filter.paths };
19
+ let section = 'branches'; // a bare list under `trigger:` is a branch list
20
+ let which = 'include';
21
+ for (const raw of lines.slice(start + 1)) {
22
+ const line = stripComment(raw);
23
+ if (!line.trim())
24
+ continue;
25
+ if (/^\S/.test(line) && !/^-\s/.test(line))
26
+ break;
27
+ const key = /^\s+(\w+)\s*:\s*(.*)$/.exec(line);
28
+ const value = key?.[2] ?? '';
29
+ if (key?.[1] && key[1] !== 'include' && key[1] !== 'exclude') {
30
+ section = key[1];
31
+ which = 'include';
32
+ if (value.trim().startsWith('['))
33
+ sections[section]?.include.push(...listItems(value));
34
+ continue;
35
+ }
36
+ if (key?.[1]) {
37
+ which = key[1] === 'exclude' ? 'exclude' : 'include';
38
+ if (value.trim().startsWith('['))
39
+ sections[section]?.[which].push(...listItems(value));
40
+ continue;
41
+ }
42
+ const item = /^\s*-\s+(.+)$/.exec(line)?.[1];
43
+ if (item)
44
+ sections[section]?.[which].push(unquote(item.trim()));
45
+ }
46
+ return filter;
47
+ }
48
+ // Whether a trigger fires for a push to `branch` that changed `files`; null when unsure.
49
+ export function triggerFires(trigger, branch, files) {
50
+ if (trigger.kind === 'none')
51
+ return false;
52
+ if (trigger.kind === 'all')
53
+ return true;
54
+ if (trigger.kind !== 'filter')
55
+ return null;
56
+ const { branches, paths } = trigger;
57
+ const branchHit = (pattern) => globMatch(pattern.replace(/^refs\/heads\//, ''), branch);
58
+ if (branches.include.length > 0 && !branches.include.some(branchHit))
59
+ return false;
60
+ if (branches.exclude.some(branchHit))
61
+ return false;
62
+ if (paths.include.length === 0 && paths.exclude.length === 0)
63
+ return true;
64
+ // Only a trailing `*` is read; other wildcards leave the answer to the grace period.
65
+ if ([...paths.include, ...paths.exclude].some((pattern) => /[*?[]/.test(pattern.replace(/\*$/, ''))))
66
+ return null;
67
+ // Azure Pipelines reads `/apps/api/*` as `apps/api/*`: paths are from the repository root.
68
+ const pathHit = (written, file) => {
69
+ const pattern = written.replace(/^\/+/, '');
70
+ if (pattern.endsWith('*'))
71
+ return file.startsWith(pattern.slice(0, -1));
72
+ const folder = pattern.replace(/\/$/, '');
73
+ return file === folder || file.startsWith(`${folder}/`);
74
+ };
75
+ return files.some((file) => (paths.include.length === 0 || paths.include.some((p) => pathHit(p, file))) &&
76
+ !paths.exclude.some((p) => pathHit(p, file)));
77
+ }
78
+ function globMatch(pattern, text) {
79
+ const source = pattern
80
+ .split('*')
81
+ .map((part) => part.replace(/[.+?^${}()|[\]\\]/g, '\\$&'))
82
+ .join('.*');
83
+ return new RegExp(`^${source}$`).test(text);
84
+ }
85
+ function listItems(text) {
86
+ return text
87
+ .trim()
88
+ .replace(/^\[|\]$/g, '')
89
+ .split(',')
90
+ .map((item) => unquote(item.trim()))
91
+ .filter(Boolean);
92
+ }
93
+ function stripComment(line) {
94
+ return line.replace(/(^|\s+)#.*$/, '');
95
+ }
96
+ function unquote(text) {
97
+ return text.replace(/^(['"])(.*)\1$/, '$2');
98
+ }
99
+ //# sourceMappingURL=trigger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trigger.js","sourceRoot":"","sources":["../../../../src/lib/providers/ado/trigger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ // GENERATED from packages/providers by `pnpm sync-conductor`. Do not edit.
2
+ // An answer about the thing asked for, not the provider: a PR, run or package that doesn't exist
3
+ // (404; Azure DevOps answers 400 for an id it can't read). A caller waiting on that thing reports
4
+ // it as that wait's problem and keeps going.
5
+ export class NotFound extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = 'NotFound';
9
+ }
10
+ }
11
+ // The provider itself failed: a refused token, a 5xx, a rate limit. `transient` is true when asking
12
+ // again later may succeed.
13
+ export class ProviderError extends Error {
14
+ status;
15
+ transient;
16
+ constructor(message, { status = null, transient = false } = {}) {
17
+ super(message);
18
+ this.name = 'ProviderError';
19
+ this.status = status;
20
+ this.transient = transient;
21
+ }
22
+ }
23
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/lib/providers/errors.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iGAAiG;AACjG,kGAAkG;AAClG,6CAA6C;AAC7C,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,oGAAoG;AACpG,2BAA2B;AAC3B,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,MAAM,CAAgB;IACtB,SAAS,CAAU;IAE5B,YACE,OAAe,EACf,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,GAAG,KAAK,KAAsD,EAAE;QAE1F,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,86 @@
1
+ // GENERATED from packages/providers by `pnpm sync-conductor`. Do not edit.
2
+ import { z } from 'zod';
3
+ import { ProviderError } from "../errors.js";
4
+ import { PASSING, repoName } from "./gh.js";
5
+ const workflowRun = z.looseObject({
6
+ conclusion: z.string().nullish(),
7
+ created_at: z.string().nullish(),
8
+ event: z.string().optional(),
9
+ head_sha: z.string().optional(),
10
+ html_url: z.string().nullish(),
11
+ id: z.number(),
12
+ name: z.string().nullish(),
13
+ path: z.string().nullish(),
14
+ status: z.string().nullish(),
15
+ workflow_id: z.number().optional(),
16
+ });
17
+ export function workflowRunSnapshot(run) {
18
+ return {
19
+ ...(run.conclusion ? { conclusion: run.conclusion } : {}),
20
+ expected: null,
21
+ pipeline: { file: run.path ?? null, id: run.workflow_id ?? null, name: run.name ?? run.path ?? `run ${run.id}` },
22
+ queued: run.created_at ?? null,
23
+ run: run.id,
24
+ sourceVersion: run.head_sha ?? null,
25
+ state: workflowRunState(run),
26
+ status: run.status ?? null,
27
+ url: run.html_url ?? null,
28
+ };
29
+ }
30
+ // A workflow with a concurrency group cancels a pending run when a newer push queues one, so
31
+ // cancelled is its own state: the newer run may have built the merge too.
32
+ export function workflowRunState(run) {
33
+ if (run.status === 'completed') {
34
+ return PASSING.has(run.conclusion ?? '') ? 'succeeded' : run.conclusion === 'cancelled' ? 'cancelled' : 'failed';
35
+ }
36
+ if (run.status === 'waiting')
37
+ return 'waiting-for-approval';
38
+ return run.status === 'in_progress' ? 'running' : 'queued';
39
+ }
40
+ const COLOUR = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, 'g');
41
+ // GitHub Actions. A push queues its runs within seconds, but nothing says which workflows a merge
42
+ // should start, so no run at all waits out the grace period.
43
+ export function githubActions(gh) {
44
+ const base = (repo) => `repos/${repoName(repo)}`;
45
+ const runGh = (args) => {
46
+ if (!gh.run)
47
+ throw new ProviderError('reading an Actions log needs a gh runner');
48
+ return gh.run(args);
49
+ };
50
+ return {
51
+ failureLog: async ({ id, repo }, { lines = 40 } = {}) => {
52
+ const run = workflowRun.parse(await gh.api(`${base(repo)}/actions/runs/${id}`));
53
+ const text = logText(await runGh(['run', 'view', String(id), '--repo', repoName(repo), '--log-failed']));
54
+ return {
55
+ log: text.slice(-lines),
56
+ pipeline: run.name ?? null,
57
+ result: run.conclusion ?? null,
58
+ run: id,
59
+ tasks: [],
60
+ url: run.html_url ?? null,
61
+ };
62
+ },
63
+ logs: async function* ({ id, repo }) {
64
+ yield logText(await runGh(['run', 'view', String(id), '--repo', repoName(repo), '--log'])).join('\n');
65
+ },
66
+ run: async ({ id, repo }) => workflowRunSnapshot(workflowRun.parse(await gh.api(`${base(repo)}/actions/runs/${id}`))),
67
+ // The runs a push started for the merge commit (pull request runs of the same SHA left out).
68
+ runsForMerge: async (repo, merge) => {
69
+ const { workflow_runs: runs } = z
70
+ .looseObject({ workflow_runs: z.array(workflowRun) })
71
+ .parse(await gh.api(`${base(repo)}/actions/runs?head_sha=${merge.sha}&per_page=100`));
72
+ return runs.filter((run) => run.event === 'push').map(workflowRunSnapshot);
73
+ },
74
+ triggersKnown: false,
75
+ };
76
+ }
77
+ // The text of `gh run view --log-failed` or `--log`: each line is "<job>\t<step>\t<timestamp>
78
+ // <text>", and the text is what a reader needs.
79
+ export function logText(output) {
80
+ return output
81
+ .replace(COLOUR, '')
82
+ .split(/\r?\n/)
83
+ .map((line) => (line.split('\t').at(-1) ?? '').replace(/^\S+Z /, ''))
84
+ .filter((line) => line.trim());
85
+ }
86
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../../src/lib/providers/github/actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,201 @@
1
+ // GENERATED from packages/providers by `pnpm sync-conductor`. Do not edit.
2
+ import { z } from 'zod';
3
+ import { isNote } from "../notes.js";
4
+ import { PASSING, repoName } from "./gh.js";
5
+ const user = z.looseObject({ login: z.string(), type: z.string().optional() }).nullish();
6
+ const pull = z.looseObject({
7
+ auto_merge: z.looseObject({ enabled_by: user }).nullish(),
8
+ base: z.looseObject({ ref: z.string() }).optional(),
9
+ head: z.looseObject({ ref: z.string().optional(), sha: z.string() }),
10
+ html_url: z.string().optional(),
11
+ merge_commit_sha: z.string().nullish(),
12
+ mergeable: z.boolean().nullish(),
13
+ mergeable_state: z.string().nullish(),
14
+ merged: z.boolean().optional(),
15
+ merged_at: z.string().nullish(),
16
+ number: z.number().optional(),
17
+ state: z.string(),
18
+ title: z.string().optional(),
19
+ });
20
+ const checkRuns = z.looseObject({
21
+ check_runs: z.array(z.looseObject({
22
+ conclusion: z.string().nullish(),
23
+ details_url: z.string().nullish(),
24
+ html_url: z.string().nullish(),
25
+ name: z.string(),
26
+ status: z.string(),
27
+ })),
28
+ });
29
+ const comment = z.looseObject({
30
+ body: z.string().nullish(),
31
+ created_at: z.string(),
32
+ html_url: z.string().nullish(),
33
+ id: z.number().optional(),
34
+ line: z.number().nullish(),
35
+ path: z.string().nullish(),
36
+ user,
37
+ });
38
+ const review = z.looseObject({
39
+ body: z.string().nullish(),
40
+ html_url: z.string().nullish(),
41
+ id: z.number().optional(),
42
+ state: z.string(),
43
+ submitted_at: z.string().nullish(),
44
+ user,
45
+ });
46
+ export const GITHUB_CAPABILITIES = {
47
+ autoLanding: 'auto-merge',
48
+ descriptionLimit: 65_536,
49
+ keepArmed: false,
50
+ mergeFailure: false,
51
+ threadState: false,
52
+ };
53
+ export function githubChecks(runs) {
54
+ return runs.map((c) => ({
55
+ current: true,
56
+ kind: 'check',
57
+ name: c.name,
58
+ required: true,
59
+ run: actionsRun(c.details_url ?? c.html_url),
60
+ state: c.status !== 'completed' ? 'pending' : PASSING.has(c.conclusion ?? '') ? 'passed' : 'failed',
61
+ status: c.status === 'completed' ? (c.conclusion ?? 'completed') : c.status,
62
+ url: c.html_url ?? c.details_url ?? null,
63
+ }));
64
+ }
65
+ // GitHub, through `gh api`. Paths and query strings are the ones the conductor's watcher has always
66
+ // asked, so a caller that counts requests per path (the daemon) sees the same requests.
67
+ export function githubCodeHost(gh) {
68
+ const base = (repo) => `repos/${repoName(repo)}`;
69
+ const rawPr = async ({ number, repo }) => pull.parse(await gh.api(`${base(repo)}/pulls/${number}`));
70
+ const checksAt = async (repo, sha) => githubChecks(checkRuns.parse(await gh.api(`${base(repo)}/commits/${sha}/check-runs?per_page=100`)).check_runs);
71
+ const rawReviews = async ({ number, repo }) => z.array(review).parse(await gh.api(`${base(repo)}/pulls/${number}/reviews?per_page=100`));
72
+ const threadsOf = async (ref, notePrefixes, { reviews, since } = {}) => {
73
+ // Comments come oldest first, so `since` keeps a new one on the first page. Reviews can't be
74
+ // asked that way; a PR has few.
75
+ const after = `per_page=100${since ? `&since=${encodeURIComponent(since)}` : ''}`;
76
+ const comments = z.array(comment).parse(await gh.api(`${base(ref.repo)}/issues/${ref.number}/comments?${after}`));
77
+ const reviewComments = z
78
+ .array(comment)
79
+ .parse(await gh.api(`${base(ref.repo)}/pulls/${ref.number}/comments?${after}`));
80
+ return githubThreads({ comments, reviewComments, reviews: reviews ?? (await rawReviews(ref)) }, notePrefixes);
81
+ };
82
+ return {
83
+ capabilities: () => GITHUB_CAPABILITIES,
84
+ checks: async (ref) => checksAt(ref.repo, (await rawPr(ref)).head.sha),
85
+ commit: async (repo, sha) => {
86
+ const found = z
87
+ .looseObject({
88
+ commit: z.looseObject({ committer: z.looseObject({ date: z.string() }) }),
89
+ parents: z.array(z.looseObject({ sha: z.string() })),
90
+ sha: z.string(),
91
+ })
92
+ .parse(await gh.api(`${base(repo)}/commits/${sha}`));
93
+ return { date: found.commit.committer.date, parents: found.parents.map((p) => p.sha), sha: found.sha };
94
+ },
95
+ pr: async (ref) => githubPrState(await rawPr(ref), ref.number),
96
+ prForBranch: async (repo, branch) => {
97
+ const head = encodeURIComponent(`${repo.owner}:${branch}`);
98
+ const [found] = z.array(pull).parse(await gh.api(`${base(repo)}/pulls?head=${head}&state=all&per_page=1`));
99
+ if (!found)
100
+ return null;
101
+ const state = githubPrState(found, found.number ?? 0);
102
+ return {
103
+ autoMerge: state.autoMerge.armed,
104
+ base: state.base,
105
+ mergeCommit: state.mergeCommit,
106
+ mergeStrategy: null,
107
+ number: state.number,
108
+ state: state.state,
109
+ title: state.title,
110
+ url: state.url,
111
+ };
112
+ },
113
+ read: async (ref, { notePrefixes }) => {
114
+ const raw = await rawPr(ref);
115
+ const state = githubPrState(raw, ref.number);
116
+ if (state.state !== 'open')
117
+ return { ...state, branchTip: null, checks: [], reviews: [], threads: [] };
118
+ const checks = await checksAt(ref.repo, raw.head.sha);
119
+ const reviews = await rawReviews(ref);
120
+ const threads = await threadsOf(ref, notePrefixes, { reviews });
121
+ return { ...state, branchTip: null, checks, reviews: githubReviews(reviews), threads };
122
+ },
123
+ reviews: async (ref) => githubReviews(await rawReviews(ref)),
124
+ threads: async (ref, { notePrefixes, since }) => threadsOf(ref, notePrefixes, { since }),
125
+ };
126
+ }
127
+ export function githubPrState(pr, number) {
128
+ const merged = Boolean(pr.merged || pr.merged_at);
129
+ return {
130
+ autoMerge: { armed: Boolean(pr.auto_merge), by: pr.auto_merge?.enabled_by?.login ?? null },
131
+ base: pr.base?.ref ?? null,
132
+ head: pr.head.ref ?? null,
133
+ merge: pr.mergeable_state === 'dirty' ? 'conflicts' : pr.mergeable === true ? 'clean' : 'pending',
134
+ mergeCommit: merged ? (pr.merge_commit_sha ?? null) : null,
135
+ mergeFailure: null,
136
+ number: pr.number ?? number,
137
+ sourceCommit: pr.head.sha,
138
+ state: merged ? 'merged' : pr.state === 'closed' ? 'closed' : 'open',
139
+ title: pr.title ?? '',
140
+ url: pr.html_url ?? '',
141
+ };
142
+ }
143
+ // A person's latest review decides their vote, as GitHub counts it; a bot's doesn't count.
144
+ export function githubReviews(reviews) {
145
+ const latest = new Map();
146
+ for (const r of reviews) {
147
+ if (!r.user || r.user.type === 'Bot' || !['APPROVED', 'CHANGES_REQUESTED', 'DISMISSED'].includes(r.state))
148
+ continue;
149
+ const before = latest.get(r.user.login);
150
+ if (!before || Date.parse(r.submitted_at ?? '') >= Date.parse(before.submitted_at ?? ''))
151
+ latest.set(r.user.login, r);
152
+ }
153
+ return [...latest.values()].map((r) => ({
154
+ at: r.submitted_at ?? null,
155
+ by: r.user?.login ?? null,
156
+ verdict: r.state === 'APPROVED' ? 'approved' : r.state === 'CHANGES_REQUESTED' ? 'changes-requested' : 'none',
157
+ }));
158
+ }
159
+ // GitHub has no review threads: each comment, inline comment and submitted review is one, in that
160
+ // order. Nothing resolves them, so a person's comment stays open until a note comes after it.
161
+ export function githubThreads({ comments, reviewComments, reviews, }, notePrefixes) {
162
+ const item = (kind, c, at, extra = {}) => ({
163
+ asks: true,
164
+ at,
165
+ by: c.user?.login ?? null,
166
+ byPerson: c.user?.type !== 'Bot' && !isNote(c.body, notePrefixes),
167
+ excerpt: (c.body ?? '').slice(0, 500),
168
+ file: null,
169
+ id: c.id ?? 0,
170
+ kind,
171
+ lastIsNote: isNote(c.body, notePrefixes),
172
+ line: null,
173
+ open: true,
174
+ url: c.html_url ?? null,
175
+ ...extra,
176
+ });
177
+ const all = [
178
+ ...comments.map((c) => item('comment', c, c.created_at)),
179
+ ...reviewComments.map((c) => item('review-comment', c, c.created_at, { file: c.path ?? null, line: c.line ?? null })),
180
+ ...reviews
181
+ .filter((r) => r.state !== 'PENDING')
182
+ .map((r) =>
183
+ // A review's own text asks for something only when it is a comment: an approval's text ("LGTM")
184
+ // doesn't, and a change request is a review verdict.
185
+ item('review', r, r.submitted_at ?? null, {
186
+ asks: r.state === 'COMMENTED' && Boolean((r.body ?? '').trim()),
187
+ reviewState: r.state,
188
+ })),
189
+ ];
190
+ // A time GitHub didn't give (or that doesn't parse) orders nothing: such a note is skipped, and such
191
+ // a comment is open only while no note has been written.
192
+ const time = (t) => Date.parse(t.at ?? '');
193
+ const lastNote = Math.max(-Infinity, ...all.filter((t) => t.lastIsNote && !Number.isNaN(time(t))).map(time));
194
+ return all.map((t) => ({ ...t, open: Number.isNaN(time(t)) ? lastNote === -Infinity : time(t) > lastNote }));
195
+ }
196
+ // The Actions run id in a check's details URL (…/actions/runs/<id>/job/<job>), or null.
197
+ function actionsRun(url) {
198
+ const id = /\/actions\/runs\/(\d+)/.exec(url ?? '')?.[1];
199
+ return id ? Number(id) : null;
200
+ }
201
+ //# sourceMappingURL=code-host.js.map