@forge-glance/sdk 0.1.0 → 0.2.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.
@@ -1,4 +1,14 @@
1
- import type { Discussion, MRDetail, PullRequest, UserRef } from "./types.ts";
1
+ import type {
2
+ BranchProtectionRule,
3
+ CreatePullRequestInput,
4
+ Discussion,
5
+ MergePullRequestInput,
6
+ MRDetail,
7
+ ProviderCapabilities,
8
+ PullRequest,
9
+ UpdatePullRequestInput,
10
+ UserRef
11
+ } from './types.ts';
2
12
 
3
13
  /**
4
14
  * Provider-agnostic interface for a Git hosting service.
@@ -31,17 +41,153 @@ export interface GitProvider {
31
41
  fetchSingleMR(
32
42
  projectPath: string,
33
43
  mrIid: number,
34
- currentUserNumericId: number | null,
44
+ currentUserNumericId: number | null
35
45
  ): Promise<PullRequest | null>;
36
46
 
47
+ /**
48
+ * Fetch a single MR/PR by its source branch within a project.
49
+ * Returns null if no open MR/PR exists for that branch.
50
+ */
51
+ fetchPullRequestByBranch(
52
+ projectPath: string,
53
+ sourceBranch: string
54
+ ): Promise<PullRequest | null>;
55
+
56
+ /**
57
+ * Create a new merge request / pull request.
58
+ * Returns the created PullRequest.
59
+ */
60
+ createPullRequest(input: CreatePullRequestInput): Promise<PullRequest>;
61
+
62
+ /**
63
+ * Update an existing merge request / pull request.
64
+ * Returns the updated PullRequest.
65
+ */
66
+ updatePullRequest(
67
+ projectPath: string,
68
+ mrIid: number,
69
+ input: UpdatePullRequestInput
70
+ ): Promise<PullRequest>;
71
+
72
+ /**
73
+ * Fetch branch protection rules for a repository.
74
+ * Returns an array of rules (one per protected branch/pattern).
75
+ */
76
+ fetchBranchProtectionRules(
77
+ projectPath: string
78
+ ): Promise<BranchProtectionRule[]>;
79
+
80
+ /**
81
+ * Delete a branch from the repository.
82
+ * @throws if the branch doesn't exist or is protected.
83
+ */
84
+ deleteBranch(projectPath: string, branch: string): Promise<void>;
85
+
37
86
  /**
38
87
  * Fetch discussions (comments, threads) for a specific MR/PR.
39
88
  * Returns the MRDetail with discussions populated.
40
89
  */
