merge-steward 0.8.8 → 0.8.10
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.
- package/dist/github/shell-git.d.ts +6 -0
- package/dist/github/shell-git.js +9 -0
- package/dist/github-auth.d.ts +1 -0
- package/dist/github-auth.js +5 -0
- package/dist/reconciler.js +2 -0
- package/dist/server.js +17 -3
- package/package.json +1 -1
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { GitOperations, SpeculativeBranchBuilder } from "../interfaces.ts";
|
|
2
2
|
import type { MergeResult } from "../types.ts";
|
|
3
|
+
export interface BotIdentity {
|
|
4
|
+
name: string;
|
|
5
|
+
email: string;
|
|
6
|
+
}
|
|
3
7
|
export declare class ShellGitOperations implements GitOperations, SpeculativeBranchBuilder {
|
|
4
8
|
private readonly clonePath;
|
|
5
9
|
private readonly repoFullName;
|
|
6
10
|
private readonly gitBin;
|
|
7
11
|
private readonly worktreeBase;
|
|
12
|
+
private botIdentity;
|
|
8
13
|
constructor(clonePath: string, repoFullName: string, gitBin?: string);
|
|
14
|
+
setBotIdentity(identity: BotIdentity): void;
|
|
9
15
|
private git;
|
|
10
16
|
/** Run a git command in a specific directory (worktree). */
|
|
11
17
|
private gitIn;
|
package/dist/github/shell-git.js
CHANGED
|
@@ -17,12 +17,16 @@ export class ShellGitOperations {
|
|
|
17
17
|
repoFullName;
|
|
18
18
|
gitBin;
|
|
19
19
|
worktreeBase;
|
|
20
|
+
botIdentity;
|
|
20
21
|
constructor(clonePath, repoFullName, gitBin = "git") {
|
|
21
22
|
this.clonePath = clonePath;
|
|
22
23
|
this.repoFullName = repoFullName;
|
|
23
24
|
this.gitBin = gitBin;
|
|
24
25
|
this.worktreeBase = `${clonePath}-worktrees`;
|
|
25
26
|
}
|
|
27
|
+
setBotIdentity(identity) {
|
|
28
|
+
this.botIdentity = identity;
|
|
29
|
+
}
|
|
26
30
|
git(args, opts) {
|
|
27
31
|
return exec(this.gitBin, ["-C", this.clonePath, ...args], {
|
|
28
32
|
timeoutMs: opts?.timeoutMs ?? 120_000,
|
|
@@ -77,6 +81,11 @@ export class ShellGitOperations {
|
|
|
77
81
|
// Create isolated worktree with spec branch starting at baseBranch.
|
|
78
82
|
mkdirSync(this.worktreeBase, { recursive: true });
|
|
79
83
|
await this.git(["worktree", "add", "-B", specName, wtPath, baseBranch]);
|
|
84
|
+
// Override git identity so merge commits are attributed to the steward, not the clone owner.
|
|
85
|
+
if (this.botIdentity) {
|
|
86
|
+
await this.gitIn(wtPath, ["config", "user.name", this.botIdentity.name]);
|
|
87
|
+
await this.gitIn(wtPath, ["config", "user.email", this.botIdentity.email]);
|
|
88
|
+
}
|
|
80
89
|
// Merge PR into spec branch inside the worktree.
|
|
81
90
|
// PR branches are always remote refs — use explicit origin/ prefix
|
|
82
91
|
// because git DWIM doesn't reliably resolve bare names in worktrees.
|
package/dist/github-auth.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export interface GitHubAppTokenManager extends RuntimeGitHubAuthProvider {
|
|
|
21
21
|
start(): Promise<void>;
|
|
22
22
|
stop(): void;
|
|
23
23
|
}
|
|
24
|
+
export declare function resolveAppSlug(credentials: GitHubAppCredentials): Promise<string>;
|
|
24
25
|
export declare function issueGitHubAppToken(credentials: GitHubAppCredentials, options?: {
|
|
25
26
|
repoFullName?: string;
|
|
26
27
|
}): Promise<{
|
package/dist/github-auth.js
CHANGED
|
@@ -30,6 +30,11 @@ function githubHeaders(token) {
|
|
|
30
30
|
"X-GitHub-Api-Version": "2022-11-28",
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
export async function resolveAppSlug(credentials) {
|
|
34
|
+
const jwt = generateJwt(credentials.appId, credentials.privateKey);
|
|
35
|
+
const data = await fetchJson("https://api.github.com/app", { headers: githubHeaders(jwt) });
|
|
36
|
+
return data.slug;
|
|
37
|
+
}
|
|
33
38
|
async function resolveInstallationIdForRepo(jwt, repoFullName) {
|
|
34
39
|
const encodedRepo = repoFullName
|
|
35
40
|
.split("/")
|
package/dist/reconciler.js
CHANGED
|
@@ -222,6 +222,8 @@ async function prepareEntry(ctx, entry, isHead, prevEntry) {
|
|
|
222
222
|
}
|
|
223
223
|
const specSha = result.sha ?? entry.headSha;
|
|
224
224
|
emit(ctx, entry, "spec_build_succeeded", { specBranch: specName, ...(prevEntry ? { dependsOn: prevEntry.id } : {}) });
|
|
225
|
+
// Push spec to remote so CI can access it.
|
|
226
|
+
await ctx.git.push(specName, true);
|
|
225
227
|
// Trigger CI on the spec branch.
|
|
226
228
|
const runId = await ctx.ci.triggerRun(specName, specSha);
|
|
227
229
|
emit(ctx, entry, "ci_triggered", { ciRunId: runId, specBranch: specName });
|
package/dist/server.js
CHANGED
|
@@ -10,18 +10,20 @@ import { buildMultiRepoHttpServer } from "./http-multi.js";
|
|
|
10
10
|
import { loadAllRepoConfigs } from "./install.js";
|
|
11
11
|
import { parseHomeConfigObject } from "./steward-home.js";
|
|
12
12
|
import { getMergeStewardPathLayout } from "./runtime-paths.js";
|
|
13
|
-
import { createGitHubAppTokenManager, resolveGitHubAuthConfig } from "./github-auth.js";
|
|
13
|
+
import { createGitHubAppTokenManager, resolveGitHubAuthConfig, resolveAppSlug } from "./github-auth.js";
|
|
14
14
|
import { discoverRepoSettings } from "./github-repo-discovery.js";
|
|
15
15
|
import { resolveSecret } from "./resolve-secret.js";
|
|
16
16
|
import { setRuntimeGitHubAuthProvider } from "./exec.js";
|
|
17
17
|
import { readFileSync, existsSync } from "node:fs";
|
|
18
|
-
async function createRepoInstance(config, logger) {
|
|
18
|
+
async function createRepoInstance(config, logger, botIdentity) {
|
|
19
19
|
const repoUrl = `https://github.com/${config.repoFullName}.git`;
|
|
20
20
|
const clone = new CloneManager(config.clonePath, repoUrl, config.repoFullName, config.gitBin, logger);
|
|
21
21
|
await clone.ensureClone();
|
|
22
22
|
await clone.fetch();
|
|
23
23
|
const store = new SqliteStore(config.database.path);
|
|
24
24
|
const git = new ShellGitOperations(clone.path, config.repoFullName, config.gitBin);
|
|
25
|
+
if (botIdentity)
|
|
26
|
+
git.setBotIdentity(botIdentity);
|
|
25
27
|
const ci = new GitHubActionsRunner(config.repoFullName, config.requiredChecks);
|
|
26
28
|
const github = new GitHubPRClient(config.repoFullName);
|
|
27
29
|
const eviction = new GitHubCheckRunReporter(config.repoFullName, config.server.bind, config.server.port, config.server.publicBaseUrl, config.admissionLabel, config.mergeQueueCheckName);
|
|
@@ -41,6 +43,7 @@ export async function startMultiServer() {
|
|
|
41
43
|
const configs = await loadAllRepoConfigs();
|
|
42
44
|
const githubAuth = resolveGitHubAuthConfig();
|
|
43
45
|
let githubAppTokenManager;
|
|
46
|
+
let botIdentity;
|
|
44
47
|
let githubRuntimeStatus = {
|
|
45
48
|
mode: "none",
|
|
46
49
|
configured: false,
|
|
@@ -64,6 +67,17 @@ export async function startMultiServer() {
|
|
|
64
67
|
setRuntimeGitHubAuthProvider(githubAppTokenManager);
|
|
65
68
|
try {
|
|
66
69
|
await githubAppTokenManager.start();
|
|
70
|
+
try {
|
|
71
|
+
const slug = await resolveAppSlug(githubAuth.credentials);
|
|
72
|
+
botIdentity = {
|
|
73
|
+
name: `${slug}[bot]`,
|
|
74
|
+
email: `${githubAuth.credentials.appId}+${slug}[bot]@users.noreply.github.com`,
|
|
75
|
+
};
|
|
76
|
+
logger.info({ botName: botIdentity.name }, "Resolved GitHub App bot identity");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
logger.warn("Could not resolve GitHub App slug, merge commits will use clone owner identity");
|
|
80
|
+
}
|
|
67
81
|
githubRuntimeStatus = {
|
|
68
82
|
...githubRuntimeStatus,
|
|
69
83
|
ready: true,
|
|
@@ -97,7 +111,7 @@ export async function startMultiServer() {
|
|
|
97
111
|
const instances = new Map();
|
|
98
112
|
for (const config of configs) {
|
|
99
113
|
logger.info({ repoId: config.repoId, repoFullName: config.repoFullName }, "Initializing repo");
|
|
100
|
-
const instance = await createRepoInstance(config, logger.child({ repoId: config.repoId }));
|
|
114
|
+
const instance = await createRepoInstance(config, logger.child({ repoId: config.repoId }), botIdentity);
|
|
101
115
|
instances.set(config.repoFullName, instance);
|
|
102
116
|
}
|
|
103
117
|
const app = await buildMultiRepoHttpServer({
|