@intentius/chant 0.124.6 → 0.124.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/lifecycle/rollback.ts"],"names":[],"mappings":"AAkBA,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,qCAAqC;AACrC,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAO5F;AAED,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC,cAAc,CAAC,CAqD1B"}
1
+ {"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/lifecycle/rollback.ts"],"names":[],"mappings":"AAmBA,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,qCAAqC;AACrC,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAO5F;AAED,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC,cAAc,CAAC,CA4D1B"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Where chant's own pull-request paths open their pull request (#3798).
3
+ *
4
+ * `reconcilePr`'s `pull-request` mode, `lexiconUpgrade`, rollback and
5
+ * `proposeWorkspaceUpgrade` open a pull request with `gh pr`. `gh pr create`,
6
+ * `view`, `edit` and `list` speak GitHub's GraphQL API, which Forgejo does not
7
+ * serve, so #3780's `GH_HOST` sends them to the right Forgejo instance only
8
+ * for them to fail there. GitLab has no `gh` at all. On those two forges each
9
+ * path opens, finds and edits its pull request over REST through
10
+ * `../../pr-forge.ts` instead. GitHub, and a run outside any CI job, keep
11
+ * `gh` and the operator's own `gh auth login`.
12
+ *
13
+ * The forge and its token come from the CI job's environment
14
+ * ({@link forgeTargetFromEnv}). The repository is the one the checkout's
15
+ * remote names, when that remote is on the job's forge, so a path working in
16
+ * another checkout than the job's own still opens its pull request there.
17
+ */
18
+ import { type ForgeFetch, type PrForge, type PullRequest, type PullRequestSpec } from "../../pr-forge.js";
19
+ type Env = Record<string, string | undefined>;
20
+ /** The repository path a git remote URL names: `owner/name`, or `group/sub/name` on GitLab. */
21
+ export declare function remoteRepoPath(url: string | undefined): string | undefined;
22
+ export interface PullRequestForgeOptions {
23
+ /** A checkout whose remote names the repository. Default: the job's repository. */
24
+ cwd?: string;
25
+ /** The remote in `cwd`. Default `origin`. */
26
+ remote?: string;
27
+ fetch?: ForgeFetch;
28
+ /** Reads a remote's URL. Default `git remote get-url`. For tests. */
29
+ remoteUrl?: (cwd: string, remote: string) => Promise<string | undefined>;
30
+ }
31
+ /**
32
+ * The REST client a pull request is opened through, or undefined when `gh`
33
+ * serves: on GitHub, and outside a CI job. A Forgejo or GitLab job that lacks
34
+ * a token or a repository throws `ForgeEnvironmentError` naming it, where
35
+ * `gh pr` would have failed on GraphQL.
36
+ */
37
+ export declare function restPullRequestForge(env?: Env, opts?: PullRequestForgeOptions): Promise<PrForge | undefined>;
38
+ /** What {@link upsertPullRequest} did. */
39
+ export interface UpsertedPullRequest {
40
+ action: "opened" | "updated" | "unchanged";
41
+ pr: PullRequest;
42
+ }
43
+ /**
44
+ * Open a pull request for `spec.head`, or bring the open one's title and
45
+ * body in line with `spec`. An open one already current is left alone.
46
+ */
47
+ export declare function upsertPullRequest(forge: PrForge, spec: PullRequestSpec): Promise<UpsertedPullRequest>;
48
+ export {};
49
+ //# sourceMappingURL=forge-pull-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forge-pull-request.d.ts","sourceRoot":"","sources":["../../../src/op/activities/forge-pull-request.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAgD,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKrJ,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAe1E;AAED,MAAM,WAAW,uBAAuB;IACtC,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,qEAAqE;IACrE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1E;AAUD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,GAAE,GAAiB,EAAE,IAAI,GAAE,uBAA4B,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAUnI;AAED,0CAA0C;AAC1C,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IAC3C,EAAE,EAAE,WAAW,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAM3G"}
@@ -25,6 +25,7 @@
25
25
  import type { UpgradeCheckResult, LexiconId, UpstreamPin } from "../../codegen/pinned-upgrade.js";
26
26
  import type { RollingUpgradeResult, RollingLexicon } from "../../codegen/rolling-upgrade.js";
27
27
  import { bumpPackageJsonVersion } from "../../codegen/version-bump.js";
28
+ import type { PrForge } from "../../pr-forge.js";
28
29
  export { bumpPackageJsonVersion };
29
30
  /** Finding mode, mirrors ReconcileOp's mode. */
30
31
  export type LexiconUpgradeMode = "report" | "issue" | "pull-request";
@@ -83,6 +84,12 @@ export interface LexiconUpgradeArgs {
83
84
  * Defaults to bumpPackageJsonVersion.
84
85
  */
85
86
  _bumpPackageVersion?: BumpPackageVersionFn;
87
+ /**
88
+ * The REST client the pull request is found, opened and labelled through,
89
+ * or null for `gh`. Default: one on a Forgejo or GitLab job, `gh`
90
+ * elsewhere (#3798). For tests.
91
+ */
92
+ _forge?: PrForge | null;
86
93
  }