41
- fetchMRDiscussions(
42
- repositoryId: string,
90
+ fetchMRDiscussions(repositoryId: string, mrIid: number): Promise<MRDetail>;
91
+
92
+ // ── Mutation capabilities ───────────────────────────────────────────────
93
+
94
+ /**
95
+ * Reports which mutation operations this provider supports.
96
+ * Callers should check these flags to conditionally show/hide UI
97
+ * affordances without knowing which provider they're talking to.
98
+ */
99
+ readonly capabilities: ProviderCapabilities;
100
+
101
+ // ── MR lifecycle mutations ──────────────────────────────────────────────
102
+
103
+ /**
104
+ * Merge (accept) a pull request / merge request.
105
+ * All input fields are optional — omitting them defers to the project's
106
+ * configured defaults (merge method, squash policy, delete-source-branch).
107
+ */
108
+ mergePullRequest(
109
+ projectPath: string,
110
+ mrIid: number,
111
+ input?: MergePullRequestInput
112
+ ): Promise<PullRequest>;
113
+
114
+ /**
115
+ * Approve a pull request / merge request.
116
+ * On GitLab: POST /merge_requests/:iid/approve
117
+ * On GitHub: POST /pulls/:number/reviews with event "APPROVE"
118
+ */
119
+ approvePullRequest(projectPath: string, mrIid: number): Promise<void>;
120
+
121
+ /**
122
+ * Revoke an existing approval.
123
+ * GitLab-only — GitHub does not support unapproving via API.
124
+ * Check `capabilities.canUnapprove` before calling.
125
+ */
126
+ unapprovePullRequest(projectPath: string, mrIid: number): Promise<void>;
127
+
128
+ /**
129
+ * Rebase the MR source branch onto the target branch.
130
+ * GitLab-only — GitHub does not have a native rebase API.
131
+ * Check `capabilities.canRebase` before calling.
132
+ */
133
+ rebasePullRequest(projectPath: string, mrIid: number): Promise<void>;
134
+
135
+ /**
136
+ * Enable auto-merge: the MR will be merged automatically when the
137
+ * pipeline succeeds and all approval rules are met.
138
+ * GitLab-only — check `capabilities.canAutoMerge` before calling.
139
+ */
140
+ setAutoMerge(projectPath: string, mrIid: number): Promise<void>;
141
+
142
+ /**
143
+ * Cancel a previously enabled auto-merge.
144
+ * GitLab-only — check `capabilities.canAutoMerge` before calling.
145
+ */
146
+ cancelAutoMerge(projectPath: string, mrIid: number): Promise<void>;
147
+
148
+ // ── Discussion mutations ────────────────────────────────────────────────
149
+
150
+ /**
151
+ * Resolve a discussion thread on an MR.
152
+ * GitLab-only — check `capabilities.canResolveDiscussions` before calling.
153
+ */
154
+ resolveDiscussion(
155
+ projectPath: string,
156
+ mrIid: number,
157
+ discussionId: string
158
+ ): Promise<void>;
159
+
160
+ /**
161
+ * Unresolve a previously resolved discussion thread.
162
+ * GitLab-only — check `capabilities.canResolveDiscussions` before calling.
163
+ */
164
+ unresolveDiscussion(
165
+ projectPath: string,
166
+ mrIid: number,
167
+ discussionId: string
168
+ ): Promise<void>;
169
+
170
+ // ── Pipeline mutations ──────────────────────────────────────────────────
171
+
172
+ /**
173
+ * Retry a failed or canceled pipeline.
174
+ * On GitLab: POST /pipelines/:id/retry
175
+ * On GitHub: POST re-run for the workflow run.
176
+ */
177
+ retryPipeline(projectPath: string, pipelineId: number): Promise<void>;
178
+
179
+ // ── Review mutations ────────────────────────────────────────────────────
180
+
181
+ /**
182
+ * Re-request review attention on an MR from its reviewers.
183
+ * If `reviewerUsernames` is provided, only those reviewers are pinged;
184
+ * otherwise all current reviewers are re-requested.
185
+ */
186
+ requestReReview(
187
+ projectPath: string,
43
188
  mrIid: number,
44
- ): Promise<MRDetail>;
189
+ reviewerUsernames?: string[]
190
+ ): Promise<void>;
45
191
 
46
192
  // ── REST pass-through (used by note mutations, job traces, etc.) ────────
47
193
 
@@ -52,11 +198,7 @@ export interface GitProvider {
52
198
  *
53
199
  * Implementations translate the path to the provider's API URL format.
54
200
  */
55
- restRequest(
56
- method: string,
57
- path: string,
58
- body?: unknown,
59
- ): Promise<Response>;
201
+ restRequest(method: string, path: string, body?: unknown): Promise<Response>;
60
202
  }
61
203
 
62
204
  /**
@@ -64,8 +206,8 @@ export interface GitProvider {
64
206
  * e.g. "gitlab:42" → 42, "github:12345" → 12345
65
207
  */
66
208
  export function parseRepoId(repositoryId: string): number {
67
- const parts = repositoryId.split(":");
68
- return parseInt(parts.at(-1) ?? "0", 10);
209
+ const parts = repositoryId.split(':');
210
+ return parseInt(parts.at(-1) ?? '0', 10);
69
211
  }
70
212
 
71
213
  /**
@@ -73,5 +215,5 @@ export function parseRepoId(repositoryId: string): number {
73
215
  * e.g. "gitlab:42" → "gitlab", "github:12345" → "github"
74
216
  */
75
217
  export function repoIdProvider(repositoryId: string): string {
76
- return repositoryId.split(":")[0] ?? "unknown";
218
+ return repositoryId.split(':')[0] ?? 'unknown';
77
219
  }
