@intentius/sql-yodeler 0.0.0-stage → 0.1.0

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 (264) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +110 -2
  3. package/dist/bin.d.ts +2 -0
  4. package/dist/bin.js +14 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/chant/apply.d.ts +51 -0
  7. package/dist/chant/apply.js +104 -0
  8. package/dist/chant/apply.js.map +1 -0
  9. package/dist/chant/build.d.ts +34 -0
  10. package/dist/chant/build.js +48 -0
  11. package/dist/chant/build.js.map +1 -0
  12. package/dist/chant/drift.d.ts +44 -0
  13. package/dist/chant/drift.js +91 -0
  14. package/dist/chant/drift.js.map +1 -0
  15. package/dist/chant/plan.d.ts +45 -0
  16. package/dist/chant/plan.js +61 -0
  17. package/dist/chant/plan.js.map +1 -0
  18. package/dist/chant/process.d.ts +41 -0
  19. package/dist/chant/process.js +87 -0
  20. package/dist/chant/process.js.map +1 -0
  21. package/dist/cli.d.ts +4 -0
  22. package/dist/cli.js +59 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/command.d.ts +17 -0
  25. package/dist/command.js +13 -0
  26. package/dist/command.js.map +1 -0
  27. package/dist/commands/apply.d.ts +3 -0
  28. package/dist/commands/apply.js +306 -0
  29. package/dist/commands/apply.js.map +1 -0
  30. package/dist/commands/drift.d.ts +3 -0
  31. package/dist/commands/drift.js +38 -0
  32. package/dist/commands/drift.js.map +1 -0
  33. package/dist/commands/index.d.ts +3 -0
  34. package/dist/commands/index.js +22 -0
  35. package/dist/commands/index.js.map +1 -0
  36. package/dist/commands/init.d.ts +3 -0
  37. package/dist/commands/init.js +135 -0
  38. package/dist/commands/init.js.map +1 -0
  39. package/dist/commands/lint.d.ts +3 -0
  40. package/dist/commands/lint.js +193 -0
  41. package/dist/commands/lint.js.map +1 -0
  42. package/dist/commands/new.d.ts +3 -0
  43. package/dist/commands/new.js +168 -0
  44. package/dist/commands/new.js.map +1 -0
  45. package/dist/commands/plan.d.ts +3 -0
  46. package/dist/commands/plan.js +171 -0
  47. package/dist/commands/plan.js.map +1 -0
  48. package/dist/commands/rebase.d.ts +3 -0
  49. package/dist/commands/rebase.js +167 -0
  50. package/dist/commands/rebase.js.map +1 -0
  51. package/dist/commands/repair.d.ts +3 -0
  52. package/dist/commands/repair.js +117 -0
  53. package/dist/commands/repair.js.map +1 -0
  54. package/dist/commands/status.d.ts +7 -0
  55. package/dist/commands/status.js +54 -0
  56. package/dist/commands/status.js.map +1 -0
  57. package/dist/config/define.d.ts +50 -0
  58. package/dist/config/define.js +20 -0
  59. package/dist/config/define.js.map +1 -0
  60. package/dist/config/index.d.ts +11 -0
  61. package/dist/config/index.js +12 -0
  62. package/dist/config/index.js.map +1 -0
  63. package/dist/config/load.d.ts +17 -0
  64. package/dist/config/load.js +102 -0
  65. package/dist/config/load.js.map +1 -0
  66. package/dist/config/settings.d.ts +40 -0
  67. package/dist/config/settings.js +88 -0
  68. package/dist/config/settings.js.map +1 -0
  69. package/dist/env-args.d.ts +18 -0
  70. package/dist/env-args.js +62 -0
  71. package/dist/env-args.js.map +1 -0
  72. package/dist/history/client.d.ts +17 -0
  73. package/dist/history/client.js +19 -0
  74. package/dist/history/client.js.map +1 -0
  75. package/dist/history/ddl.d.ts +58 -0
  76. package/dist/history/ddl.js +100 -0
  77. package/dist/history/ddl.js.map +1 -0
  78. package/dist/history/index.d.ts +25 -0
  79. package/dist/history/index.js +26 -0
  80. package/dist/history/index.js.map +1 -0
  81. package/dist/history/lock.d.ts +100 -0
  82. package/dist/history/lock.js +224 -0
  83. package/dist/history/lock.js.map +1 -0
  84. package/dist/history/postgres/ddl.d.ts +22 -0
  85. package/dist/history/postgres/ddl.js +47 -0
  86. package/dist/history/postgres/ddl.js.map +1 -0
  87. package/dist/history/postgres/index.d.ts +12 -0
  88. package/dist/history/postgres/index.js +13 -0
  89. package/dist/history/postgres/index.js.map +1 -0
  90. package/dist/history/postgres/lock.d.ts +48 -0
  91. package/dist/history/postgres/lock.js +95 -0
  92. package/dist/history/postgres/lock.js.map +1 -0
  93. package/dist/history/postgres/store.d.ts +39 -0
  94. package/dist/history/postgres/store.js +68 -0
  95. package/dist/history/postgres/store.js.map +1 -0
  96. package/dist/history/rows.d.ts +96 -0
  97. package/dist/history/rows.js +73 -0
  98. package/dist/history/rows.js.map +1 -0
  99. package/dist/history/store.d.ts +72 -0
  100. package/dist/history/store.js +134 -0
  101. package/dist/history/store.js.map +1 -0
  102. package/dist/history/topology.d.ts +41 -0
  103. package/dist/history/topology.js +54 -0
  104. package/dist/history/topology.js.map +1 -0
  105. package/dist/index.d.ts +10 -0
  106. package/dist/index.js +10 -0
  107. package/dist/index.js.map +1 -0
  108. package/dist/init/adopt.d.ts +70 -0
  109. package/dist/init/adopt.js +138 -0
  110. package/dist/init/adopt.js.map +1 -0
  111. package/dist/init/baseline.d.ts +61 -0
  112. package/dist/init/baseline.js +88 -0
  113. package/dist/init/baseline.js.map +1 -0
  114. package/dist/init/files.d.ts +23 -0
  115. package/dist/init/files.js +77 -0
  116. package/dist/init/files.js.map +1 -0
  117. package/dist/init/index.d.ts +16 -0
  118. package/dist/init/index.js +17 -0
  119. package/dist/init/index.js.map +1 -0
  120. package/dist/init/live.d.ts +28 -0
  121. package/dist/init/live.js +45 -0
  122. package/dist/init/live.js.map +1 -0
  123. package/dist/lint/check.d.ts +81 -0
  124. package/dist/lint/check.js +208 -0
  125. package/dist/lint/check.js.map +1 -0
  126. package/dist/lint/config.d.ts +21 -0
  127. package/dist/lint/config.js +43 -0
  128. package/dist/lint/config.js.map +1 -0
  129. package/dist/lint/index.d.ts +31 -0
  130. package/dist/lint/index.js +43 -0
  131. package/dist/lint/index.js.map +1 -0
  132. package/dist/lint/project-rules.d.ts +19 -0
  133. package/dist/lint/project-rules.js +32 -0
  134. package/dist/lint/project-rules.js.map +1 -0
  135. package/dist/lint/report.d.ts +7 -0
  136. package/dist/lint/report.js +48 -0
  137. package/dist/lint/report.js.map +1 -0
  138. package/dist/lint/rules.d.ts +53 -0
  139. package/dist/lint/rules.js +42 -0
  140. package/dist/lint/rules.js.map +1 -0
  141. package/dist/lint/silences.d.ts +49 -0
  142. package/dist/lint/silences.js +91 -0
  143. package/dist/lint/silences.js.map +1 -0
  144. package/dist/lint/statements.d.ts +38 -0
  145. package/dist/lint/statements.js +120 -0
  146. package/dist/lint/statements.js.map +1 -0
  147. package/dist/migrations/checksum.d.ts +56 -0
  148. package/dist/migrations/checksum.js +72 -0
  149. package/dist/migrations/checksum.js.map +1 -0
  150. package/dist/migrations/create.d.ts +73 -0
  151. package/dist/migrations/create.js +119 -0
  152. package/dist/migrations/create.js.map +1 -0
  153. package/dist/migrations/directory.d.ts +119 -0
  154. package/dist/migrations/directory.js +225 -0
  155. package/dist/migrations/directory.js.map +1 -0
  156. package/dist/migrations/document.d.ts +83 -0
  157. package/dist/migrations/document.js +82 -0
  158. package/dist/migrations/document.js.map +1 -0
  159. package/dist/migrations/index.d.ts +20 -0
  160. package/dist/migrations/index.js +21 -0
  161. package/dist/migrations/index.js.map +1 -0
  162. package/dist/pr/comment.d.ts +32 -0
  163. package/dist/pr/comment.js +99 -0
  164. package/dist/pr/comment.js.map +1 -0
  165. package/dist/pr/forge.d.ts +50 -0
  166. package/dist/pr/forge.js +105 -0
  167. package/dist/pr/forge.js.map +1 -0
  168. package/dist/pr/model.d.ts +91 -0
  169. package/dist/pr/model.js +113 -0
  170. package/dist/pr/model.js.map +1 -0
  171. package/dist/pr/render.d.ts +27 -0
  172. package/dist/pr/render.js +246 -0
  173. package/dist/pr/render.js.map +1 -0
  174. package/dist/project.d.ts +62 -0
  175. package/dist/project.js +92 -0
  176. package/dist/project.js.map +1 -0
  177. package/dist/rebase/index.d.ts +121 -0
  178. package/dist/rebase/index.js +390 -0
  179. package/dist/rebase/index.js.map +1 -0
  180. package/dist/rebase/repair.d.ts +41 -0
  181. package/dist/rebase/repair.js +68 -0
  182. package/dist/rebase/repair.js.map +1 -0
  183. package/dist/replay/clickhouse.d.ts +33 -0
  184. package/dist/replay/clickhouse.js +106 -0
  185. package/dist/replay/clickhouse.js.map +1 -0
  186. package/dist/replay/index.d.ts +36 -0
  187. package/dist/replay/index.js +54 -0
  188. package/dist/replay/index.js.map +1 -0
  189. package/dist/replay/postgres.d.ts +31 -0
  190. package/dist/replay/postgres.js +140 -0
  191. package/dist/replay/postgres.js.map +1 -0
  192. package/dist/replay/replay.d.ts +114 -0
  193. package/dist/replay/replay.js +98 -0
  194. package/dist/replay/replay.js.map +1 -0
  195. package/dist/replay/report.d.ts +18 -0
  196. package/dist/replay/report.js +72 -0
  197. package/dist/replay/report.js.map +1 -0
  198. package/dist/steps/backfill.d.ts +128 -0
  199. package/dist/steps/backfill.js +307 -0
  200. package/dist/steps/backfill.js.map +1 -0
  201. package/dist/steps/index.d.ts +52 -0
  202. package/dist/steps/index.js +52 -0
  203. package/dist/steps/index.js.map +1 -0
  204. package/dist/steps/kinds.d.ts +101 -0
  205. package/dist/steps/kinds.js +143 -0
  206. package/dist/steps/kinds.js.map +1 -0
  207. package/dist/steps/postgres-migration.d.ts +95 -0
  208. package/dist/steps/postgres-migration.js +149 -0
  209. package/dist/steps/postgres-migration.js.map +1 -0
  210. package/dist/steps/rebuild.d.ts +97 -0
  211. package/dist/steps/rebuild.js +162 -0
  212. package/dist/steps/rebuild.js.map +1 -0
  213. package/dist/steps/run.d.ts +45 -0
  214. package/dist/steps/run.js +72 -0
  215. package/dist/steps/run.js.map +1 -0
  216. package/dist/topology/render.d.ts +17 -0
  217. package/dist/topology/render.js +17 -0
  218. package/dist/topology/render.js.map +1 -0
  219. package/dist/version.d.ts +2 -0
  220. package/dist/version.js +11 -0
  221. package/dist/version.js.map +1 -0
  222. package/dist/versioned/approval.d.ts +35 -0
  223. package/dist/versioned/approval.js +53 -0
  224. package/dist/versioned/approval.js.map +1 -0
  225. package/dist/versioned/clickhouse.d.ts +24 -0
  226. package/dist/versioned/clickhouse.js +34 -0
  227. package/dist/versioned/clickhouse.js.map +1 -0
  228. package/dist/versioned/digest.d.ts +77 -0
  229. package/dist/versioned/digest.js +69 -0
  230. package/dist/versioned/digest.js.map +1 -0
  231. package/dist/versioned/driver.d.ts +41 -0
  232. package/dist/versioned/driver.js +13 -0
  233. package/dist/versioned/driver.js.map +1 -0
  234. package/dist/versioned/engine.d.ts +152 -0
  235. package/dist/versioned/engine.js +277 -0
  236. package/dist/versioned/engine.js.map +1 -0
  237. package/dist/versioned/explain.d.ts +123 -0
  238. package/dist/versioned/explain.js +289 -0
  239. package/dist/versioned/explain.js.map +1 -0
  240. package/dist/versioned/index.d.ts +37 -0
  241. package/dist/versioned/index.js +54 -0
  242. package/dist/versioned/index.js.map +1 -0
  243. package/dist/versioned/op.d.ts +62 -0
  244. package/dist/versioned/op.js +153 -0
  245. package/dist/versioned/op.js.map +1 -0
  246. package/dist/versioned/postgres/catalog.d.ts +33 -0
  247. package/dist/versioned/postgres/catalog.js +34 -0
  248. package/dist/versioned/postgres/catalog.js.map +1 -0
  249. package/dist/versioned/postgres/driver.d.ts +69 -0
  250. package/dist/versioned/postgres/driver.js +113 -0
  251. package/dist/versioned/postgres/driver.js.map +1 -0
  252. package/dist/versioned/postgres/executor.d.ts +104 -0
  253. package/dist/versioned/postgres/executor.js +172 -0
  254. package/dist/versioned/postgres/executor.js.map +1 -0
  255. package/dist/versioned/postgres/index.d.ts +11 -0
  256. package/dist/versioned/postgres/index.js +12 -0
  257. package/dist/versioned/postgres/index.js.map +1 -0
  258. package/dist/versioned/report.d.ts +22 -0
  259. package/dist/versioned/report.js +81 -0
  260. package/dist/versioned/report.js.map +1 -0
  261. package/dist/versioned/state.d.ts +108 -0
  262. package/dist/versioned/state.js +153 -0
  263. package/dist/versioned/state.js.map +1 -0
  264. package/package.json +51 -4
