@magnusekdahl/parallix 1.2.1 → 1.3.1
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/index.js +190 -185
- package/lib/agents/agents.js +34 -4
- package/lib/agents/agents.ts +40 -5
- package/lib/commands/active.js +502 -579
- package/lib/commands/active.ts +665 -0
- package/lib/commands/checkpoint.js +98 -74
- package/lib/commands/checkpoint.ts +79 -0
- package/lib/commands/config.js +61 -31
- package/lib/commands/config.ts +47 -0
- package/lib/commands/coverage-gate.js +271 -246
- package/lib/commands/coverage-gate.ts +362 -0
- package/lib/commands/diff.js +140 -119
- package/lib/commands/diff.ts +125 -0
- package/lib/commands/draft.js +770 -923
- package/lib/commands/draft.ts +1021 -0
- package/lib/commands/handoff.js +588 -608
- package/lib/commands/handoff.ts +694 -0
- package/lib/commands/integrate.js +1331 -1468
- package/lib/commands/integrate.ts +1688 -0
- package/lib/commands/mission-start.js +279 -237
- package/lib/commands/mission-start.ts +263 -0
- package/lib/commands/rebase.js +606 -582
- package/lib/commands/rebase.ts +635 -0
- package/lib/commands/repair-handoff.js +181 -179
- package/lib/commands/repair-handoff.ts +228 -0
- package/lib/commands/resolve-conflict.js +121 -102
- package/lib/commands/resolve-conflict.ts +112 -0
- package/lib/commands/review.js +3 -4
- package/lib/commands/review.ts +14 -0
- package/lib/commands/setup-review.js +4 -5
- package/lib/commands/setup-review.ts +14 -0
- package/lib/commands/setup.js +3 -3
- package/lib/commands/setup.ts +2 -0
- package/lib/commands/stats-backfill.js +394 -359
- package/lib/commands/stats-backfill.ts +418 -0
- package/lib/commands/stats.js +1424 -1665
- package/lib/commands/stats.ts +2186 -0
- package/lib/commands/status.js +219 -200
- package/lib/commands/status.ts +219 -0
- package/lib/commands/verify.js +3 -1
- package/lib/commands/verify.ts +2 -0
- package/lib/core/nels.js +112 -127
- package/lib/core/nels.ts +189 -0
- package/lib/core/subagent-limit.js +15 -16
- package/lib/core/subagent-limit.ts +25 -0
- package/lib/index.js +142 -59
- package/lib/index.ts +134 -0
- package/lib/review/rebase.js +142 -145
- package/lib/review/rebase.ts +188 -0
- package/lib/review/review-adapter.js +99 -87
- package/lib/review/review-adapter.ts +198 -0
- package/lib/review/review-artifacts.js +486 -629
- package/lib/review/review-artifacts.ts +622 -0
- package/lib/review/review-commands.js +1220 -1373
- package/lib/review/review-commands.ts +1579 -0
- package/lib/review/review-events.js +544 -886
- package/lib/review/review-events.ts +954 -0
- package/lib/review/review-loop.js +945 -1020
- package/lib/review/review-loop.ts +1174 -0
- package/lib/review/review-polling.js +86 -115
- package/lib/review/review-polling.ts +194 -0
- package/lib/review/review-prompts.js +154 -189
- package/lib/review/review-prompts.ts +182 -0
- package/lib/review/review-state.js +246 -225
- package/lib/review/review-state.ts +353 -0
- package/lib/review/review.js +63 -84
- package/lib/review/review.ts +138 -0
- package/lib/tools/backlog.js +694 -680
- package/lib/tools/backlog.ts +835 -0
- package/lib/tools/forgejo.js +1270 -1405
- package/lib/tools/forgejo.ts +1793 -0
- package/lib/tools/gatekeeper.js +106 -96
- package/lib/tools/gatekeeper.ts +124 -0
- package/lib/tools/redgreen.js +200 -181
- package/lib/tools/redgreen.ts +221 -0
- package/lib/tools/sessions.js +58 -52
- package/lib/tools/sessions.ts +81 -0
- package/lib/tools/setup-review.js +902 -975
- package/lib/tools/setup-review.ts +1152 -0
- package/package.json +4 -4
- package/px.js +226 -208
package/lib/tools/gatekeeper.js
CHANGED
|
@@ -1,124 +1,134 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.DEFAULT_GATEKEEPER_USER = void 0;
|
|
40
|
+
exports.checkMandatoryFiles = checkMandatoryFiles;
|
|
41
|
+
exports.buildPushbackBody = buildPushbackBody;
|
|
42
|
+
exports.runGatekeeper = runGatekeeper;
|
|
43
|
+
const fs_1 = __importDefault(require("fs"));
|
|
44
|
+
const path_1 = __importDefault(require("path"));
|
|
45
|
+
const fmt = __importStar(require("../core/fmt.js"));
|
|
46
|
+
const mission_utils_js_1 = require("../core/mission-utils.js");
|
|
47
|
+
const backlog_js_1 = require("./backlog.js");
|
|
48
|
+
const forgejo_js_1 = require("./forgejo.js");
|
|
9
49
|
const DEFAULT_GATEKEEPER_USER = 'forgejo-gatekeeper';
|
|
10
|
-
|
|
50
|
+
exports.DEFAULT_GATEKEEPER_USER = DEFAULT_GATEKEEPER_USER;
|
|
11
51
|
// Pre-review pushback bot. Runs after performHandoff has created/updated the
|
|
12
52
|
// PR and before the human/agent reviewer engages, so missing mandatory
|
|
13
53
|
// artifacts surface as a request-changes review instead of consuming a
|
|
14
54
|
// reviewer cycle. Returns { ok, missing, skipped, posted } so callers can
|
|
15
55
|
// surface a clear log line without needing to re-derive state.
|
|
16
|
-
|
|
17
56
|
/**
|
|
18
57
|
* @param {string} slug
|
|
19
58
|
* @param {{rootDir?: string, findMissionDirFn?: Function, findCheckpointsFn?: Function, resolveTaskFileFn?: Function}} [options]
|
|
20
59
|
* @returns {{ok: boolean, missing: string[]}}
|
|
21
60
|
*/
|
|
22
61
|
function checkMandatoryFiles(slug, options = {}) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
const { rootDir = process.cwd(), findMissionDirFn = mission_utils_js_1.findMissionDir, findCheckpointsFn = mission_utils_js_1.findCheckpoints, resolveTaskFileFn = backlog_js_1.resolveTaskFile } = options;
|
|
63
|
+
const missing = [];
|
|
64
|
+
const expectedMissionDir = (0, mission_utils_js_1.missionDirForSlug)(rootDir, slug);
|
|
65
|
+
const expectedMissionRel = path_1.default.relative(rootDir, expectedMissionDir).split(path_1.default.sep).join('/');
|
|
66
|
+
const missionDir = findMissionDirFn(slug, rootDir);
|
|
67
|
+
const missionPath = missionDir ? path_1.default.join(missionDir, 'MISSION.md') : null;
|
|
68
|
+
if (!missionPath || !fs_1.default.existsSync(missionPath)) {
|
|
69
|
+
missing.push(`${expectedMissionRel}/MISSION.md`);
|
|
70
|
+
}
|
|
71
|
+
if (missionDir) {
|
|
72
|
+
const checkpoints = findCheckpointsFn(missionDir);
|
|
73
|
+
if (!checkpoints || checkpoints.length === 0) {
|
|
74
|
+
missing.push(`${expectedMissionRel}/CP-*.md (at least one checkpoint document)`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
missing.push(`${expectedMissionRel}/CP-*.md (at least one checkpoint document)`);
|
|
79
|
+
}
|
|
80
|
+
const taskResolution = resolveTaskFileFn(slug, rootDir);
|
|
81
|
+
const missionArtifactsPresent = Boolean(missionPath && fs_1.default.existsSync(missionPath) && missionDir && findCheckpointsFn(missionDir).length > 0);
|
|
82
|
+
if ((!taskResolution || !taskResolution.ok) && !missionArtifactsPresent) {
|
|
83
|
+
const { tasksDir } = (0, backlog_js_1.getTaskStorage)(rootDir);
|
|
84
|
+
const taskDirRel = path_1.default.relative(rootDir, tasksDir).split(path_1.default.sep).join('/');
|
|
85
|
+
missing.push(`${taskDirRel}/${slug} - *.md`);
|
|
44
86
|
}
|
|
45
|
-
|
|
46
|
-
missing.push(`${expectedMissionRel}/CP-*.md (at least one checkpoint document)`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const taskResolution = resolveTaskFileFn(slug, rootDir);
|
|
50
|
-
const missionArtifactsPresent = Boolean(missionPath && fs.existsSync(missionPath) && missionDir && findCheckpointsFn(missionDir).length > 0);
|
|
51
|
-
if ((!taskResolution || !taskResolution.ok) && !missionArtifactsPresent) {
|
|
52
|
-
const { tasksDir } = getTaskStorage(rootDir);
|
|
53
|
-
const taskDirRel = path.relative(rootDir, tasksDir).split(path.sep).join('/');
|
|
54
|
-
missing.push(`${taskDirRel}/${slug} - *.md`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return { ok: missing.length === 0, missing };
|
|
87
|
+
return { ok: missing.length === 0, missing };
|
|
58
88
|
}
|
|
59
|
-
|
|
60
89
|
/**
|
|
61
90
|
* @param {string} slug
|
|
62
91
|
* @param {string[]} missing
|
|
63
92
|
* @returns {string}
|
|
64
93
|
*/
|
|
65
94
|
function buildPushbackBody(slug, missing) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
95
|
+
const bullets = missing.map(item => `- ${item}`).join('\n');
|
|
96
|
+
return [
|
|
97
|
+
`**Pre-review gatekeeper: missing mandatory artifacts for \`${slug}\`.**`,
|
|
98
|
+
'',
|
|
99
|
+
'The following files are required before a reviewer engages but were not found on this branch:',
|
|
100
|
+
'',
|
|
101
|
+
bullets,
|
|
102
|
+
'',
|
|
103
|
+
'Push the missing artifacts and re-request review. This comment is automated; once the artifacts are present the gatekeeper will not block again.'
|
|
104
|
+
].join('\n');
|
|
76
105
|
}
|
|
77
|
-
|
|
78
106
|
/**
|
|
79
107
|
* @param {string} slug
|
|
80
108
|
* @param {{rootDir?: string, branch?: string, user?: string, log?: Function, readTokenFn?: Function, postReviewFn?: Function, checkFn?: Function}} [options]
|
|
81
109
|
* @returns {{ok: boolean, missing: string[], skipped: boolean, posted: boolean}}
|
|
82
110
|
*/
|
|
83
111
|
function runGatekeeper(slug, options = {}) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const body = buildPushbackBody(slug, check.missing);
|
|
107
|
-
log(fmt.status('INFO', `Gatekeeper: posting request-changes pushback on ${fmt.branch(branch)} as ${fmt.agent(user)}. Missing: ${check.missing.join(', ')}.`));
|
|
108
|
-
const result = postReviewFn(branch, token, 'request-changes', body);
|
|
109
|
-
|
|
110
|
-
if (!result || !result.ok) {
|
|
111
|
-
const detail = result && result.error ? result.error : 'unknown postReview failure';
|
|
112
|
-
log(fmt.status('WARN', `Gatekeeper: pushback post failed for ${fmt.slug(slug)}: ${detail}.`));
|
|
113
|
-
return { ok: false, missing: check.missing, skipped: false, posted: false };
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return { ok: false, missing: check.missing, skipped: false, posted: true };
|
|
112
|
+
const { rootDir = process.cwd(), user = process.env.FORGEJO_GATEKEEPER_USER || DEFAULT_GATEKEEPER_USER, log = fmt.log.plain, readTokenFn = forgejo_js_1.readToken, postReviewFn = forgejo_js_1.postReview, checkFn = checkMandatoryFiles } = options;
|
|
113
|
+
const branch = options.branch || (0, mission_utils_js_1.missionBranchName)(slug, rootDir);
|
|
114
|
+
const check = checkFn(slug, { rootDir });
|
|
115
|
+
if (check.ok) {
|
|
116
|
+
log(fmt.status('INFO', `Gatekeeper: all mandatory artifacts present for ${fmt.slug(slug)}.`));
|
|
117
|
+
return { ok: true, missing: [], skipped: false, posted: false };
|
|
118
|
+
}
|
|
119
|
+
const token = readTokenFn(user);
|
|
120
|
+
if (!token) {
|
|
121
|
+
log(fmt.status('WARN', `Gatekeeper: no Forgejo token for "${fmt.agent(user)}"; skipping pushback for ${fmt.slug(slug)}. Missing: ${check.missing.join(', ')}.`));
|
|
122
|
+
return { ok: false, missing: check.missing, skipped: true, posted: false };
|
|
123
|
+
}
|
|
124
|
+
const body = buildPushbackBody(slug, check.missing);
|
|
125
|
+
log(fmt.status('INFO', `Gatekeeper: posting request-changes pushback on ${fmt.branch(branch)} as ${fmt.agent(user)}. Missing: ${check.missing.join(', ')}.`));
|
|
126
|
+
const result = postReviewFn(branch, token, 'request-changes', body);
|
|
127
|
+
if (!result || !result.ok) {
|
|
128
|
+
const detail = result && result.error ? result.error : 'unknown postReview failure';
|
|
129
|
+
log(fmt.status('WARN', `Gatekeeper: pushback post failed for ${fmt.slug(slug)}: ${detail}.`));
|
|
130
|
+
return { ok: false, missing: check.missing, skipped: false, posted: false };
|
|
131
|
+
}
|
|
132
|
+
return { ok: false, missing: check.missing, skipped: false, posted: true };
|
|
117
133
|
}
|
|
118
|
-
|
|
119
|
-
module.exports = {
|
|
120
|
-
DEFAULT_GATEKEEPER_USER,
|
|
121
|
-
checkMandatoryFiles,
|
|
122
|
-
buildPushbackBody,
|
|
123
|
-
runGatekeeper
|
|
124
|
-
};
|
|
134
|
+
;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import * as fmt from '../core/fmt.js';
|
|
4
|
+
|
|
5
|
+
import { findMissionDir, findCheckpoints, missionDirForSlug, missionBranchName } from '../core/mission-utils.js';
|
|
6
|
+
import { resolveTaskFile, getTaskStorage } from './backlog.js';
|
|
7
|
+
import { readToken, postReview } from './forgejo.js';
|
|
8
|
+
|
|
9
|
+
const DEFAULT_GATEKEEPER_USER = 'forgejo-gatekeeper';
|
|
10
|
+
|
|
11
|
+
// Pre-review pushback bot. Runs after performHandoff has created/updated the
|
|
12
|
+
// PR and before the human/agent reviewer engages, so missing mandatory
|
|
13
|
+
// artifacts surface as a request-changes review instead of consuming a
|
|
14
|
+
// reviewer cycle. Returns { ok, missing, skipped, posted } so callers can
|
|
15
|
+
// surface a clear log line without needing to re-derive state.
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} slug
|
|
19
|
+
* @param {{rootDir?: string, findMissionDirFn?: Function, findCheckpointsFn?: Function, resolveTaskFileFn?: Function}} [options]
|
|
20
|
+
* @returns {{ok: boolean, missing: string[]}}
|
|
21
|
+
*/
|
|
22
|
+
function checkMandatoryFiles(slug: string, options: { rootDir?: string, findMissionDirFn?: Function, findCheckpointsFn?: Function, resolveTaskFileFn?: Function } = {} as any) {
|
|
23
|
+
const {
|
|
24
|
+
rootDir = process.cwd(),
|
|
25
|
+
findMissionDirFn = findMissionDir,
|
|
26
|
+
findCheckpointsFn = findCheckpoints,
|
|
27
|
+
resolveTaskFileFn = resolveTaskFile
|
|
28
|
+
} = options;
|
|
29
|
+
|
|
30
|
+
const missing = [];
|
|
31
|
+
const expectedMissionDir = missionDirForSlug(rootDir, slug);
|
|
32
|
+
const expectedMissionRel = path.relative(rootDir, expectedMissionDir).split(path.sep).join('/');
|
|
33
|
+
|
|
34
|
+
const missionDir = findMissionDirFn(slug, rootDir);
|
|
35
|
+
const missionPath = missionDir ? path.join(missionDir, 'MISSION.md') : null;
|
|
36
|
+
if (!missionPath || !fs.existsSync(missionPath)) {
|
|
37
|
+
missing.push(`${expectedMissionRel}/MISSION.md`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (missionDir) {
|
|
41
|
+
const checkpoints = findCheckpointsFn(missionDir);
|
|
42
|
+
if (!checkpoints || checkpoints.length === 0) {
|
|
43
|
+
missing.push(`${expectedMissionRel}/CP-*.md (at least one checkpoint document)`);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
missing.push(`${expectedMissionRel}/CP-*.md (at least one checkpoint document)`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const taskResolution = resolveTaskFileFn(slug, rootDir);
|
|
50
|
+
const missionArtifactsPresent = Boolean(missionPath && fs.existsSync(missionPath) && missionDir && findCheckpointsFn(missionDir).length > 0);
|
|
51
|
+
if ((!taskResolution || !taskResolution.ok) && !missionArtifactsPresent) {
|
|
52
|
+
const { tasksDir } = getTaskStorage(rootDir);
|
|
53
|
+
const taskDirRel = path.relative(rootDir, tasksDir).split(path.sep).join('/');
|
|
54
|
+
missing.push(`${taskDirRel}/${slug} - *.md`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { ok: missing.length === 0, missing };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {string} slug
|
|
62
|
+
* @param {string[]} missing
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
function buildPushbackBody(slug: string, missing: string[]): string {
|
|
66
|
+
const bullets = missing.map(item => `- ${item}`).join('\n');
|
|
67
|
+
return [
|
|
68
|
+
`**Pre-review gatekeeper: missing mandatory artifacts for \`${slug}\`.**`,
|
|
69
|
+
'',
|
|
70
|
+
'The following files are required before a reviewer engages but were not found on this branch:',
|
|
71
|
+
'',
|
|
72
|
+
bullets,
|
|
73
|
+
'',
|
|
74
|
+
'Push the missing artifacts and re-request review. This comment is automated; once the artifacts are present the gatekeeper will not block again.'
|
|
75
|
+
].join('\n');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {string} slug
|
|
80
|
+
* @param {{rootDir?: string, branch?: string, user?: string, log?: Function, readTokenFn?: Function, postReviewFn?: Function, checkFn?: Function}} [options]
|
|
81
|
+
* @returns {{ok: boolean, missing: string[], skipped: boolean, posted: boolean}}
|
|
82
|
+
*/
|
|
83
|
+
function runGatekeeper(slug: string, options: { rootDir?: string, branch?: string, user?: string, log?: Function, readTokenFn?: Function, postReviewFn?: Function, checkFn?: Function } = {} as any) {
|
|
84
|
+
const {
|
|
85
|
+
rootDir = process.cwd(),
|
|
86
|
+
user = process.env.FORGEJO_GATEKEEPER_USER || DEFAULT_GATEKEEPER_USER,
|
|
87
|
+
log = fmt.log.plain,
|
|
88
|
+
readTokenFn = readToken,
|
|
89
|
+
postReviewFn = postReview,
|
|
90
|
+
checkFn = checkMandatoryFiles
|
|
91
|
+
} = options;
|
|
92
|
+
const branch = options.branch || missionBranchName(slug, rootDir);
|
|
93
|
+
|
|
94
|
+
const check = checkFn(slug, { rootDir });
|
|
95
|
+
if (check.ok) {
|
|
96
|
+
log(fmt.status('INFO', `Gatekeeper: all mandatory artifacts present for ${fmt.slug(slug)}.`));
|
|
97
|
+
return { ok: true, missing: [], skipped: false, posted: false };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const token = readTokenFn(user);
|
|
101
|
+
if (!token) {
|
|
102
|
+
log(fmt.status('WARN', `Gatekeeper: no Forgejo token for "${fmt.agent(user)}"; skipping pushback for ${fmt.slug(slug)}. Missing: ${check.missing.join(', ')}.`));
|
|
103
|
+
return { ok: false, missing: check.missing, skipped: true, posted: false };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const body = buildPushbackBody(slug, check.missing);
|
|
107
|
+
log(fmt.status('INFO', `Gatekeeper: posting request-changes pushback on ${fmt.branch(branch)} as ${fmt.agent(user)}. Missing: ${check.missing.join(', ')}.`));
|
|
108
|
+
const result = postReviewFn(branch, token, 'request-changes', body);
|
|
109
|
+
|
|
110
|
+
if (!result || !result.ok) {
|
|
111
|
+
const detail = result && result.error ? result.error : 'unknown postReview failure';
|
|
112
|
+
log(fmt.status('WARN', `Gatekeeper: pushback post failed for ${fmt.slug(slug)}: ${detail}.`));
|
|
113
|
+
return { ok: false, missing: check.missing, skipped: false, posted: false };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { ok: false, missing: check.missing, skipped: false, posted: true };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
export { DEFAULT_GATEKEEPER_USER };
|
|
121
|
+
export { checkMandatoryFiles };
|
|
122
|
+
export { buildPushbackBody };
|
|
123
|
+
export { runGatekeeper };
|
|
124
|
+
;
|