package/src/index.ts CHANGED
@@ -16,6 +16,12 @@
16
16
  export type {
17
17
  PullRequest,
18
18
  PullRequestsSnapshot,
19
+ CreatePullRequestInput,
20
+ UpdatePullRequestInput,
21
+ MergePullRequestInput,
22
+ MergeMethod,
23
+ ProviderCapabilities,
24
+ BranchProtectionRule,
19
25
  Pipeline,
20
26
  PipelineJob,
21
27
  UserRef,
@@ -27,28 +33,32 @@ export type {
27
33
  MRDetail,
28
34
  FeedEvent,
29
35
  FeedSnapshot,
30
- ServerNotification,
31
- } from "./types.ts";
36
+ ServerNotification
37
+ } from './types.ts';
32
38
 
33
39
  // ── Provider interface ────────────────────────────────────────────────────────
34
- export type { GitProvider } from "./GitProvider.ts";
35
- export { parseRepoId, repoIdProvider } from "./GitProvider.ts";
40
+ export type { GitProvider } from './GitProvider.ts';
41
+ export { parseRepoId, repoIdProvider } from './GitProvider.ts';
36
42
 
37
43
  // ── Logger ────────────────────────────────────────────────────────────────────
38
- export type { ForgeLogger } from "./logger.ts";
39
- export { noopLogger } from "./logger.ts";
44
+ export type { ForgeLogger } from './logger.ts';
45
+ export { noopLogger } from './logger.ts';
40
46
 
41
47
  // ── Providers ─────────────────────────────────────────────────────────────────
42
- export { GitLabProvider, parseGitLabRepoId, MR_DASHBOARD_FRAGMENT } from "./GitLabProvider.ts";
43
- export { GitHubProvider } from "./GitHubProvider.ts";
44
- export { createProvider, SUPPORTED_PROVIDERS } from "./providers.ts";
45
- export type { ProviderSlug } from "./providers.ts";
48
+ export {
49
+ GitLabProvider,
50
+ parseGitLabRepoId,
51
+ MR_DASHBOARD_FRAGMENT
52
+ } from './GitLabProvider.ts';
53
+ export { GitHubProvider } from './GitHubProvider.ts';
54
+ export { createProvider, SUPPORTED_PROVIDERS } from './providers.ts';
55
+ export type { ProviderSlug } from './providers.ts';
46
56
 
47
57
  // ── GitLab real-time ──────────────────────────────────────────────────────────
48
- export { ActionCableClient } from "./ActionCableClient.ts";
49
- export type { ActionCableCallbacks } from "./ActionCableClient.ts";
58
+ export { ActionCableClient } from './ActionCableClient.ts';
59
+ export type { ActionCableCallbacks } from './ActionCableClient.ts';
50
60
 
51
61
  // ── GitLab detail + mutations ─────────────────────────────────────────────────
52
- export { MRDetailFetcher } from "./MRDetailFetcher.ts";
53
- export { NoteMutator } from "./NoteMutator.ts";
54
- export type { CreatedNote } from "./NoteMutator.ts";
62
+ export { MRDetailFetcher } from './MRDetailFetcher.ts';
63
+ export { NoteMutator } from './NoteMutator.ts';
64
+ export type { CreatedNote } from './NoteMutator.ts';
package/src/types.ts CHANGED
@@ -84,6 +84,117 @@ export interface PullRequest {
84
84
  detailedMergeStatus: string | null;
85
85
  }
86
86
 