@@ -0,0 +1,99 @@
1
+ /**
2
+ * One comment per environment on the pull request: found by its marker and
3
+ * updated, else created. The three forges' REST APIs:
4
+ *
5
+ * GitHub GET/POST {api}/repos/{owner}/{repo}/issues/{n}/comments
6
+ * PATCH {api}/repos/{owner}/{repo}/issues/comments/{id}
7
+ * GitLab GET/POST {api}/projects/{id}/merge_requests/{iid}/notes
8
+ * PUT {api}/projects/{id}/merge_requests/{iid}/notes/{note_id}
9
+ * Forgejo GET/POST {api}/repos/{owner}/{repo}/issues/{n}/comments (Gitea's API, /api/v1)
10
+ * PATCH {api}/repos/{owner}/{repo}/issues/comments/{id}
11
+ */
12
+ import { YodelError } from "../project.js";
13
+ const PAGE = 100;
14
+ const MAX_PAGES = 50;
15
+ function client(t, f, shape) {
16
+ const call = async (method, url, body) => {
17
+ let res;
18
+ try {
19
+ res = await f(url, { method, headers: { ...shape.headers, ...(body ? { "Content-Type": "application/json" } : {}) }, ...(body ? { body: JSON.stringify(body) } : {}) });
20
+ }
21
+ catch (e) {
22
+ throw new YodelError(`${t.forge}: ${method} ${url} failed: ${e instanceof Error ? e.message : String(e)}`);
23
+ }
24
+ const text = await res.text();
25
+ if (!res.ok)
26
+ throw new YodelError(`${t.forge}: ${method} ${url} answered ${String(res.status)}: ${text.slice(0, 300).replaceAll(t.token, "[token]")}`);
27
+ return text ? JSON.parse(text) : {};
28
+ };
29
+ const toComment = (c) => ({ id: Number(c.id), body: typeof c.body === "string" ? c.body : "", url: shape.webUrl?.(c) ?? (typeof c.html_url === "string" ? c.html_url : undefined) });
30
+ return {
31
+ async list() {
32
+ const all = [];
33
+ for (let page = 1; page <= MAX_PAGES; page++) {
34
+ const got = (await call("GET", shape.list(page)));
35
+ if (!Array.isArray(got))
36
+ throw new YodelError(`${t.forge}: listing comments did not return a list`);
37
+ all.push(...got.filter((c) => shape.keep?.(c) ?? true).map(toComment));
38
+ if (got.length < PAGE)
39
+ break;
40
+ }
41
+ return all;
42
+ },
43
+ async create(body) {
44
+ return toComment((await call("POST", shape.create, { body })));
45
+ },
46
+ async update(id, body) {
47
+ return toComment((await call(shape.updateMethod, shape.update(id), { body })));
48
+ },
49
+ };
50
+ }
51
+ const repoPath = (repo) => repo.split("/").map(encodeURIComponent).join("/");
52
+ export function commentClient(t, f = fetch) {
53
+ if (t.forge === "gitlab") {
54
+ const base = `${t.apiUrl}/projects/${encodeURIComponent(t.repo)}/merge_requests/${String(t.pr)}/notes`;
55
+ return client(t, f, {
56
+ headers: { "PRIVATE-TOKEN": t.token, Accept: "application/json" },
57
+ list: (page) => `${base}?per_page=${String(PAGE)}&page=${String(page)}&sort=asc&order_by=created_at`,
58
+ create: base,
59
+ update: (id) => `${base}/${String(id)}`,
60
+ updateMethod: "PUT",
61
+ // System notes ("added 1 commit") are the forge's own, never ours.
62
+ keep: (c) => c.system !== true,
63
+ });
64
+ }
65
+ if (t.forge === "forgejo") {
66
+ const base = `${t.apiUrl}/repos/${repoPath(t.repo)}/issues`;
67
+ return client(t, f, {
68
+ headers: { Authorization: `token ${t.token}`, Accept: "application/json" },
69
+ list: (page) => `${base}/${String(t.pr)}/comments?limit=${String(PAGE)}&page=${String(page)}`,
70
+ create: `${base}/${String(t.pr)}/comments`,
71
+ update: (id) => `${base}/comments/${String(id)}`,
72
+ updateMethod: "PATCH",
73
+ });
74
+ }
75
+ const base = `${t.apiUrl}/repos/${repoPath(t.repo)}/issues`;
76
+ return client(t, f, {
77
+ headers: { Authorization: `Bearer ${t.token}`, Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28" },
78
+ list: (page) => `${base}/${String(t.pr)}/comments?per_page=${String(PAGE)}&page=${String(page)}`,
79
+ create: `${base}/${String(t.pr)}/comments`,
80
+ update: (id) => `${base}/comments/${String(id)}`,
81
+ updateMethod: "PATCH",
82
+ });
83
+ }
84
+ /** The comment carrying `marker`, the newest when several do. */
85
+ export async function findComment(c, marker) {
86
+ return (await c.list()).filter((x) => x.body.includes(marker)).at(-1);
87
+ }
88
+ /** Updates the comment carrying `marker`, or creates one. */
89
+ export async function upsertComment(c, marker, body, existing) {
90
+ if (!body.includes(marker))
91
+ throw new YodelError("the comment body has no marker; it could never be found again to update");
92
+ const found = existing ?? (await findComment(c, marker));
93
+ if (!found)
94
+ return { action: "created", comment: await c.create(body) };
95
+ if (found.body === body)
96
+ return { action: "unchanged", comment: found };
97
+ return { action: "updated", comment: await c.update(found.id, body) };
98
+ }
99
+ //# sourceMappingURL=comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/pr/comment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Where `yodel plan <env> --comment` posts: the forge, the repository, the
3
+ * pull (merge) request and the token, from the CI job's environment, each
4
+ * overridden by a flag.
5
+ *
6
+ * - GitHub Actions: `GITHUB_ACTIONS=true`. `GITHUB_REPOSITORY`, the PR number
7
+ * from the event payload (`GITHUB_EVENT_PATH`: `pull_request.number`, or
8
+ * `refs/pull/<n>/merge` in `GITHUB_REF`), `GITHUB_API_URL` (default
9
+ * https://api.github.com), token `GITHUB_TOKEN`.
10
+ * - GitLab CI: `GITLAB_CI=true`. `CI_API_V4_URL`, `CI_PROJECT_ID`,
11
+ * `CI_MERGE_REQUEST_IID` (a merge request pipeline), token `GITLAB_TOKEN`
12
+ * (a project or personal access token with `api` scope: `CI_JOB_TOKEN`
13
+ * cannot write merge request notes).
14
+ * - Forgejo Actions: `FORGEJO_ACTIONS=true` (runner 7 and later), or
15
+ * `GITEA_ACTIONS=true`, or a GitHub-style job whose API URL ends in
16
+ * `/api/v1`. `FORGEJO_REPOSITORY` / `GITHUB_REPOSITORY`, the PR number from
17
+ * `FORGEJO_EVENT_PATH` / `GITHUB_EVENT_PATH` or the ref, `FORGEJO_API_URL` /
18
+ * `GITHUB_API_URL` (else `<server>/api/v1`), token `FORGEJO_TOKEN` /
19
+ * `GITHUB_TOKEN`.
20
+ *
21
+ * `--token-env <NAME>` names the variable the token is read from; the token
22
+ * itself is never a flag, never printed and never put in an error.
23
+ */
24
+ export type ForgeKind = "github" | "gitlab" | "forgejo";
25
+ export declare const FORGES: readonly ForgeKind[];
26
+ export interface ForgeTarget {
27
+ forge: ForgeKind;
28
+ /** `owner/name` (GitHub, Forgejo), or the project id or path (GitLab). */
29
+ repo: string;
30
+ /** The PR number (GitHub, Forgejo) or MR iid (GitLab). */
31
+ pr: number;
32
+ /** The REST API's base, e.g. https://api.github.com, https://gitlab.com/api/v4, https://codeberg.org/api/v1. */
33
+ apiUrl: string;
34
+ token: string;
35
+ /** The variable the token came from, for messages. */
36
+ tokenEnv: string;
37
+ }
38
+ export interface ForgeFlags {
39
+ forge?: string | undefined;
40
+ repo?: string | undefined;
41
+ pr?: string | undefined;
42
+ apiUrl?: string | undefined;
43
+ tokenEnv?: string | undefined;
44
+ }
45
+ /** Which forge the job runs on, from its environment; `undefined` outside a known CI. */
46
+ export declare function detectForge(env: NodeJS.ProcessEnv): ForgeKind | undefined;
47
+ /** The PR number from a GitHub-style event payload, or from the ref. */
48
+ export declare function prFromEvent(eventPath: string | undefined, ref: string | undefined): number | undefined;
49
+ /** Resolves the target from flags and the environment, or says what is missing. */
50
+ export declare function resolveForgeTarget(flags: ForgeFlags, env: NodeJS.ProcessEnv): ForgeTarget;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Where `yodel plan <env> --comment` posts: the forge, the repository, the
3
+ * pull (merge) request and the token, from the CI job's environment, each
4
+ * overridden by a flag.
5
+ *
6
+ * - GitHub Actions: `GITHUB_ACTIONS=true`. `GITHUB_REPOSITORY`, the PR number
7
+ * from the event payload (`GITHUB_EVENT_PATH`: `pull_request.number`, or
8
+ * `refs/pull/<n>/merge` in `GITHUB_REF`), `GITHUB_API_URL` (default
9
+ * https://api.github.com), token `GITHUB_TOKEN`.
10
+ * - GitLab CI: `GITLAB_CI=true`. `CI_API_V4_URL`, `CI_PROJECT_ID`,
11
+ * `CI_MERGE_REQUEST_IID` (a merge request pipeline), token `GITLAB_TOKEN`
12
+ * (a project or personal access token with `api` scope: `CI_JOB_TOKEN`
13
+ * cannot write merge request notes).
14
+ * - Forgejo Actions: `FORGEJO_ACTIONS=true` (runner 7 and later), or
15
+ * `GITEA_ACTIONS=true`, or a GitHub-style job whose API URL ends in
16
+ * `/api/v1`. `FORGEJO_REPOSITORY` / `GITHUB_REPOSITORY`, the PR number from
17
+ * `FORGEJO_EVENT_PATH` / `GITHUB_EVENT_PATH` or the ref, `FORGEJO_API_URL` /
18
+ * `GITHUB_API_URL` (else `<server>/api/v1`), token `FORGEJO_TOKEN` /
19
+ * `GITHUB_TOKEN`.
20
+ *
21
+ * `--token-env <NAME>` names the variable the token is read from; the token
22
+ * itself is never a flag, never printed and never put in an error.
23
+ */
24
+ import { readFileSync } from "node:fs";
25
+ import { YodelError } from "../project.js";
26
+ export const FORGES = ["github", "gitlab", "forgejo"];
27
+ const truthy = (v) => v === "true" || v === "1";
28
+ /** Which forge the job runs on, from its environment; `undefined` outside a known CI. */
29
+ export function detectForge(env) {
30
+ if (truthy(env.GITLAB_CI))
31
+ return "gitlab";
32
+ if (truthy(env.FORGEJO_ACTIONS) || truthy(env.GITEA_ACTIONS))
33
+ return "forgejo";
34
+ if (truthy(env.GITHUB_ACTIONS))
35
+ return /\/api\/v1\/?$/.test(env.GITHUB_API_URL ?? "") ? "forgejo" : "github";
36
+ return undefined;
37
+ }
38
+ /** The PR number from a GitHub-style event payload, or from the ref. */
39
+ export function prFromEvent(eventPath, ref) {
40
+ if (eventPath) {
41
+ try {
42
+ const event = JSON.parse(readFileSync(eventPath, "utf8"));
43
+ const n = event.pull_request?.number ?? (event.issue?.pull_request ? event.issue.number : undefined) ?? (event.pull_request ? event.number : undefined);
44
+ if (typeof n === "number" && Number.isInteger(n) && n > 0)
45
+ return n;
46
+ }
47
+ catch {
48
+ // Unreadable payload: fall back to the ref.
49
+ }
50
+ }
51
+ const m = /^refs\/pull\/(\d+)\/(?:merge|head)$/.exec(ref ?? "");
52
+ return m ? Number(m[1]) : undefined;
53
+ }
54
+ const DEFAULT_TOKEN_ENV = {
55
+ github: ["GITHUB_TOKEN"],
56
+ gitlab: ["GITLAB_TOKEN"],
57
+ forgejo: ["FORGEJO_TOKEN", "GITHUB_TOKEN"],
58
+ };
59
+ /** Resolves the target from flags and the environment, or says what is missing. */
60
+ export function resolveForgeTarget(flags, env) {
61
+ if (flags.forge !== undefined && !FORGES.includes(flags.forge))
62
+ throw new YodelError(`--forge must be one of ${FORGES.join(", ")}, got ${JSON.stringify(flags.forge)}`);
63
+ const forge = flags.forge ?? detectForge(env);
64
+ if (!forge)
65
+ throw new YodelError("--comment cannot tell the forge: not a GitHub Actions, GitLab CI or Forgejo Actions job; pass --forge github|gitlab|forgejo with --repo, --pr and --api-url");
66
+ const pick = (...names) => names.map((n) => env[n]).find((v) => v !== undefined && v !== "");
67
+ let repo = flags.repo;
68
+ let pr = flags.pr !== undefined ? Number(flags.pr) : undefined;
69
+ let apiUrl = flags.apiUrl;
70
+ if (forge === "gitlab") {
71
+ repo ??= pick("CI_PROJECT_ID", "CI_PROJECT_PATH");
72
+ pr ??= pick("CI_MERGE_REQUEST_IID") !== undefined ? Number(pick("CI_MERGE_REQUEST_IID")) : undefined;
73
+ apiUrl ??= pick("CI_API_V4_URL");
74
+ }
75
+ else {
76
+ const p = forge === "forgejo" ? "FORGEJO_" : "GITHUB_";
77
+ repo ??= pick(`${p}REPOSITORY`, "GITHUB_REPOSITORY");
78
+ pr ??= prFromEvent(pick(`${p}EVENT_PATH`, "GITHUB_EVENT_PATH"), pick(`${p}REF`, "GITHUB_REF"));
79
+ apiUrl ??= pick(`${p}API_URL`, "GITHUB_API_URL");
80
+ if (!apiUrl && forge === "forgejo") {
81
+ const server = pick("FORGEJO_SERVER_URL", "GITHUB_SERVER_URL");
82
+ if (server)
83
+ apiUrl = `${server.replace(/\/+$/, "")}/api/v1`;
84
+ }
85
+ if (!apiUrl && forge === "github")
86
+ apiUrl = "https://api.github.com";
87
+ }
88
+ const missing = [];
89
+ if (!repo)
90
+ missing.push(forge === "gitlab" ? "the project (--repo, or CI_PROJECT_ID)" : "the repository (--repo owner/name, or GITHUB_REPOSITORY)");
91
+ if (pr === undefined || !Number.isInteger(pr) || pr <= 0) {
92
+ missing.push(forge === "gitlab" ? "the merge request (--pr, or CI_MERGE_REQUEST_IID in a merge request pipeline)" : "the pull request (--pr, or a pull_request event)");
93
+ }
94
+ if (!apiUrl)
95
+ missing.push(forge === "gitlab" ? "the API URL (--api-url, or CI_API_V4_URL)" : "the API URL (--api-url, or FORGEJO_API_URL / GITHUB_API_URL)");
96
+ const names = flags.tokenEnv ? [flags.tokenEnv] : DEFAULT_TOKEN_ENV[forge];
97
+ const tokenEnv = names.find((n) => env[n]) ?? names[0] ?? "";
98
+ const token = env[tokenEnv] ?? "";
99
+ if (!token)
100
+ missing.push(`a token (${names.join(" or ")} is not set${flags.tokenEnv ? "" : "; name another variable with --token-env"})`);
101
+ if (missing.length > 0)
102
+ throw new YodelError(`--comment on ${forge} needs ${missing.join(", ")}`);
103
+ return { forge, repo: repo, pr: pr, apiUrl: apiUrl.replace(/\/+$/, ""), token, tokenEnv };
104
+ }
105
+ //# sourceMappingURL=forge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forge.js","sourceRoot":"","sources":["../../src/pr/forge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * The versioned plan (#16): what `yodel plan <env>` shows for a project
3
+ * with migrations, and what the pull request comment renders. Collected once,
4
+ * rendered as text, markdown or JSON (`./render.ts`).
5
+ *
6
+ * The digest is `statusReport`'s, the value `yodel apply <env> --digest` (the
7
+ * migrations Op's Plan step) prints and the gate binds, so the
8
+ * `chant approve <op> <gate> --plan <digest>` the comment prints is the one
9
+ * the post-merge apply needs. Nothing here writes: no lock, no history row,
10
+ * no ledger entry.
11
+ */
12
+ import type { MigrationStep } from "@intentius/chant-lexicon-sql/migration-statements";
13
+ import type { GateLedgerPort } from "@intentius/chant/op/gate";
14
+ import { type Environment, type Project, type SqlDialect } from "../project.js";
15
+ import { type MigrateOpRef, type VersionedEnv } from "../versioned/index.js";
16
+ import { type LatestApproval, type MoveExplanation } from "../versioned/explain.js";
17
+ import type { DigestSubject } from "../versioned/digest.js";
18
+ export interface StepView {
19
+ index: number;
20
+ step: MigrationStep;
21
+ /** Succeeded in an earlier run; not sent again. */
22
+ done: boolean;
23
+ /** An Op or manual step apply does not run, and why; any of them refuses the run. */
24
+ refused?: string | undefined;
25
+ /** A backfill step's module, as the migration's directory holds it. */
26
+ source?: {
27
+ file: string;
28
+ text: string;
29
+ } | undefined;
30
+ }
31
+ export interface PendingView {
32
+ id: string;
33
+ outOfOrder: boolean;
34
+ /** Where a migration that ran part way resumes. */
35
+ resumeAt?: number | undefined;
36
+ steps: StepView[];
37
+ }
38
+ export type ApprovalView = {
39
+ kind: "no-op";
40
+ message: string;
41
+ } | {
42
+ kind: "op";
43
+ op: string;
44
+ gate: string;
45
+ /** The command that approves this plan; absent when there is no digest. */
46
+ command?: string | undefined;
47
+ /** The newest approval of the gate in chant's ledger, when it could be read. */
48
+ latest?: (LatestApproval & {
49
+ moved?: MoveExplanation | undefined;
50
+ }) | undefined;
51
+ /** Why the ledger was not read. */
52
+ ledgerNote?: string | undefined;
53
+ };
54
+ export interface VersionedPlan {
55
+ environment: string;
56
+ dialect: SqlDialect;
57
+ /** `<database>.history (<topology> (<where it came from>))`; Postgres has no topology, so only `<database>.history`. */
58
+ history?: string | undefined;
59
+ appliedCount: number;
60
+ pending: PendingView[];
61
+ /** Directory problems, checksum mismatches, out-of-order migrations. */
62
+ problems: string[];
63
+ /** Why `yodel apply` would refuse, with its exit code. */
64
+ refusal?: {
65
+ exitCode: number;
66
+ message: string;
67
+ } | undefined;
68
+ /** The digest the gate binds; absent when apply would refuse or has nothing to do. */
69
+ digest?: string | undefined;
70
+ /** What the digest is taken over, carried in the comment so a later one can say what moved. */
71
+ subject?: DigestSubject | undefined;
72
+ approval?: ApprovalView | undefined;
73
+ /** The comment this one replaces showed another digest: what moved since. */
74
+ sinceLast?: MoveExplanation | undefined;
75
+ notes: string[];
76
+ }
77
+ export interface CollectOptions {
78
+ allowOutOfOrder?: boolean;
79
+ /** The subject the previous comment carried, when updating one. */
80
+ previous?: DigestSubject | undefined;
81
+ /** The gate ledger; default chant's, in the project's git checkout. `null` skips it. */
82
+ ledger?: GateLedgerPort | null;
83
+ /** The migrations Op; default discovered in the project. */
84
+ op?: MigrateOpRef | null;
85
+ opName?: string | undefined;
86
+ processEnv?: NodeJS.ProcessEnv;
87
+ /** For tests: the environment already bound. */
88
+ venv?: VersionedEnv;
89
+ }
90
+ /** Collects the plan; throws only when the project or the server cannot be read at all. */
91
+ export declare function collectVersionedPlan(project: Project, env: Environment, options?: CollectOptions): Promise<VersionedPlan>;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The versioned plan (#16): what `yodel plan <env>` shows for a project
3
+ * with migrations, and what the pull request comment renders. Collected once,
4
+ * rendered as text, markdown or JSON (`./render.ts`).
5
+ *
6
+ * The digest is `statusReport`'s, the value `yodel apply <env> --digest` (the
7
+ * migrations Op's Plan step) prints and the gate binds, so the
8
+ * `chant approve <op> <gate> --plan <digest>` the comment prints is the one
9
+ * the post-merge apply needs. Nothing here writes: no lock, no history row,
10
+ * no ledger entry.
11
+ */
12
+ import { YodelError } from "../project.js";
13
+ import { scanMigrations } from "../migrations/index.js";
14
+ import { describeTopology } from "../history/index.js";
15
+ import { asBackfill } from "../steps/kinds.js";
16
+ import { findMigrateOp, gitLedger, migrateOpExample, migrationsDir, closeVersioned, openVersioned, outOfOrder, planDigest, sameDigest, statusReport, } from "../versioned/index.js";
17
+ import { currentSubject, explainAgainst, explainMove, latestApproval } from "../versioned/explain.js";
18
+ const viewOf = (m, done = [], outOfOrder = false, resumeAt, refused = []) => ({
19
+ id: m.id,
20
+ outOfOrder,
21
+ resumeAt,
22
+ steps: m.document.steps.map((step, index) => {
23
+ const file = asBackfill(step)?.options.file;
24
+ const text = file === undefined ? undefined : m.files.extra?.[file];
25
+ return { index, step, done: done.includes(index), refused: refused.find((r) => r.index === index)?.reason, ...(file !== undefined && text !== undefined ? { source: { file, text } } : {}) };
26
+ }),
27
+ });
28
+ /** Collects the plan; throws only when the project or the server cannot be read at all. */
29
+ export async function collectVersionedPlan(project, env, options = {}) {
30
+ const dir = migrationsDir(project);
31
+ const scan = scanMigrations(dir);
32
+ const problems = scan.problems.map((p) => p.message);
33
+ const base = { environment: env.name, dialect: project.dialect, problems, notes: [] };
34
+ if (!scan.ordered) {
35
+ return { ...base, appliedCount: 0, pending: [], refusal: { exitCode: 1, message: "the migrations directory is not one unbroken chain; nothing can be applied until it is" } };
36
+ }
37
+ const ordered = scan.ordered;
38
+ const venv = options.venv ?? (await openVersioned(project, env, options.processEnv));
39
+ try {
40
+ return await collectWith(project, env, options, venv, ordered, base, problems);
41
+ }
42
+ finally {
43
+ if (!options.venv)
44
+ await closeVersioned(venv);
45
+ }
46
+ }
47
+ async function collectWith(project, env, options, venv, ordered, base, problems) {
48
+ const report = await statusReport(venv, ordered, { allowOutOfOrder: options.allowOutOfOrder === true, sync: false });
49
+ const { status } = report;
50
+ for (const m of status.mismatches)
51
+ if (!problems.includes(m.message))
52
+ problems.push(m.message);
53
+ const late = outOfOrder(status);
54
+ if (late.length > 0)
55
+ problems.push(`out of order: ${late.map((p) => p.id).join(", ")} (the chain puts ${late.length === 1 ? "it" : "them"} before a migration already applied)`);
56
+ let subject;
57
+ if (report.digest) {
58
+ subject = await currentSubject(venv, status, status.pending);
59
+ // Read twice (the report's, then here): if the server moved in between, carry no subject rather than a wrong one.
60
+ if (!(await sameDigest(await planDigest(subject), report.digest)))
61
+ subject = undefined;
62
+ }
63
+ const plan = {
64
+ ...base,
65
+ history: venv.dialect === "postgres" ? `${venv.location.database}.history` : `${venv.location.database}.history (${report.topology ?? describeTopology(venv.location.topology)})`,
66
+ appliedCount: status.applied.length,
67
+ pending: status.pending.map((p) => viewOf(p.migration, p.partWay?.done ?? [], p.outOfOrder, p.partWay?.resumeAt, p.refusedSteps)),
68
+ refusal: report.refusal,
69
+ digest: report.digest,
70
+ subject,
71
+ };
72
+ if (options.previous && subject) {
73
+ const prev = await planDigest(options.previous);
74
+ if (!(await sameDigest(prev, report.digest)))
75
+ plan.sinceLast = await explainMove({ approvedDigest: prev, now: subject, previous: options.previous, ordered, applied: status.applied });
76
+ }
77
+ plan.approval = await approvalView(project, env, venv, ordered, plan, options);
78
+ return plan;
79
+ }
80
+ async function approvalView(project, env, venv, ordered, plan, options) {
81
+ let op;
82
+ try {
83
+ op = options.op ?? (await findMigrateOp(project, env, options.opName));
84
+ }
85
+ catch (e) {
86
+ if (!(e instanceof YodelError))
87
+ throw e;
88
+ return { kind: "no-op", message: e.message.includes("no Op applies") ? `no Op applies the migrations to ${env.name}; declare one, for example:\n\n${migrateOpExample(env.name)}` : e.message };
89
+ }
90
+ const view = {
91
+ kind: "op",
92
+ op: op.name,
93
+ gate: op.gate,
94
+ command: plan.digest ? `chant approve ${op.name} ${op.gate} --plan ${plan.digest}` : undefined,
95
+ };
96
+ if (options.ledger === null)
97
+ return view;
98
+ try {
99
+ const ledger = options.ledger ?? (await gitLedger(project.dir));
100
+ const latest = await latestApproval(ledger, op, plan.digest);
101
+ if (!latest)
102
+ return view;
103
+ view.latest = latest;
104
+ if (!latest.holds && !latest.sameDigest && latest.digest && plan.subject) {
105
+ view.latest.moved = await explainAgainst(venv, ordered, { approvedDigest: latest.digest, approvedAt: latest.at, now: plan.subject, previous: options.previous });
106
+ }
107
+ }
108
+ catch (e) {
109
+ view.ledgerNote = `chant's gate ledger could not be read (${e instanceof Error ? (e.message.split("\n")[0] ?? "") : String(e)}); fetch the chant/lifecycle branch to see approvals here`;
110
+ }
111
+ return view;
112
+ }
113
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/pr/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The versioned plan as text (`yodel plan <env>`), as the pull request
3
+ * comment's markdown (`--format markdown`, `--comment`) and as JSON.
4
+ *
5
+ * The comment starts with a hidden marker, `<!-- yodel:plan env=<env> -->`,
6
+ * by which `--comment` finds the comment it posted before and updates it,
7
+ * and ends with the digest's subject, hidden, so the next comment can say
8
+ * what moved. Neither holds a secret: migration ids, checksums, a hash of
9
+ * the live catalog. Server addresses and tokens are never rendered.
10
+ */
11
+ import type { VersionedPlan } from "./model.js";
12
+ /** The marker that identifies one environment's plan comment. */
13
+ export declare const commentMarker: (env: string) => string;
14
+ /** The subject a comment body carries, encoded. */
15
+ export declare const subjectIn: (body: string) => string | undefined;
16
+ /** GitHub refuses a comment over 65536 characters; GitLab and Forgejo allow more. */
17
+ export declare const COMMENT_LIMIT = 65000;
18
+ /** Values a statement may quote that do not belong in a comment, though the file is in the repo. */
19
+ export declare function redact(sql: string): string;
20
+ /** `yodel plan <env>` for a project with migrations. */
21
+ export declare function renderPlanText(plan: VersionedPlan): string;
22
+ /** The pull request comment body. */
23
+ export declare function renderPlanMarkdown(plan: VersionedPlan, options?: {
24
+ sql?: boolean;
25
+ }): string;
26
+ /** `yodel plan <env> --json` for a project with migrations. */
27
+ export declare function planJsonVersioned(plan: VersionedPlan): Record<string, unknown>;