87
94
  export interface LexiconUpgradeResult {
88
95
  lexicon: SupportedLexicon;
@@ -1 +1 @@
1
- {"version":3,"file":"lexicon-upgrade.d.ts","sourceRoot":"","sources":["../../../src/op/activities/lexicon-upgrade.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lexicon-upgrade.d.ts","sourceRoot":"","sources":["../../../src/op/activities/lexicon-upgrade.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,7 @@
22
22
  * The workspace code loads on first call, so importing core's activities
23
23
  * loads nothing under `workspace/` (#2525 rule 5).
24
24
  */
25
+ import type { PrForge } from "../../pr-forge.js";
25
26
  export type ProposeUpgradeMode = "report" | "branch" | "pull-request";
26
27
  export interface ProposeWorkspaceUpgradeArgs {
27
28
  /** The lineage scope: `"."` (default) or a vendor scope's directory. */
@@ -43,6 +44,11 @@ export interface ProposeWorkspaceUpgradeArgs {
43
44
  cwd?: string;
44
45
  /** Replaces the git and gh child processes. For tests. */
45
46
  _run?: CommandRunner;
47
+ /**
48
+ * The REST client the pull request is opened through, or null for `gh`.
49
+ * Default: one on a Forgejo or GitLab job, `gh` elsewhere (#3798). For tests.
50
+ */
51
+ _forge?: PrForge | null;
46
52
  /** Replaces build and lint in the worktree. For tests. */
47
53
  _runChant?: import("../../workspace/lineage-upgrade.js").ChantRunner;
48
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"propose-upgrade.d.ts","sourceRoot":"","sources":["../../../src/op/activities/propose-upgrade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AASH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEtE,MAAM,WAAW,2BAA2B;IAC1C,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gHAAgH;IAChH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6GAA6G;IAC7G,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,iCAAiC,EAAE,WAAW,CAAC;CACnE;AAED,uFAAuF;AACvF,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEhG,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,kBAAkB,CAAC;IACzB,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAiCD,6GAA6G;AAC7G,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,2BAA2B,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAmFvH"}
1
+ {"version":3,"file":"propose-upgrade.d.ts","sourceRoot":"","sources":["../../../src/op/activities/propose-upgrade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAI9C,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEtE,MAAM,WAAW,2BAA2B;IAC1C,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gHAAgH;IAChH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6GAA6G;IAC7G,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,iCAAiC,EAAE,WAAW,CAAC;CACnE;AAED,uFAAuF;AACvF,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEhG,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,kBAAkB,CAAC;IACzB,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD,uCAAuC;AACvC,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAiCD,6GAA6G;AAC7G,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,2BAA2B,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAyFvH"}
@@ -1 +1 @@
1
- {"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../../src/op/activities/reconcile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../../src/op/activities/reconcile.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,8 @@
2
2
  * What chant and the products built on it ask of a forge: keep one comment
3
3
  * (a merge request note on GitLab) on a pull request up to date, set a commit
4
4
  * status, keep one tracking issue in the repository, list who approved a pull
5
- * request, and find the pull request that merged a commit.
5
+ * request, find the pull request that merged a commit, and open or edit a
6
+ * pull request (a merge request on GitLab) for a branch.
6
7
  *
7
8
  * The pull-request loop (#3183) uses the note, the status and the review
8
9
  * calls. `reconcilePr`'s `comment` and `issue` finding modes post through the
@@ -21,6 +22,10 @@
21
22
  * `gitlab:<login>`, or `<forge>@<host>:<login>` off the forge's default host.
22
23
  * The apply compares that string with the approval's `resolvedBy`.
23
24
  *
25
+ * Opening a pull request goes over REST too (#3798): `gh pr` speaks GitHub's
26
+ * GraphQL, which Forgejo does not serve, so chant's own pull-request paths
27
+ * open theirs through {@link PrForge.openPullRequest} on Forgejo and GitLab.
28
+ *
24
29
  * Like `./pr-loop.ts`, this bundles without the TypeScript toolchain (#3421):
25
30
  * it imports nothing but `node:fs`, to read a CI job's event payload.
26
31
  * `./pr-forge-bundle.test.ts` holds it to that.
@@ -40,7 +45,13 @@ export type ForgeFetch = (url: string, init: {
40
45
  export interface ForgeStatus {
41
46
  /** The status's name, such as `chant/plan` or `terragucci/plan`. */
42
47
  context: string;
43
- state: "pending" | "success" | "failure";
48
+ /**
49
+ * GitLab's own states, plus GitHub's `failure` and `error`. Each forge gets
50
+ * the nearest state it has ({@link statusStateFor}): `running` is `pending`
51
+ * on GitHub and Forgejo, `canceled` is `error` there, and `failure` and
52
+ * `error` are `failed` on GitLab.
53
+ */
54
+ state: ForgeStatusState;
44
55
  /** Cut to what the forge keeps: 140 characters on GitHub and Forgejo, 255 on GitLab. */
45
56
  description: string;
46
57
  /** The pipeline run, linked from the status. */
@@ -48,6 +59,12 @@ export interface ForgeStatus {
48
59
  /** GitLab only: the pipeline the status belongs to. */
49
60
  pipelineId?: number;
50
61
  }
62
+ /** A commit status's state, as a caller names it. */
63
+ export type ForgeStatusState = "pending" | "running" | "success" | "failed" | "failure" | "canceled" | "error";
64
+ /** Every {@link ForgeStatusState}, for a caller that reads one from its own input. */
65
+ export declare const FORGE_STATUS_STATES: readonly ForgeStatusState[];
66
+ /** The state `kind` is sent for `state`. Forgejo takes GitHub's. */
67
+ export declare function statusStateFor(kind: ForgeKind, state: ForgeStatusState): string;
51
68
  /**
52
69
  * How a comment or an issue is told to be the caller's own. By default the
53
70
  * body starts with the marker, chant's recipe since #2291, and anyone may
@@ -57,12 +74,15 @@ export interface MarkerMatch {
57
74
  /** `prefix` (the default): the body starts with the marker. `anywhere`: the body carries it. */
58
75
  match?: "prefix" | "anywhere";
59
76
  /**
60
- * Only a comment or issue written by this login counts: `user.login` on
61
- * GitHub and Forgejo, `author.username` on GitLab, compared without case.
62
- * A merge request's author can write a note carrying any marker, so a
63
- * product that reads its own notes back names its bot here.
77
+ * Only a comment or issue written by this login, or by any of these
78
+ * logins, counts: `user.login` on GitHub and Forgejo, `author.username` on
79
+ * GitLab, compared without case. A merge request's author can write a note
80
+ * carrying any marker, so a product that reads its own notes back names
81
+ * its bot here. A list is for a bot whose login the job cannot know in
82
+ * advance, such as `gitea-actions` or `forgejo-actions` on Forgejo (#3834).
83
+ * An empty list matches nobody.
64
84
  */
65
- author?: string;
85
+ author?: string | readonly string[];
66
86
  }
67
87
  /** What {@link PrForge.upsertComment} did. */
68
88
  export interface CommentResult {
@@ -136,6 +156,32 @@ export interface IssueResult {
136
156
  /** When the issue was opened (the forge's `created_at`, ISO 8601), for an issue that exists after the call or was just closed. */
137
157
  created?: string;
138
158
  }
159
+ /** A pull request (merge request) for {@link PrForge.openPullRequest} to open. */
160
+ export interface PullRequestSpec {
161
+ /** The branch with the change, in the same repository. */
162
+ head: string;
163
+ /** The branch it merges into. Default: the repository's default branch, read from the forge. */
164
+ base?: string;
165
+ title: string;
166
+ body: string;
167
+ /**
168
+ * Open it as a draft: GitHub's `draft`, GitLab's `Draft: ` title prefix,
169
+ * Forgejo's `WIP: ` title prefix (it has no draft field).
170
+ */
171
+ draft?: boolean;
172
+ }
173
+ /** A pull request (merge request) as the forge answered it. */
174
+ export interface PullRequest {
175
+ /** The pull request's number, or the merge request's iid. */
176
+ number: number;
177
+ url?: string;
178
+ title: string;
179
+ body: string;
180
+ /** Its head (source) branch. */
181
+ head: string;
182
+ /** Its base (target) branch. */
183
+ base?: string;
184
+ }
139
185
  export interface PrForge {
140
186
  kind: ForgeKind;
141
187
  /** Lower-cased, such as `github.com`. */
@@ -198,6 +244,25 @@ export interface PrForge {
198
244
  approvers(pr: number): Promise<string[]>;
199
245
  /** The merged pull request that produced `sha`, or null. */
200
246
  pullRequestFor(sha: string): Promise<number | null>;
247
+ /**
248
+ * Open a pull request (a merge request on GitLab) from `head` into `base`,
249
+ * or into the default branch when `base` is not given. Over REST on every
250
+ * forge, so it works on Forgejo, where `gh pr create` cannot (#3798).
251
+ */
252
+ openPullRequest(spec: PullRequestSpec): Promise<PullRequest>;
253
+ /**
254
+ * The OPEN pull request whose head is branch `head` in this repository (a
255
+ * fork's branch of the same name is not it), or undefined. The oldest when
256
+ * there are several.
257
+ */
258
+ findPullRequest(head: string): Promise<PullRequest | undefined>;
259
+ /** Change an open pull request's title or body. */
260
+ editPullRequest(pr: number, change: {
261
+ title?: string;
262
+ body?: string;
263
+ }): Promise<PullRequest | undefined>;
264
+ /** Add labels to a pull request by name. Forgejo needs them to exist; GitHub and GitLab make them. */
265
+ addLabels(pr: number, labels: readonly string[]): Promise<void>;
201
266
  }
202
267
  /** A GitHub or Forgejo client. */
203
268
  export type GithubShapedForge = PrForge & {
@@ -1 +1 @@
1
- {"version":3,"file":"pr-forge.d.ts","sourceRoot":"","sources":["../src/pr-forge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAExD,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAAoC,CAAC;AAEjF,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KACrE,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAEvE,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACzC,wFAAwF;IACxF,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,gGAAgG;IAChG,KAAK,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC9B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;IAC5C,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,wGAAwG;IACxG,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,wGAAwG;IACxG,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,wGAAwG;IACxG,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IACpD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC;CAC9E;AAED,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACxE,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kIAAkI;IAClI,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACpG;;;OAGG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClF;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IAC/F;;;;;OAKG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC5D,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D;;;;;;OAMG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACzG;;;;;OAKG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC/E;;;OAGG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtF,kDAAkD;IAClD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,4DAA4D;IAC5D,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACrD;AAED,kCAAkC;AAClC,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG;IAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAE,CAAC;AAEzE,+DAA+D;AAC/D,qBAAa,aAAc,SAAQ,KAAK;IAEpC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM;IAHzB,YACW,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EAIf;CACF;AAID,qHAAqH;AACrH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIrF;AAiJD,MAAM,WAAW,kBAAkB;IACjC,kGAAkG;IAClG,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,uIAAuI;IACvI,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAiGD,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,iBAAiB,CAEvE;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,IAAI,EAAE,kBAAkB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAE3F;AAED,MAAM,WAAW,kBAAkB;IACjC,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,oIAAoI;IACpI,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,CAAC,EAAE,eAAe,GAAG,WAAW,CAAC;IAC5C,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAID;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAqF7D;AAED,mEAAmE;AACnE,qBAAa,qBAAsB,SAAQ,KAAK;IAM5C,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE;IAN5B;;;OAGG;IACH,YACW,IAAI,EAAE,SAAS,GAAG,SAAS,EAC3B,OAAO,EAAE,MAAM,EAAE,EAQ3B;CACF;AAWD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,OAAO,CAwCpI;AAID,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAI9C;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,GAAE,GAAiB,GAAG,SAAS,GAAG,SAAS,CAKzE;AAED,uHAAuH;AACvH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,qGAAqG;IACrG,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,WAAW,CAAC,EAAE,eAAe,GAAG,WAAW,CAAC;IAC5C,6DAA6D;IAC7D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,kDAAkD;IAClD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAIlE,CAAC;AAoBF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,GAAiB,EAAE,IAAI,GAAE,kBAAuB,GAAG,WAAW,CAuErG;AAED,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,OAAO,CAgBhF"}
1
+ {"version":3,"file":"pr-forge.d.ts","sourceRoot":"","sources":["../src/pr-forge.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.124.6",
3
+ "version": "0.124.7",
4
4
  "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -13,6 +13,7 @@ import { promisify } from "node:util";
13
13
  import { tmpdir } from "node:os";
14
14
  import { join } from "node:path";
15
15
  import { ghHostEnv } from "../op/activities/gh-host";
16
+ import { restPullRequestForge } from "../op/activities/forge-pull-request";
16
17
 
17
18
  const execFileAsync = promisify(execFile);
18
19
 
@@ -107,9 +108,16 @@ export async function rollbackToRevision(opts: {
107
108
 
108
109
  await git(["commit", "-m", rollbackTitle(env, ref)], wt);
109
110
  await git(["push", "-u", "origin", branch], wt);
111
+ // `gh pr` speaks GraphQL, which Forgejo does not serve: a Forgejo or
112
+ // GitLab job opens the pull request over REST (#3798).
113
+ const forge = await restPullRequestForge(process.env, { cwd: wt });
114
+ if (forge) {
115
+ const pr = await forge.openPullRequest({ head: branch, title: rollbackTitle(env, ref), body: rollbackBody(env, ref, sourceDir) });
116
+ return { noop: false, branch, prUrl: pr.url ?? "" };
117
+ }
110
118
  // `gh pr create` names no host: tell it the one `origin` is on, or the
111
- // CI job's forge, so a GitHub Enterprise Server or Forgejo checkout is not
112
- // sent to github.com (#3780).
119
+ // CI job's forge, so a GitHub Enterprise Server checkout is not sent to
120
+ // github.com (#3780).
113
121
  const { stdout } = await execFileAsync(
114
122
  "gh",
115
123
  ["pr", "create", "--title", rollbackTitle(env, ref), "--body", rollbackBody(env, ref, sourceDir), "--head", branch],
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Which pull-request paths go over REST (#3798): a Forgejo or GitLab job
3
+ * does, GitHub and a local run keep `gh`. Driven with an injected fetch.
4
+ */
5
+
6
+ import { describe, expect, test } from "vitest";
7
+ import { ForgeEnvironmentError, type ForgeFetch } from "../../pr-forge";
8
+ import { remoteRepoPath, restPullRequestForge, upsertPullRequest } from "./forge-pull-request";
9
+
10
+ interface Call {
11
+ method: string;
12
+ url: string;
13
+ body?: unknown;
14
+ }
15
+
16
+ function fakeFetch(routes: Record<string, unknown>): { fetch: ForgeFetch; calls: Call[] } {
17
+ const calls: Call[] = [];
18
+ const fetch: ForgeFetch = async (url, init) => {
19
+ calls.push({ method: init.method, url, ...(init.body ? { body: JSON.parse(init.body) } : {}) });
20
+ const found = routes[`${init.method} ${new URL(url).pathname}`];
21
+ if (found === undefined) return { ok: false, status: 404, text: async () => "" };
22
+ return { ok: true, status: 200, text: async () => JSON.stringify(found) };
23
+ };
24
+ return { fetch, calls };
25
+ }
26
+
27
+ const FORGEJO_JOB = {
28
+ FORGEJO_ACTIONS: "true",
29
+ GITHUB_SERVER_URL: "https://forge.example",
30
+ GITHUB_API_URL: "https://forge.example/api/v1",
31
+ GITHUB_REPOSITORY: "acme/infra",
32
+ GITHUB_TOKEN: "tok",
33
+ };
34
+
35
+ describe("remoteRepoPath", () => {
36
+ test("reads owner/name off https, ssh and scp-style remotes", () => {
37
+ expect(remoteRepoPath("https://forge.example/acme/infra.git")).toBe("acme/infra");
38
+ expect(remoteRepoPath("ssh://git@forge.example:2222/acme/infra.git")).toBe("acme/infra");
39
+ expect(remoteRepoPath("git@gitlab.com:group/sub/infra.git")).toBe("group/sub/infra");
40
+ expect(remoteRepoPath("https://forge.example/")).toBeUndefined();
41
+ expect(remoteRepoPath(undefined)).toBeUndefined();
42
+ });
43
+ });
44
+
45
+ describe("restPullRequestForge", () => {
46
+ test("GitHub and a run outside CI keep gh", async () => {
47
+ expect(await restPullRequestForge({ GITHUB_ACTIONS: "true", GITHUB_REPOSITORY: "acme/infra", GITHUB_TOKEN: "t" })).toBeUndefined();
48
+ expect(await restPullRequestForge({})).toBeUndefined();
49
+ });
50
+
51
+ test("a Forgejo job opens over REST, on the repository the checkout's remote names", async () => {
52
+ const { fetch, calls } = fakeFetch({ "POST /api/v1/repos/acme/other/pulls": { number: 3, html_url: "https://forge.example/acme/other/pulls/3" } });
53
+ const forge = await restPullRequestForge(FORGEJO_JOB, { cwd: "/wt", fetch, remoteUrl: async () => "https://forge.example/acme/other.git" });
54
+ expect(forge?.kind).toBe("forgejo");
55
+ expect((await forge!.openPullRequest({ head: "h", base: "main", title: "t", body: "b" })).url).toBe("https://forge.example/acme/other/pulls/3");
56
+ expect(calls[0].url).toBe("https://forge.example/api/v1/repos/acme/other/pulls");
57
+ });
58
+
59
+ test("a remote on another host leaves the job's repository", async () => {
60
+ const { fetch, calls } = fakeFetch({ "POST /api/v1/repos/acme/infra/pulls": { number: 1 } });
61
+ const forge = await restPullRequestForge(FORGEJO_JOB, { cwd: "/wt", fetch, remoteUrl: async () => "https://github.com/acme/mirror.git" });
62
+ await forge!.openPullRequest({ head: "h", base: "main", title: "t", body: "b" });
63
+ expect(calls[0].url).toBe("https://forge.example/api/v1/repos/acme/infra/pulls");
64
+ });
65
+
66
+ test("a GitLab job opens a merge request; a Forgejo job with no token is refused by name", async () => {
67
+ const forge = await restPullRequestForge({ GITLAB_CI: "true", CI_API_V4_URL: "https://gl/api/v4", CI_PROJECT_ID: "42", GITLAB_TOKEN: "t" });
68
+ expect(forge?.kind).toBe("gitlab");
69
+ const { GITHUB_TOKEN: _, ...noToken } = FORGEJO_JOB;
70
+ await expect(restPullRequestForge(noToken)).rejects.toBeInstanceOf(ForgeEnvironmentError);
71
+ });
72
+ });
73
+
74
+ describe("upsertPullRequest", () => {
75
+ const open = { number: 10, title: "t", body: "b", head: { ref: "h", repo: { full_name: "acme/infra" } }, html_url: "https://forge.example/acme/infra/pulls/10" };
76
+
77
+ test("opens one when none is open, edits the open one, leaves a current one alone", async () => {
78
+ const env = FORGEJO_JOB;
79
+ const none = fakeFetch({ "GET /api/v1/repos/acme/infra/pulls": [], "POST /api/v1/repos/acme/infra/pulls": { number: 11 } });
80
+ expect((await upsertPullRequest((await restPullRequestForge(env, { fetch: none.fetch }))!, { head: "h", base: "main", title: "t", body: "b" })).action).toBe("opened");
81
+
82
+ const stale = fakeFetch({ "GET /api/v1/repos/acme/infra/pulls": [open], "PATCH /api/v1/repos/acme/infra/pulls/10": { ...open, title: "t2" } });
83
+ const r = await upsertPullRequest((await restPullRequestForge(env, { fetch: stale.fetch }))!, { head: "h", base: "main", title: "t2", body: "b" });
84
+ expect(r).toMatchObject({ action: "updated", pr: { number: 10, title: "t2", url: open.html_url } });
85
+ expect(stale.calls.at(-1)).toMatchObject({ method: "PATCH", body: { title: "t2", body: "b" } });
86
+
87
+ const current = fakeFetch({ "GET /api/v1/repos/acme/infra/pulls": [open] });
88
+ expect((await upsertPullRequest((await restPullRequestForge(env, { fetch: current.fetch }))!, { head: "h", title: "t", body: "b\n" })).action).toBe("unchanged");
89
+ expect(current.calls.every((c) => c.method === "GET")).toBe(true);
90
+ });
91
+ });
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Where chant's own pull-request paths open their pull request (#3798).
3
+ *
4
+ * `reconcilePr`'s `pull-request` mode, `lexiconUpgrade`, rollback and
5
+ * `proposeWorkspaceUpgrade` open a pull request with `gh pr`. `gh pr create`,
6
+ * `view`, `edit` and `list` speak GitHub's GraphQL API, which Forgejo does not
7
+ * serve, so #3780's `GH_HOST` sends them to the right Forgejo instance only
8
+ * for them to fail there. GitLab has no `gh` at all. On those two forges each
9
+ * path opens, finds and edits its pull request over REST through
10
+ * `../../pr-forge.ts` instead. GitHub, and a run outside any CI job, keep
11
+ * `gh` and the operator's own `gh auth login`.
12
+ *
13
+ * The forge and its token come from the CI job's environment
14
+ * ({@link forgeTargetFromEnv}). The repository is the one the checkout's
15
+ * remote names, when that remote is on the job's forge, so a path working in
16
+ * another checkout than the job's own still opens its pull request there.
17
+ */
18
+
19
+ import { execFile } from "node:child_process";
20
+ import { promisify } from "node:util";
21
+ import { detectForge, forgeClient, forgeTargetFromEnv, type ForgeFetch, type PrForge, type PullRequest, type PullRequestSpec } from "../../pr-forge";
22
+ import { remoteHost } from "./gh-host";
23
+
24
+ const execFileAsync = promisify(execFile);
25
+
26
+ type Env = Record<string, string | undefined>;
27
+
28
+ /** The repository path a git remote URL names: `owner/name`, or `group/sub/name` on GitLab. */
29
+ export function remoteRepoPath(url: string | undefined): string | undefined {
30
+ const u = url?.trim();
31
+ if (!u) return undefined;
32
+ const scp = /^[^@/\s]+@[^:/\s]+:(?!\/)(.+)$/.exec(u);
33
+ let path: string;
34
+ if (scp) path = scp[1]!;
35
+ else {
36
+ try {
37
+ path = new URL(u).pathname;
38
+ } catch {
39
+ return undefined;
40
+ }
41
+ }
42
+ const out = path.replace(/^\/+/, "").replace(/\/+$/, "").replace(/\.git$/, "");
43
+ return out.includes("/") ? out : undefined;
44
+ }
45
+
46
+ export interface PullRequestForgeOptions {
47
+ /** A checkout whose remote names the repository. Default: the job's repository. */
48
+ cwd?: string;
49
+ /** The remote in `cwd`. Default `origin`. */
50
+ remote?: string;
51
+ fetch?: ForgeFetch;
52
+ /** Reads a remote's URL. Default `git remote get-url`. For tests. */
53
+ remoteUrl?: (cwd: string, remote: string) => Promise<string | undefined>;
54
+ }
55
+
56
+ const gitRemoteUrl = async (cwd: string, remote: string): Promise<string | undefined> => {
57
+ try {
58
+ return (await execFileAsync("git", ["remote", "get-url", remote], { cwd })).stdout.trim();
59
+ } catch {
60
+ return undefined;
61
+ }
62
+ };
63
+
64
+ /**
65
+ * The REST client a pull request is opened through, or undefined when `gh`
66
+ * serves: on GitHub, and outside a CI job. A Forgejo or GitLab job that lacks
67
+ * a token or a repository throws `ForgeEnvironmentError` naming it, where
68
+ * `gh pr` would have failed on GraphQL.
69
+ */
70
+ export async function restPullRequestForge(env: Env = process.env, opts: PullRequestForgeOptions = {}): Promise<PrForge | undefined> {
71
+ const kind = detectForge(env);
72
+ if (kind !== "forgejo" && kind !== "gitlab") return undefined;
73
+ const target = forgeTargetFromEnv(env, { kind });
74
+ if (opts.cwd) {
75
+ const url = await (opts.remoteUrl ?? gitRemoteUrl)(opts.cwd, opts.remote ?? "origin");
76
+ const path = remoteRepoPath(url);
77
+ if (path && remoteHost(url) === target.host) target.repo = path;
78
+ }
79
+ return forgeClient(target, opts.fetch);
80
+ }
81
+
82
+ /** What {@link upsertPullRequest} did. */
83
+ export interface UpsertedPullRequest {
84
+ action: "opened" | "updated" | "unchanged";
85
+ pr: PullRequest;
86
+ }
87
+
88
+ /**
89
+ * Open a pull request for `spec.head`, or bring the open one's title and
90
+ * body in line with `spec`. An open one already current is left alone.
91
+ */
92
+ export async function upsertPullRequest(forge: PrForge, spec: PullRequestSpec): Promise<UpsertedPullRequest> {
93
+ const open = await forge.findPullRequest(spec.head);
94
+ if (!open) return { action: "opened", pr: await forge.openPullRequest(spec) };
95
+ if (open.title === spec.title && open.body.trim() === spec.body.trim()) return { action: "unchanged", pr: open };
96
+ const edited = await forge.editPullRequest(open.number, { title: spec.title, body: spec.body });
97
+ return { action: "updated", pr: edited ?? { ...open, title: spec.title, body: spec.body } };
98
+ }
@@ -739,3 +739,61 @@ describe("a lexicon with several pins (#3288)", () => {
739
739
  expect(upgradePrTitle("sql", "17.11", "17.12", "postgres-17")).toBe("feat(sql): upgrade postgres-17 17.11 to 17.12");
740
740
  });
741
741
  });
742
+
743
+ // ── Forgejo and GitLab open the PR over REST (#3798) ──────────────────
744
+
745
+ describe("lexiconUpgrade pull request over REST", () => {
746
+ const pin = {
747
+ file: "src/pin.ts",
748
+ pattern: /V = "(.+)"/,
749
+ replace: (v: string) => `V = "${v}"`,
750
+ upstream: { owner: "o", repo: "r", kind: "releases" as const },
751
+ };
752
+
753
+ function fakeForge(open?: { number: number; url: string; body: string }) {
754
+ const calls: string[] = [];
755
+ const forge = {
756
+ findPullRequest: vi.fn(async (head: string) => (calls.push(`find ${head}`), open ? { ...open, title: "t", head } : undefined)),
757
+ openPullRequest: vi.fn(async (spec: { head: string; base?: string }) => (calls.push(`open ${spec.head} -> ${spec.base}`), { number: 5, url: "https://forge/pulls/5", title: "t", body: "b", head: spec.head })),
758
+ editPullRequest: vi.fn(async (n: number) => (calls.push(`edit ${n}`), undefined)),
759
+ addLabels: vi.fn(async (n: number, labels: readonly string[]) => void calls.push(`label ${n} ${labels.join(",")}`)),
760
+ };
761
+ return { forge: forge as unknown as import("../../pr-forge").PrForge, calls };
762
+ }
763
+
764
+ async function run(forge: import("../../pr-forge").PrForge) {
765
+ const { gh, calls } = recordingGh();
766
+ const dir = join(tmpdir(), `chant-3798-${process.pid}`);
767
+ mkdirSync(dir, { recursive: true });
768
+ writeFileSync(join(dir, "package.json"), JSON.stringify({ version: "0.1.0" }));
769
+ const r = await lexiconUpgrade({
770
+ lexicon: "k3s",
771
+ lexiconDir: dir,
772
+ mode: "pull-request",
773
+ _loadPin: async () => pin,
774
+ _checkPinned: vi.fn(async () => pinnedResult()),
775
+ _applyBump: vi.fn(async () => ({ filePath: "/x/src/pin.ts" })),
776
+ _bumpPackageVersion: vi.fn(),
777
+ _gh: gh,
778
+ _forge: forge,
779
+ });
780
+ return { r, ghCalls: calls };
781
+ }
782
+
783
+ test("opens the pull request and labels it through the forge, with no gh pr call", async () => {
784
+ const { forge, calls } = fakeForge();
785
+ const { r, ghCalls } = await run(forge);
786
+ expect(r.prUrl).toBe("https://forge/pulls/5");
787
+ expect(calls.filter((c) => c.startsWith("open"))).toEqual([`open ${upgradeBranchName("k3s")} -> main`]);
788
+ expect(calls.some((c) => c.startsWith("label"))).toBe(r.semverLabel !== undefined && r.semverLabel !== null);
789
+ expect(ghCalls.filter((c) => c.startsWith("gh "))).toEqual([]);
790
+ });
791
+
792
+ test("edits the open pull request in place of opening another", async () => {
793
+ const { forge, calls } = fakeForge({ number: 9, url: "https://forge/pulls/9", body: "old" });
794
+ const { r } = await run(forge);
795
+ expect(r.prUrl).toBe("https://forge/pulls/9");
796
+ expect(calls).toContain("edit 9");
797
+ expect(calls.some((c) => c.startsWith("open"))).toBe(false);
798
+ });
799
+ });
@@ -31,6 +31,8 @@ import type { UpgradeCheckResult, LexiconId, UpstreamPin } from "../../codegen/p
31
31
  import type { RollingUpgradeResult, RollingLexicon } from "../../codegen/rolling-upgrade";
32
32
  import { bumpForSeverity, bumpPackageJsonVersion } from "../../codegen/version-bump";
33
33
  import { ghHostEnv } from "./gh-host";
34
+ import { restPullRequestForge } from "./forge-pull-request";
35
+ import type { PrForge } from "../../pr-forge";
34
36
  import { postOrUpdateGithubIssue } from "./reconcile";
35
37
 
36
38
  export { bumpPackageJsonVersion };
@@ -99,6 +101,12 @@ export interface LexiconUpgradeArgs {
99
101
  * Defaults to bumpPackageJsonVersion.
100
102
  */
101
103
  _bumpPackageVersion?: BumpPackageVersionFn;
104
+ /**
105
+ * The REST client the pull request is found, opened and labelled through,
106
+ * or null for `gh`. Default: one on a Forgejo or GitLab job, `gh`
107
+ * elsewhere (#3798). For tests.
108
+ */
109
+ _forge?: PrForge | null;
102
110
  }
103
111
 
104
112
  export interface LexiconUpgradeResult {
@@ -416,7 +424,8 @@ async function postLexiconIssue(
416
424
  * Check whether an open PR exists for the given branch.
417
425
  * Returns the PR URL, or null if none.
418
426
  */
419
- async function openPrUrl(branch: string, gh: GhRunner): Promise<string | null> {
427
+ async function openPrUrl(branch: string, gh: GhRunner, forge?: PrForge): Promise<string | null> {
428
+ if (forge) return (await forge.findPullRequest(branch))?.url ?? null;
420
429
  try {
421
430
  const { stdout } = await gh(
422
431
  `gh pr view ${shellQuote(branch)} --json url,state --jq 'select(.state=="OPEN") | .url'`,
@@ -432,7 +441,8 @@ async function openPrUrl(branch: string, gh: GhRunner): Promise<string | null> {
432
441
  * Read the body of the open PR for `branch`, if any.
433
442
  * Returns null when there is no open PR or gh is unavailable.
434
443
  */
435
- async function currentPrBody(branch: string, gh: GhRunner): Promise<string | null> {
444
+ async function currentPrBody(branch: string, gh: GhRunner, forge?: PrForge): Promise<string | null> {
445
+ if (forge) return (await forge.findPullRequest(branch))?.body.trim() || null;
436
446
  try {
437
447
  const { stdout } = await gh(
438
448
  `gh pr view ${shellQuote(branch)} --json body,state --jq 'select(.state=="OPEN") | .body'`,
@@ -750,9 +760,12 @@ export async function lexiconUpgrade(args: LexiconUpgradeArgs): Promise<LexiconU
750
760
 
751
761
  // Idempotency check: if the open PR already has this summary, nothing changed.
752
762
  // Compare trimmed — gh/git round-trips can alter trailing whitespace.
753
- const existingPrBody = await currentPrBody(branch, gh);
763
+ // `gh pr` speaks GraphQL, which Forgejo does not serve: a Forgejo or
764
+ // GitLab job finds, opens and labels the pull request over REST (#3798).
765
+ const forge = args._forge !== undefined ? (args._forge ?? undefined) : await restPullRequestForge(process.env);
766
+ const existingPrBody = await currentPrBody(branch, gh, forge);
754
767
  if (existingPrBody !== null && existingPrBody.trim() === summary.trim()) {
755
- const existingUrl = await openPrUrl(branch, gh);
768
+ const existingUrl = await openPrUrl(branch, gh, forge);
756
769
  return {
757
770
  lexicon,
758
771
  mode,
@@ -825,10 +838,23 @@ export async function lexiconUpgrade(args: LexiconUpgradeArgs): Promise<LexiconU
825
838
  });
826
839
 
827
840
  // Open or update the PR.
828
- const existingUrl = await openPrUrl(branch, gh);
829
841
  let prUrl: string;
830
-
831
- if (existingUrl) {
842
+ const open = forge ? await forge.findPullRequest(branch) : undefined;
843
+ const existingUrl = forge ? null : await openPrUrl(branch, gh);
844
+
845
+ if (forge) {
846
+ let pr = open;
847
+ if (pr) {
848
+ const edited = await forge.editPullRequest(pr.number, { title, body: summary });
849
+ prUrl = edited?.url ?? pr.url ?? "";
850
+ } else {
851
+ pr = await forge.openPullRequest({ head: branch, base: "main", title, body: summary });
852
+ prUrl = pr.url ?? "";
853
+ }
854
+ // Best-effort, as below. Forgejo adds only a label the repository
855
+ // already has; GitHub and GitLab make one.
856
+ if (semverLabel) await forge.addLabels(pr.number, [semverLabel]).catch(() => {/* best-effort */});
857
+ } else if (existingUrl) {
832
858
  await gh(`gh pr edit ${shellQuote(branch)} --title ${shellQuote(title)} --body ${shellQuote(summary)}`);
833
859
  prUrl = existingUrl;
834
860
  } else {
@@ -838,7 +864,7 @@ export async function lexiconUpgrade(args: LexiconUpgradeArgs): Promise<LexiconU
838
864
  prUrl = stdout.trim();
839
865
  }
840
866
 
841
- if (semverLabel) {
867
+ if (semverLabel && !forge) {
842
868
  await ensureLabelOnPr(branch, semverLabel, gh);
843
869
  }
844
870
 
@@ -27,6 +27,8 @@ import { execFile } from "node:child_process";
27
27
  import { promisify } from "node:util";
28
28
  import type { StagedUpgrade } from "../../workspace/lineage-upgrade";
29
29
  import { ghHostEnv } from "./gh-host";
30
+ import { restPullRequestForge, upsertPullRequest } from "./forge-pull-request";
31
+ import type { PrForge } from "../../pr-forge";
30
32
 
31
33
  const execFileAsync = promisify(execFile);
32
34
 
@@ -52,6 +54,11 @@ export interface ProposeWorkspaceUpgradeArgs {
52
54
  cwd?: string;
53
55
  /** Replaces the git and gh child processes. For tests. */
54
56
  _run?: CommandRunner;
57
+ /**
58
+ * The REST client the pull request is opened through, or null for `gh`.
59
+ * Default: one on a Forgejo or GitLab job, `gh` elsewhere (#3798). For tests.
60
+ */
61
+ _forge?: PrForge | null;
55
62
  /** Replaces build and lint in the worktree. For tests. */
56
63
  _runChant?: import("../../workspace/lineage-upgrade").ChantRunner;
57
64
  }
@@ -198,6 +205,12 @@ export async function proposeWorkspaceUpgrade(args: ProposeWorkspaceUpgradeArgs)
198
205
  if (!hasRemote) throw new Error(`proposeWorkspaceUpgrade: no remote "${remote}" to open a pull request on`);
199
206
 
200
207
  const text = body(staged, lines);
208
+ // `gh pr` speaks GraphQL, which Forgejo does not serve (#3798).
209
+ const forge = args._forge !== undefined ? args._forge : await restPullRequestForge(process.env, { cwd: staged.repo, remote });
210
+ if (forge) {
211
+ result.prUrl = (await upsertPullRequest(forge, { head: branch, base: base!, title, body: text })).pr.url;
212
+ return result;
213
+ }
201
214
  const existing = (await run("gh", ["pr", "list", "--head", branch, "--state", "open", "--json", "url", "--jq", ".[0].url // empty"], staged.repo)).trim();
202
215
  if (existing) {
203
216
  await run("gh", ["pr", "edit", existing, "--title", title, "--body", text], staged.repo);
@@ -3,6 +3,7 @@ import { readFile } from "node:fs/promises";
3
3
  import { promisify } from "node:util";
4
4
  import { ForgeApiError, forgejoForge, githubForge, type ForgeFetch, type GithubShapedForge } from "../../pr-forge";
5
5
  import { ghHostEnv } from "./gh-host";
6
+ import { restPullRequestForge } from "./forge-pull-request";
6
7
 
7
8
  const execAsync = promisify(exec);
8
9
 
@@ -1363,8 +1364,15 @@ export async function reconcilePr(args: ReconcilePrArgs, signal?: AbortSignal):
1363
1364
  await execAsync(`git add ${shellQuote(output)}`, { signal });
1364
1365
  await execAsync(`git commit -m ${shellQuote(title)}`, { signal });
1365
1366
  await execAsync(`git push -u origin ${shellQuote(branch)}`, { signal });
1366
- // `gh pr create` names no host, so on GitHub Enterprise Server or Forgejo
1367
- // it is told the job's own (#3780). See `./gh-host.ts`.
1367
+ // `gh pr` speaks GraphQL, which Forgejo does not serve, and GitLab has no
1368
+ // `gh`: a Forgejo or GitLab job opens the pull request over REST (#3798).
1369
+ const forge = await restPullRequestForge(process.env, { fetch: (url, init) => globalThis.fetch(url, { ...init, ...(signal ? { signal } : {}) }) });
1370
+ if (forge) {
1371
+ const pr = await forge.openPullRequest({ head: branch, title, body: summary });
1372
+ return { mode, branch, summary, entries, prUrl: pr.url ?? "" };
1373
+ }
1374
+ // `gh pr create` names no host, so on GitHub Enterprise Server it is told
1375
+ // the job's own (#3780). See `./gh-host.ts`.
1368
1376
  const { stdout } = await execAsync(
1369
1377
  `gh pr create --title ${shellQuote(title)} --body ${shellQuote(summary)} --head ${shellQuote(branch)}`,
1370
1378
  { signal, env: await ghHostEnv(process.env) },
@@ -34,7 +34,7 @@ describe("the pr-forge bundle", () => {
34
34
  expect(inputs.filter((i) => pattern.test(i)), String(pattern)).toEqual([]);
35
35
  }
36
36
  expect(inputs.map((i) => i.replace(/^.*?packages\//, "packages/")).sort()).toEqual(["packages/core/src/pr-forge.ts"]);
37
- // About 20 KB today.
37
+ // About 27 KB today.
38
38
  expect(result.outputFiles.reduce((n, f) => n + f.contents.byteLength, 0)).toBeLessThan(32 * 1024);
39
39
  });
40
40
  });
@@ -14,9 +14,12 @@ import {
14
14
  forgeTargetFromEnv,
15
15
  forgejoForge,
16
16
  forgePrincipalOf,
17
+ FORGE_STATUS_STATES,
17
18
  githubForge,
18
19
  gitlabForge,
20
+ statusStateFor,
19
21
  type ForgeFetch,
22
+ type ForgeStatusState,
20
23
  } from "./pr-forge";
21
24
  import { forgePrincipal, parseForgeIdentity } from "./workspace/identity";
22
25
 
@@ -675,3 +678,154 @@ describe("addComment and findIssue (#3818)", () => {
675
678
  expect(fj.calls[0].headers.Authorization).toBeUndefined();
676
679
  });
677
680
  });
681
+
682
+ describe("status states and author lists (#3834)", () => {
683
+ const gh = { apiBase: "https://api.github.com", repo: "acme/infra", token: "t0k" };
684
+
685
+ test("each state goes to each forge as its nearest state", () => {
686
+ const table = Object.fromEntries(FORGE_STATUS_STATES.map((s) => [s, [statusStateFor("github", s), statusStateFor("forgejo", s), statusStateFor("gitlab", s)]]));
687
+ expect(table).toEqual({
688
+ pending: ["pending", "pending", "pending"],
689
+ running: ["pending", "pending", "running"],
690
+ success: ["success", "success", "success"],
691
+ failed: ["failure", "failure", "failed"],
692
+ failure: ["failure", "failure", "failed"],
693
+ canceled: ["error", "error", "canceled"],
694
+ error: ["error", "error", "failed"],
695
+ });
696
+ expect(() => statusStateFor("gitlab", "skipped" as ForgeStatusState)).toThrow(/one of pending, running/);
697
+ });
698
+
699
+ test("a running status is running on GitLab and pending on GitHub and Forgejo", async () => {
700
+ const gl = fakeFetch({ [`POST /api/v4/projects/42/statuses/${SHA}`]: {} });
701
+ await gitlabForge({ apiBase: "https://gl/api/v4", project: "42", token: "t", fetch: gl.fetch }).setStatus(SHA, { context: "terragucci/plan", state: "running", description: "planning" });
702
+ await gitlabForge({ apiBase: "https://gl/api/v4", project: "42", token: "t", fetch: gl.fetch }).setStatus(SHA, { context: "terragucci/plan", state: "canceled", description: "stopped" });
703
+ expect(gl.calls.map((c) => (c.body as { state: string }).state)).toEqual(["running", "canceled"]);
704
+ const g = fakeFetch({ [`POST /repos/acme/infra/statuses/${SHA}`]: {} });
705
+ await githubForge({ ...gh, fetch: g.fetch }).setStatus(SHA, { context: "terragucci/plan", state: "running", description: "planning" });
706
+ await githubForge({ ...gh, fetch: g.fetch }).setStatus(SHA, { context: "terragucci/plan", state: "failed", description: "no" });
707
+ expect(g.calls.map((c) => (c.body as { state: string }).state)).toEqual(["pending", "failure"]);
708
+ const fj = fakeFetch({ [`POST /api/v1/repos/acme/infra/statuses/${SHA}`]: {} });
709
+ await forgejoForge({ ...gh, apiBase: "https://codeberg.org/api/v1", host: "codeberg.org", fetch: fj.fetch }).setStatus(SHA, { context: "c", state: "running", description: "d" });
710
+ expect(fj.calls[0].body).toMatchObject({ state: "pending" });
711
+ });
712
+
713
+ const BOTS = ["github-actions[bot]", "gitea-actions", "forgejo-actions"];
714
+
715
+ test("a comment by any of several logins is the caller's own, without case", async () => {
716
+ const { fetch, calls } = fakeFetch({
717
+ "GET /api/v1/repos/acme/infra/issues/4/comments": [
718
+ { id: 1, body: "<!-- tg -->\nplanted", user: { login: "mallory" } },
719
+ { id: 2, body: "<!-- tg -->\nold", user: { login: "Forgejo-Actions" } },
720
+ ],
721
+ "PATCH /api/v1/repos/acme/infra/issues/comments/2": { id: 2, html_url: "https://cb/2" },
722
+ });
723
+ const forge = forgejoForge({ ...gh, apiBase: "https://codeberg.org/api/v1", host: "codeberg.org", fetch });
724
+ expect(await forge.findComment(4, "<!-- tg -->", { author: BOTS })).toEqual({ id: 2, body: "<!-- tg -->\nold" });
725
+ expect(await forge.upsertComment(4, "<!-- tg -->", "<!-- tg -->\nnew", { author: BOTS })).toEqual({ action: "updated", id: 2, url: "https://cb/2" });
726
+ expect(calls.at(-1)?.url).toBe("https://codeberg.org/api/v1/repos/acme/infra/issues/comments/2");
727
+ expect(await forge.findComment(4, "<!-- tg -->", { author: [] })).toBeUndefined();
728
+ expect((await forge.findComment(4, "<!-- tg -->", { author: "mallory" }))?.id).toBe(1);
729
+ });
730
+
731
+ test("an issue by any of several logins, for findIssue and trackIssue", async () => {
732
+ const { fetch, calls } = fakeFetch({
733
+ "GET /repos/acme/infra/issues": [
734
+ { number: 3, title: "Drift", body: "<!-- d -->\nplanted", user: { login: "mallory" } },
735
+ { number: 4, title: "Drift", body: "<!-- d -->\nold", user: { login: "github-actions[bot]" } },
736
+ ],
737
+ "PATCH /repos/acme/infra/issues/4": { number: 4 },
738
+ });
739
+ const forge = githubForge({ ...gh, fetch });
740
+ expect((await forge.findIssue("<!-- d -->", { author: BOTS }))?.number).toBe(4);
741
+ expect(await forge.trackIssue("<!-- d -->", { title: "Drift", body: "<!-- d -->\nnew" }, { author: BOTS })).toMatchObject({ action: "updated", number: 4 });
742
+ expect(calls.at(-1)).toMatchObject({ method: "PATCH", url: "https://api.github.com/repos/acme/infra/issues/4" });
743
+ });
744
+ });
745
+
746
+ describe("pull requests over REST (#3798)", () => {
747
+ const gh = { apiBase: "https://api.github.com", repo: "acme/infra", token: "t0k" };
748
+ const fjOpts = { ...gh, apiBase: "https://forge.example/api/v1", host: "forge.example" };
749
+ const gl = { apiBase: "https://gl/api/v4", project: "group/infra", token: "t" };
750
+
751
+ test("Forgejo opens a pull request into the default branch read from the repository", async () => {
752
+ const { fetch, calls } = fakeFetch({
753
+ "GET /api/v1/repos/acme/infra": { default_branch: "trunk" },
754
+ "POST /api/v1/repos/acme/infra/pulls": (c: Call) => ({ number: 9, html_url: "https://forge.example/acme/infra/pulls/9", title: (c.body as { title: string }).title, body: "b", head: { ref: "chant/x" }, base: { ref: "trunk" } }),
755
+ });
756
+ const pr = await forgejoForge({ ...fjOpts, fetch }).openPullRequest({ head: "chant/x", title: "t", body: "b" });
757
+ expect(pr).toEqual({ number: 9, url: "https://forge.example/acme/infra/pulls/9", title: "t", body: "b", head: "chant/x", base: "trunk" });
758
+ expect(calls.map((c) => `${c.method} ${c.url}`)).toEqual(["GET https://forge.example/api/v1/repos/acme/infra", "POST https://forge.example/api/v1/repos/acme/infra/pulls"]);
759
+ expect(calls[1].body).toEqual({ title: "t", body: "b", head: "chant/x", base: "trunk" });
760
+ expect(calls[1].headers.Authorization).toBe("token t0k");
761
+ });
762
+
763
+ test("a draft is GitHub's draft field, Forgejo's WIP: and GitLab's Draft: prefix", async () => {
764
+ const g = fakeFetch({ "POST /repos/acme/infra/pulls": { number: 1 } });
765
+ await githubForge({ ...gh, fetch: g.fetch }).openPullRequest({ head: "h", base: "main", title: "t", body: "b", draft: true });
766
+ expect(g.calls[0].body).toEqual({ title: "t", body: "b", head: "h", base: "main", draft: true });
767
+ const f = fakeFetch({ "POST /api/v1/repos/acme/infra/pulls": { number: 1 } });
768
+ await forgejoForge({ ...fjOpts, fetch: f.fetch }).openPullRequest({ head: "h", base: "main", title: "t", body: "b", draft: true });
769
+ expect(f.calls[0].body).toEqual({ title: "WIP: t", body: "b", head: "h", base: "main" });
770
+ const l = fakeFetch({ "POST /api/v4/projects/group%2Finfra/merge_requests": { iid: 4, web_url: "https://gl/mr/4", source_branch: "h", target_branch: "main", title: "Draft: t", description: "b" } });
771
+ const mr = await gitlabForge({ ...gl, fetch: l.fetch }).openPullRequest({ head: "h", base: "main", title: "t", body: "b", draft: true });
772
+ expect(l.calls[0].body).toEqual({ source_branch: "h", target_branch: "main", title: "Draft: t", description: "b" });
773
+ expect(mr).toEqual({ number: 4, url: "https://gl/mr/4", title: "Draft: t", body: "b", head: "h", base: "main" });
774
+ });
775
+
776
+ test("GitLab reads the default branch off the project", async () => {
777
+ const { fetch, calls } = fakeFetch({
778
+ "GET /api/v4/projects/group%2Finfra": { default_branch: "main" },
779
+ "POST /api/v4/projects/group%2Finfra/merge_requests": { iid: 2 },
780
+ });
781
+ await gitlabForge({ ...gl, fetch }).openPullRequest({ head: "h", title: "t", body: "b" });
782
+ expect((calls[1].body as { target_branch: string }).target_branch).toBe("main");
783
+ });
784
+
785
+ test("findPullRequest takes the oldest open one from this repository, not a fork's", async () => {
786
+ const f = fakeFetch({
787
+ "GET /api/v1/repos/acme/infra/pulls": [
788
+ { number: 12, title: "fork", body: "", head: { ref: "chant/x", repo: { full_name: "mallory/infra" } } },
789
+ { number: 11, title: "newer", body: "", head: { ref: "chant/x", repo: { full_name: "acme/infra" } } },
790
+ { number: 10, title: "mine", body: "b", head: { ref: "chant/x", repo: { full_name: "acme/infra" } }, base: { ref: "main" }, html_url: "https://forge.example/acme/infra/pulls/10" },
791
+ { number: 3, title: "other", body: "", head: { ref: "other", repo: { full_name: "acme/infra" } } },
792
+ ],
793
+ });
794
+ const forge = forgejoForge({ ...fjOpts, fetch: f.fetch });
795
+ expect(await forge.findPullRequest("chant/x")).toEqual({ number: 10, title: "mine", body: "b", head: "chant/x", base: "main", url: "https://forge.example/acme/infra/pulls/10" });
796
+ expect(f.calls[0].url).toBe("https://forge.example/api/v1/repos/acme/infra/pulls?state=open&limit=50&page=1");
797
+ expect(await forge.findPullRequest("none")).toBeUndefined();
798
+
799
+ const g = fakeFetch({ "GET /repos/acme/infra/pulls": [] });
800
+ expect(await githubForge({ ...gh, fetch: g.fetch }).findPullRequest("chant/x")).toBeUndefined();
801
+ expect(g.calls[0].url).toBe("https://api.github.com/repos/acme/infra/pulls?state=open&head=acme%3Achant%2Fx&per_page=100&page=1");
802
+
803
+ const l = fakeFetch({
804
+ "GET /api/v4/projects/group%2Finfra/merge_requests": [
805
+ { iid: 8, source_branch: "chant/x", project_id: 1, source_project_id: 2, title: "fork", description: "" },
806
+ { iid: 7, source_branch: "chant/x", project_id: 1, source_project_id: 1, title: "mine", description: "d", target_branch: "main" },
807
+ ],
808
+ });
809
+ expect(await gitlabForge({ ...gl, fetch: l.fetch }).findPullRequest("chant/x")).toEqual({ number: 7, title: "mine", body: "d", head: "chant/x", base: "main" });
810
+ expect(l.calls[0].url).toBe("https://gl/api/v4/projects/group%2Finfra/merge_requests?state=opened&source_branch=chant%2Fx&per_page=100&page=1");
811
+ });
812
+
813
+ test("editPullRequest and addLabels on each forge", async () => {
814
+ const f = fakeFetch({ "PATCH /api/v1/repos/acme/infra/pulls/10": { number: 10, title: "t2" }, "POST /api/v1/repos/acme/infra/issues/10/labels": [] });
815
+ const forge = forgejoForge({ ...fjOpts, fetch: f.fetch });
816
+ expect((await forge.editPullRequest(10, { title: "t2", body: "b2" }))?.title).toBe("t2");
817
+ await forge.addLabels(10, ["minor"]);
818
+ await forge.addLabels(10, []);
819
+ expect(f.calls.map((c) => [c.method, c.body])).toEqual([["PATCH", { title: "t2", body: "b2" }], ["POST", { labels: ["minor"] }]]);
820
+ const l = fakeFetch({ "PUT /api/v4/projects/group%2Finfra/merge_requests/7": { iid: 7 } });
821
+ const g = gitlabForge({ ...gl, fetch: l.fetch });
822
+ await g.editPullRequest(7, { body: "d" });
823
+ await g.addLabels(7, ["minor", "breaking"]);
824
+ expect(l.calls.map((c) => c.body)).toEqual([{ description: "d" }, { add_labels: "minor,breaking" }]);
825
+ });
826
+
827
+ test("a repository with no default branch is refused by name", async () => {
828
+ const { fetch } = fakeFetch({ "GET /api/v1/repos/acme/infra": {} });
829
+ await expect(forgejoForge({ ...fjOpts, fetch }).openPullRequest({ head: "h", title: "t", body: "b" })).rejects.toThrow(/no default branch.*pass base/);
830
+ });
831
+ });
package/src/pr-forge.ts CHANGED
@@ -2,7 +2,8 @@
2
2
  * What chant and the products built on it ask of a forge: keep one comment
3
3
  * (a merge request note on GitLab) on a pull request up to date, set a commit
4
4
  * status, keep one tracking issue in the repository, list who approved a pull
5
- * request, and find the pull request that merged a commit.
5
+ * request, find the pull request that merged a commit, and open or edit a
6
+ * pull request (a merge request on GitLab) for a branch.
6
7
  *
7
8
  * The pull-request loop (#3183) uses the note, the status and the review
8
9
  * calls. `reconcilePr`'s `comment` and `issue` finding modes post through the
@@ -21,6 +22,10 @@
21
22
  * `gitlab:<login>`, or `<forge>@<host>:<login>` off the forge's default host.
22
23
  * The apply compares that string with the approval's `resolvedBy`.
23
24
  *
25
+ * Opening a pull request goes over REST too (#3798): `gh pr` speaks GitHub's
26
+ * GraphQL, which Forgejo does not serve, so chant's own pull-request paths
27
+ * open theirs through {@link PrForge.openPullRequest} on Forgejo and GitLab.
28
+ *
24
29
  * Like `./pr-loop.ts`, this bundles without the TypeScript toolchain (#3421):
25
30
  * it imports nothing but `node:fs`, to read a CI job's event payload.
26
31
  * `./pr-forge-bundle.test.ts` holds it to that.
@@ -41,7 +46,13 @@ export type ForgeFetch = (
41
46
  export interface ForgeStatus {
42
47
  /** The status's name, such as `chant/plan` or `terragucci/plan`. */
43
48
  context: string;
44
- state: "pending" | "success" | "failure";
49
+ /**
50
+ * GitLab's own states, plus GitHub's `failure` and `error`. Each forge gets
51
+ * the nearest state it has ({@link statusStateFor}): `running` is `pending`
52
+ * on GitHub and Forgejo, `canceled` is `error` there, and `failure` and
53
+ * `error` are `failed` on GitLab.
54
+ */
55
+ state: ForgeStatusState;
45
56
  /** Cut to what the forge keeps: 140 characters on GitHub and Forgejo, 255 on GitLab. */
46
57
  description: string;
47
58
  /** The pipeline run, linked from the status. */
@@ -50,6 +61,30 @@ export interface ForgeStatus {
50
61
  pipelineId?: number;
51
62
  }
52
63
 
64
+ /** A commit status's state, as a caller names it. */
65
+ export type ForgeStatusState = "pending" | "running" | "success" | "failed" | "failure" | "canceled" | "error";
66
+
67
+ /** Every {@link ForgeStatusState}, for a caller that reads one from its own input. */
68
+ export const FORGE_STATUS_STATES: readonly ForgeStatusState[] = ["pending", "running", "success", "failed", "failure", "canceled", "error"];
69
+
70
+ /**
71
+ * What each forge is sent for a {@link ForgeStatusState} (#3834). GitHub
72
+ * keeps `pending`, `success`, `failure` and `error`; Forgejo the same and
73
+ * `warning`; GitLab `pending`, `running`, `success`, `failed` and `canceled`.
74
+ * A state the forge lacks becomes its nearest one.
75
+ */
76
+ const STATUS_STATE: Record<"github" | "gitlab", Record<ForgeStatusState, string>> = {
77
+ github: { pending: "pending", running: "pending", success: "success", failed: "failure", failure: "failure", canceled: "error", error: "error" },
78
+ gitlab: { pending: "pending", running: "running", success: "success", failed: "failed", failure: "failed", canceled: "canceled", error: "failed" },
79
+ };
80
+
81
+ /** The state `kind` is sent for `state`. Forgejo takes GitHub's. */
82
+ export function statusStateFor(kind: ForgeKind, state: ForgeStatusState): string {
83
+ const mapped = STATUS_STATE[kind === "gitlab" ? "gitlab" : "github"][state];
84
+ if (mapped === undefined) throw new Error(`a commit status state is one of ${FORGE_STATUS_STATES.join(", ")}, not ${JSON.stringify(state)}`);
85
+ return mapped;
86
+ }
87
+
53
88
  /**
54
89
  * How a comment or an issue is told to be the caller's own. By default the
55
90
  * body starts with the marker, chant's recipe since #2291, and anyone may
@@ -59,12 +94,15 @@ export interface MarkerMatch {
59
94
  /** `prefix` (the default): the body starts with the marker. `anywhere`: the body carries it. */
60
95
  match?: "prefix" | "anywhere";
61
96
  /**
62
- * Only a comment or issue written by this login counts: `user.login` on
63
- * GitHub and Forgejo, `author.username` on GitLab, compared without case.
64
- * A merge request's author can write a note carrying any marker, so a
65
- * product that reads its own notes back names its bot here.
97
+ * Only a comment or issue written by this login, or by any of these
98
+ * logins, counts: `user.login` on GitHub and Forgejo, `author.username` on
99
+ * GitLab, compared without case. A merge request's author can write a note
100
+ * carrying any marker, so a product that reads its own notes back names
101
+ * its bot here. A list is for a bot whose login the job cannot know in
102
+ * advance, such as `gitea-actions` or `forgejo-actions` on Forgejo (#3834).
103
+ * An empty list matches nobody.
66
104
  */
67
- author?: string;
105
+ author?: string | readonly string[];
68
106
  }
69
107
 
70
108
  /** What {@link PrForge.upsertComment} did. */
@@ -146,6 +184,34 @@ export interface IssueResult {
146
184
  created?: string;
147
185
  }
148
186
 
187
+ /** A pull request (merge request) for {@link PrForge.openPullRequest} to open. */
188
+ export interface PullRequestSpec {
189
+ /** The branch with the change, in the same repository. */
190
+ head: string;
191
+ /** The branch it merges into. Default: the repository's default branch, read from the forge. */
192
+ base?: string;
193
+ title: string;
194
+ body: string;
195
+ /**
196
+ * Open it as a draft: GitHub's `draft`, GitLab's `Draft: ` title prefix,
197
+ * Forgejo's `WIP: ` title prefix (it has no draft field).
198
+ */
199
+ draft?: boolean;
200
+ }
201
+
202
+ /** A pull request (merge request) as the forge answered it. */
203
+ export interface PullRequest {
204
+ /** The pull request's number, or the merge request's iid. */
205
+ number: number;
206
+ url?: string;
207
+ title: string;
208
+ body: string;
209
+ /** Its head (source) branch. */
210
+ head: string;
211
+ /** Its base (target) branch. */
212
+ base?: string;
213
+ }
214
+
149
215
  export interface PrForge {
150
216
  kind: ForgeKind;
151
217
  /** Lower-cased, such as `github.com`. */
@@ -208,6 +274,22 @@ export interface PrForge {
208
274
  approvers(pr: number): Promise<string[]>;
209
275
  /** The merged pull request that produced `sha`, or null. */
210
276
  pullRequestFor(sha: string): Promise<number | null>;
277
+ /**
278
+ * Open a pull request (a merge request on GitLab) from `head` into `base`,
279
+ * or into the default branch when `base` is not given. Over REST on every
280
+ * forge, so it works on Forgejo, where `gh pr create` cannot (#3798).
281
+ */
282
+ openPullRequest(spec: PullRequestSpec): Promise<PullRequest>;
283
+ /**
284
+ * The OPEN pull request whose head is branch `head` in this repository (a
285
+ * fork's branch of the same name is not it), or undefined. The oldest when
286
+ * there are several.
287
+ */
288
+ findPullRequest(head: string): Promise<PullRequest | undefined>;
289
+ /** Change an open pull request's title or body. */
290
+ editPullRequest(pr: number, change: { title?: string; body?: string }): Promise<PullRequest | undefined>;
291
+ /** Add labels to a pull request by name. Forgejo needs them to exist; GitHub and GitLab make them. */
292
+ addLabels(pr: number, labels: readonly string[]): Promise<void>;
211
293
  }
212
294
 
213
295
  /** A GitHub or Forgejo client. */
@@ -301,8 +383,15 @@ interface Threads {
301
383
  const carries = (body: string, marker: string, match: MarkerMatch["match"]): boolean =>
302
384
  match === "anywhere" ? body.includes(marker) : body.startsWith(marker);
303
385
 
386
+ /** Whether `author` is one of `want`, without case. No `want` (or `""`) takes anyone. */
387
+ const authorIn = (want: MarkerMatch["author"], author: string | undefined): boolean => {
388
+ if (want === undefined || want === "") return true;
389
+ const logins = (typeof want === "string" ? [want] : want).map((l) => l.toLowerCase());
390
+ return author !== undefined && logins.includes(author.toLowerCase());
391
+ };
392
+
304
393
  const ownedBy = (marker: string, opts: MarkerMatch) => (t: Thread): boolean =>
305
- carries(t.body, marker, opts.match) && (!opts.author || t.author?.toLowerCase() === opts.author.toLowerCase());
394
+ carries(t.body, marker, opts.match) && authorIn(opts.author, t.author);
306
395
 
307
396
  function checkMarker(what: string, marker: string, body: string, match: MarkerMatch["match"]): void {
308
397
  if (!marker) throw new Error(`the ${what} needs a marker to be found again`);
@@ -420,6 +509,21 @@ function githubShaped(kind: "github" | "forgejo", opts: GithubForgeOptions): Git
420
509
  return { id, body: str(v.body) ?? "", ...(created ? { created } : {}), ...(str(v.title) !== undefined ? { title: str(v.title) } : {}), ...(author ? { author } : {}), ...(url ? { url } : {}) };
421
510
  };
422
511
  const threads = (items: unknown[]): Thread[] => items.map(thread).filter((t): t is Thread => t !== undefined);
512
+ const pull = (v: unknown): PullRequest | undefined => {
513
+ if (!isObject(v)) return undefined;
514
+ const number = num(v.number);
515
+ const head = isObject(v.head) ? str(v.head.ref) : undefined;
516
+ if (number === undefined) return undefined;
517
+ const base = isObject(v.base) ? str(v.base.ref) : undefined;
518
+ const url = str(v.html_url);
519
+ return { number, title: str(v.title) ?? "", body: str(v.body) ?? "", head: head ?? "", ...(base ? { base } : {}), ...(url ? { url } : {}) };
520
+ };
521
+ /** A pull request whose head branch lives in this repository, not a fork. */
522
+ const fromHere = (v: unknown, head: string): boolean => {
523
+ if (!isObject(v) || !isObject(v.head) || v.head.ref !== head) return false;
524
+ const full = isObject(v.head.repo) ? str(v.head.repo.full_name) : undefined;
525
+ return full === undefined || full.toLowerCase() === opts.repo.toLowerCase();
526
+ };
423
527
  const t: Threads = {
424
528
  comments: async (pr) => threads(await api.list(`${repo}/issues/${pr}/comments`, pageParams, pageSize)),
425
529
  addComment: async (pr, body) => thread(await api.call("POST", `${repo}/issues/${pr}/comments`, { body })),
@@ -445,7 +549,7 @@ function githubShaped(kind: "github" | "forgejo", opts: GithubForgeOptions): Git
445
549
  ...threadCalls(t),
446
550
  async setStatus(sha, status) {
447
551
  await api.call("POST", `${repo}/statuses/${sha}`, {
448
- state: status.state,
552
+ state: statusStateFor(kind, status.state),
449
553
  context: status.context,
450
554
  description: status.description.slice(0, GITHUB_DESCRIPTION),
451
555
  ...(status.url ? { target_url: status.url } : {}),
@@ -483,9 +587,44 @@ function githubShaped(kind: "github" | "forgejo", opts: GithubForgeOptions): Git
483
587
  const pick = (exact ?? merged[0]) as Record<string, unknown> | undefined;
484
588
  return pick && typeof pick.number === "number" ? pick.number : null;
485
589
  },
590
+ async openPullRequest(spec) {
591
+ const base = spec.base ?? (await defaultBranchOf(api, repo, "default_branch"));
592
+ const title = spec.draft && kind === "forgejo" ? `WIP: ${spec.title}` : spec.title;
593
+ const made = await api.call("POST", `${repo}/pulls`, {
594
+ title,
595
+ body: spec.body,
596
+ head: spec.head,
597
+ base,
598
+ ...(spec.draft && kind === "github" ? { draft: true } : {}),
599
+ });
600
+ return pull(made) ?? { number: 0, title, body: spec.body, head: spec.head, base };
601
+ },
602
+ async findPullRequest(head) {
603
+ // GitHub filters by `owner:branch` server-side; Forgejo's list takes no
604
+ // head filter, so every open page is read and matched here.
605
+ const owner = opts.repo.split("/")[0];
606
+ const query = kind === "github" ? `?state=open&head=${encodeURIComponent(`${owner}:${head}`)}` : "?state=open";
607
+ const open = (await api.list(`${repo}/pulls${query}`, pageParams, pageSize)).filter((p) => fromHere(p, head));
608
+ return open.map(pull).filter((p): p is PullRequest => p !== undefined).sort((a, b) => a.number - b.number)[0];
609
+ },
610
+ async editPullRequest(pr, change) {
611
+ return pull(await api.call("PATCH", `${repo}/pulls/${pr}`, { ...(change.title !== undefined ? { title: change.title } : {}), ...(change.body !== undefined ? { body: change.body } : {}) }));
612
+ },
613
+ async addLabels(pr, labels) {
614
+ if (labels.length === 0) return;
615
+ await api.call("POST", `${repo}/issues/${pr}/labels`, { labels: [...labels] });
616
+ },
486
617
  };
487
618
  }
488
619
 
620
+ /** The repository's default branch, from `GET` on the repository (`/repos/{repo}`, `/projects/{id}`). */
621
+ async function defaultBranchOf(api: Transport, path: string, field: string): Promise<string> {
622
+ const r = await api.call("GET", path);
623
+ const branch = isObject(r) ? str(r[field]) : undefined;
624
+ if (!branch) throw new Error(`${path} names no default branch to open the pull request against; pass base`);
625
+ return branch;
626
+ }
627
+
489
628
  /** A GitHub client (github.com or GitHub Enterprise Server). */
490
629
  export function githubForge(opts: GithubForgeOptions): GithubShapedForge {
491
630
  return githubShaped("github", opts);
@@ -515,8 +654,6 @@ export interface GitlabForgeOptions {
515
654
  fetch?: ForgeFetch;
516
655
  }
517
656
 
518
- const GITLAB_STATE: Record<ForgeStatus["state"], string> = { pending: "pending", success: "success", failure: "failed" };
519
-
520
657
  /**
521
658
  * A GitLab client. Writing notes needs an access token with the `api` scope
522
659
  * on most instances: the job token reaches only the endpoints the instance's
@@ -545,6 +682,14 @@ export function gitlabForge(opts: GitlabForgeOptions): PrForge {
545
682
  return { id, body: str(v.description) ?? "", ...(created ? { created } : {}), ...(str(v.title) !== undefined ? { title: str(v.title) } : {}), ...(author ? { author } : {}), ...(url ? { url } : {}) };
546
683
  };
547
684
  const notes = `${project}/merge_requests`;
685
+ const mergeRequest = (v: unknown): PullRequest | undefined => {
686
+ if (!isObject(v)) return undefined;
687
+ const number = num(v.iid);
688
+ if (number === undefined) return undefined;
689
+ const base = str(v.target_branch);
690
+ const url = str(v.web_url);
691
+ return { number, title: str(v.title) ?? "", body: str(v.description) ?? "", head: str(v.source_branch) ?? "", ...(base ? { base } : {}), ...(url ? { url } : {}) };
692
+ };
548
693
  const t: Threads = {
549
694
  comments: async (mr) =>
550
695
  (await api.list(`${notes}/${mr}/notes`, pageParams, 100))
@@ -577,7 +722,7 @@ export function gitlabForge(opts: GitlabForgeOptions): PrForge {
577
722
  async setStatus(sha, status) {
578
723
  try {
579
724
  await api.call("POST", `${project}/statuses/${sha}`, {
580
- state: GITLAB_STATE[status.state],
725
+ state: statusStateFor("gitlab", status.state),
581
726
  name: status.context,
582
727
  description: status.description.slice(0, GITLAB_DESCRIPTION),
583
728
  ...(status.url ? { target_url: status.url } : {}),
@@ -606,6 +751,28 @@ export function gitlabForge(opts: GitlabForgeOptions): PrForge {
606
751
  ?? mrs.find((m) => isObject(m) && m.state === "merged");
607
752
  return isObject(merged) && typeof merged.iid === "number" ? merged.iid : null;
608
753
  },
754
+ async openPullRequest(spec) {
755
+ const base = spec.base ?? (await defaultBranchOf(api, project, "default_branch"));
756
+ const title = spec.draft ? `Draft: ${spec.title}` : spec.title;
757
+ const made = await api.call("POST", notes, { source_branch: spec.head, target_branch: base, title, description: spec.body });
758
+ return mergeRequest(made) ?? { number: 0, title, body: spec.body, head: spec.head, base };
759
+ },
760
+ async findPullRequest(head) {
761
+ const open = await api.list(`${notes}?state=opened&source_branch=${encodeURIComponent(head)}`, pageParams, 100);
762
+ return open
763
+ // A fork's merge request into this project has another source project.
764
+ .filter((m) => isObject(m) && m.source_branch === head && (m.source_project_id === undefined || m.source_project_id === m.project_id))
765
+ .map(mergeRequest)
766
+ .filter((m): m is PullRequest => m !== undefined)
767
+ .sort((a, b) => a.number - b.number)[0];
768
+ },
769
+ async editPullRequest(mr, change) {
770
+ return mergeRequest(await api.call("PUT", `${notes}/${mr}`, { ...(change.title !== undefined ? { title: change.title } : {}), ...(change.body !== undefined ? { description: change.body } : {}) }));
771
+ },
772
+ async addLabels(mr, labels) {
773
+ if (labels.length === 0) return;
774
+ await api.call("PUT", `${notes}/${mr}`, { add_labels: labels.join(",") });
775
+ },
609
776
  };
610
777
  }
611
778