87
+ // ── MR/PR mutation inputs ─────────────────────────────────────────────────────
88
+
89
+ /** Input for creating a new merge request / pull request. */
90
+ export interface CreatePullRequestInput {
91
+ /** Project path (GitLab: "group/project") or owner/repo (GitHub: "owner/repo"). */
92
+ projectPath: string;
93
+ title: string;
94
+ description?: string;
95
+ sourceBranch: string;
96
+ targetBranch: string;
97
+ draft?: boolean;
98
+ /** Usernames to assign as reviewers. */
99
+ reviewers?: string[];
100
+ /** Usernames to assign. */
101
+ assignees?: string[];
102
+ /** Labels to apply (string names). */
103
+ labels?: string[];
104
+ }
105
+
106
+ /** Input for updating an existing merge request / pull request. */
107
+ export interface UpdatePullRequestInput {
108
+ title?: string;
109
+ description?: string;
110
+ /** Set draft status. */
111
+ draft?: boolean;
112
+ /** Change the target branch. */
113
+ targetBranch?: string;
114
+ /** Usernames to assign as reviewers (replaces current set). */
115
+ reviewers?: string[];
116
+ /** Usernames to assign (replaces current set). */
117
+ assignees?: string[];
118
+ /** Labels (replaces current set). */
119
+ labels?: string[];
120
+ /** Set MR state: "close" or "reopen". */
121
+ stateEvent?: 'close' | 'reopen';
122
+ }
123
+
124
+ /**
125
+ * Merge strategy override.
126
+ * - "merge" — Standard merge commit.
127
+ * - "squash" — Squash all commits into one before merging.
128
+ * - "rebase" — Rebase the source branch onto the target (fast-forward).
129
+ *
130
+ * When omitted, the provider uses the project's configured default merge method.
131
+ */
132
+ export type MergeMethod = 'merge' | 'squash' | 'rebase';
133
+
134
+ /**
135
+ * Input for merging (accepting) a pull request / merge request.
136
+ *
137
+ * All fields are **optional**. Omitting them defers to the project-level
138
+ * settings configured in the forge UI (merge method, squash policy,
139
+ * delete-source-branch, etc.). This matches how the web UI works.
140
+ */
141
+ export interface MergePullRequestInput {
142
+ /** Merge commit message. Omit to use the provider/project default. */
143
+ commitMessage?: string;
144
+ /** Squash commit message (when merge method is "squash"). */
145
+ squashCommitMessage?: string;
146
+ /** Whether to squash commits. Omit to use the MR / project default. */
147
+ squash?: boolean;
148
+ /** Merge strategy override. Omit to use the project's default merge method. */
149
+ mergeMethod?: MergeMethod;
150
+ /** Delete source branch after merge. Omit to use project default. */
151
+ shouldRemoveSourceBranch?: boolean;
152
+ /** SHA that HEAD must match for the merge to proceed (optimistic locking). */
153
+ sha?: string;
154
+ }
155
+
156
+ /**
157
+ * Reports which mutation operations a provider supports.
158
+ *
159
+ * Callers should check these flags before invoking vendor-specific methods
160
+ * so they can conditionally show/hide UI affordances without
161
+ * knowing which provider they're talking to.
162
+ */
163
+ export interface ProviderCapabilities {
164
+ /** Can merge / accept a pull request. */
165
+ canMerge: boolean;
166
+ /** Can approve a pull request. */
167
+ canApprove: boolean;
168
+ /** Can revoke an existing approval. */
169
+ canUnapprove: boolean;
170
+ /** Can rebase the source branch onto the target. */
171
+ canRebase: boolean;
172
+ /** Can enable automatic merge when pipeline succeeds. */
173
+ canAutoMerge: boolean;
174
+ /** Can resolve / unresolve discussion threads. */
175
+ canResolveDiscussions: boolean;
176
+ /** Can retry a pipeline. */
177
+ canRetryPipeline: boolean;
178
+ /** Can re-request review attention from reviewers. */
179
+ canRequestReReview: boolean;
180
+ }
181
+
182
+ /** Branch protection rule (provider-agnostic). */
183
+ export interface BranchProtectionRule {
184
+ /** Branch name or pattern, e.g. "main" or "release/*". */
185
+ pattern: string;
186
+ /** Whether force-pushes are allowed. */
187
+ allowForcePush: boolean;
188
+ /** Whether branch deletions are allowed. */
189
+ allowDeletion: boolean;
190
+ /** Number of required approving reviews (0 = none required). */
191
+ requiredApprovals: number;
192
+ /** Whether the branch requires status checks to pass before merge. */
193
+ requireStatusChecks: boolean;
194
+ /** Raw provider-specific data for fields not covered above. */
195
+ raw?: Record<string, unknown>;
196
+ }
197
+
87
198
  /** Snapshot payload sent when a client first connects. */
88
199
  export interface PullRequestsSnapshot {
89
200
  items: PullRequest[];