@open-tomato/rafa 0.39.0 → 0.40.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.
- package/dist/cli.js +781 -164
- package/dist/effort/store/index.js +2 -2
- package/dist/{index-m0wt4nr1.js → index-334y39tn.js} +66 -0
- package/dist/{index-1r2b1052.js → index-8veaj0t9.js} +2 -2
- package/dist/{index-psv1sxkv.js → index-j7kjj0dd.js} +138 -51
- package/dist/{index-g4116t9m.js → index-krpmxpkh.js} +1 -1
- package/dist/{index-nwgwxfkt.js → index-zcbj07aq.js} +553 -100
- package/dist/index.js +4 -4
- package/dist/plan/index.js +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -747,6 +747,59 @@ var init_config_readers = __esm(() => {
|
|
|
747
747
|
FRAGMENTS_EXPECTED = `a relative directory path not under ${UNTRACKED_DIRECTORY}/`;
|
|
748
748
|
});
|
|
749
749
|
|
|
750
|
+
// src/config-schema-board-project.ts
|
|
751
|
+
function isWholeBetween(raw, min, max) {
|
|
752
|
+
return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= min && raw <= max;
|
|
753
|
+
}
|
|
754
|
+
function rangeWords(min, max) {
|
|
755
|
+
return `a whole number from ${String(min)} to ${String(max)}`;
|
|
756
|
+
}
|
|
757
|
+
function wholeBetween(min, max) {
|
|
758
|
+
return (raw, at) => isWholeBetween(raw, min, max) ? { value: raw, problems: [], extras: [] } : refused(at, raw, rangeWords(min, max));
|
|
759
|
+
}
|
|
760
|
+
function offOrWholeBetween(min, max) {
|
|
761
|
+
return (raw, at) => raw === false || isWholeBetween(raw, min, max) ? { value: raw, problems: [], extras: [] } : refused(at, raw, `false or ${rangeWords(min, max)}`);
|
|
762
|
+
}
|
|
763
|
+
var BOARD_PROJECT_RETRIES_MIN = 1, BOARD_PROJECT_RETRIES_MAX = 10, BOARD_PROJECT_RETRY_WAIT_MIN_SECONDS = 1, BOARD_PROJECT_RETRY_WAIT_MAX_SECONDS = 60, BOARD_PROJECT_PROGRESS_MIN_SECONDS = 1, BOARD_PROJECT_PROGRESS_MAX_SECONDS = 300, BOARD_PROJECT_WRITE_BATCH_MIN = 1, BOARD_PROJECT_WRITE_BATCH_MAX = 100, BOARD_PROJECT_WRITE_PAUSE_MIN_MS = 0, BOARD_PROJECT_WRITE_PAUSE_MAX_MS = 60000, boardProjectRetries, boardProjectRetryWaitSeconds, boardProjectProgressSeconds, boardProjectWriteBatchSize, boardProjectWritePauseMs, BOARD_PROJECT_LIMIT_DEFAULTS, BOARD_PROJECT_LIMIT_SETTINGS;
|
|
764
|
+
var init_config_schema_board_project = __esm(() => {
|
|
765
|
+
init_config_sections();
|
|
766
|
+
boardProjectRetries = offOrWholeBetween(BOARD_PROJECT_RETRIES_MIN, BOARD_PROJECT_RETRIES_MAX);
|
|
767
|
+
boardProjectRetryWaitSeconds = wholeBetween(BOARD_PROJECT_RETRY_WAIT_MIN_SECONDS, BOARD_PROJECT_RETRY_WAIT_MAX_SECONDS);
|
|
768
|
+
boardProjectProgressSeconds = offOrWholeBetween(BOARD_PROJECT_PROGRESS_MIN_SECONDS, BOARD_PROJECT_PROGRESS_MAX_SECONDS);
|
|
769
|
+
boardProjectWriteBatchSize = wholeBetween(BOARD_PROJECT_WRITE_BATCH_MIN, BOARD_PROJECT_WRITE_BATCH_MAX);
|
|
770
|
+
boardProjectWritePauseMs = wholeBetween(BOARD_PROJECT_WRITE_PAUSE_MIN_MS, BOARD_PROJECT_WRITE_PAUSE_MAX_MS);
|
|
771
|
+
BOARD_PROJECT_LIMIT_DEFAULTS = Object.freeze({
|
|
772
|
+
boardProjectRetries: 3,
|
|
773
|
+
boardProjectRetryWaitSeconds: 2,
|
|
774
|
+
boardProjectProgressSeconds: 10,
|
|
775
|
+
boardProjectWriteBatchSize: 20,
|
|
776
|
+
boardProjectWritePauseMs: 1000
|
|
777
|
+
});
|
|
778
|
+
BOARD_PROJECT_LIMIT_SETTINGS = {
|
|
779
|
+
boardProjectRetries: { key: "board.project.retries", read: boardProjectRetries, cli: false },
|
|
780
|
+
boardProjectRetryWaitSeconds: {
|
|
781
|
+
key: "board.project.retryWaitSeconds",
|
|
782
|
+
read: boardProjectRetryWaitSeconds,
|
|
783
|
+
cli: false
|
|
784
|
+
},
|
|
785
|
+
boardProjectProgressSeconds: {
|
|
786
|
+
key: "board.project.progressSeconds",
|
|
787
|
+
read: boardProjectProgressSeconds,
|
|
788
|
+
cli: false
|
|
789
|
+
},
|
|
790
|
+
boardProjectWriteBatchSize: {
|
|
791
|
+
key: "board.project.writeBatchSize",
|
|
792
|
+
read: boardProjectWriteBatchSize,
|
|
793
|
+
cli: false
|
|
794
|
+
},
|
|
795
|
+
boardProjectWritePauseMs: {
|
|
796
|
+
key: "board.project.writePauseMs",
|
|
797
|
+
read: boardProjectWritePauseMs,
|
|
798
|
+
cli: false
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
});
|
|
802
|
+
|
|
750
803
|
// src/config-schema-release.ts
|
|
751
804
|
var PR_DEFAULTS, RELEASE_DEFAULTS, DANGEROUS_RELEASE_DEFAULTS, PR_SETTINGS, RELEASE_SETTINGS, DANGEROUS_RELEASE_SETTINGS;
|
|
752
805
|
var init_config_schema_release = __esm(() => {
|
|
@@ -1093,6 +1146,7 @@ var CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, SETTING_NAMES, SETTING_BY_KEY, SECTI
|
|
|
1093
1146
|
var init_config_schema = __esm(() => {
|
|
1094
1147
|
init_config_items();
|
|
1095
1148
|
init_config_readers();
|
|
1149
|
+
init_config_schema_board_project();
|
|
1096
1150
|
init_config_schema_hub();
|
|
1097
1151
|
init_config_schema_release();
|
|
1098
1152
|
init_config_schema_tests();
|
|
@@ -1132,6 +1186,7 @@ var init_config_schema = __esm(() => {
|
|
|
1132
1186
|
boardRelationships: "labels",
|
|
1133
1187
|
boardProjectTemplate: BOARD_PROJECT_TEMPLATE_DEFAULT,
|
|
1134
1188
|
boardProjectNumber: null,
|
|
1189
|
+
...BOARD_PROJECT_LIMIT_DEFAULTS,
|
|
1135
1190
|
roadmapIssue: null,
|
|
1136
1191
|
claimsStaleAfter: "3d",
|
|
1137
1192
|
claimsAhead: "off",
|
|
@@ -1222,6 +1277,7 @@ var init_config_schema = __esm(() => {
|
|
|
1222
1277
|
},
|
|
1223
1278
|
boardProjectTemplate: { key: "board.project.template", read: projectUrl, cli: false },
|
|
1224
1279
|
boardProjectNumber: { key: "board.project.number", read: projectNumber, cli: false },
|
|
1280
|
+
...BOARD_PROJECT_LIMIT_SETTINGS,
|
|
1225
1281
|
roadmapIssue: { key: "roadmap.issue", read: issueNumber, cli: false },
|
|
1226
1282
|
claimsStaleAfter: { key: "claims.staleAfter", read: claimsStaleAfter, cli: false },
|
|
1227
1283
|
claimsAhead: { key: "claims.ahead", read: claimsAhead, cli: false },
|
|
@@ -1334,6 +1390,11 @@ function readLayer(rawOf, atOf) {
|
|
|
1334
1390
|
boardRelationships: read("boardRelationships"),
|
|
1335
1391
|
boardProjectTemplate: read("boardProjectTemplate"),
|
|
1336
1392
|
boardProjectNumber: read("boardProjectNumber"),
|
|
1393
|
+
boardProjectRetries: read("boardProjectRetries"),
|
|
1394
|
+
boardProjectRetryWaitSeconds: read("boardProjectRetryWaitSeconds"),
|
|
1395
|
+
boardProjectProgressSeconds: read("boardProjectProgressSeconds"),
|
|
1396
|
+
boardProjectWriteBatchSize: read("boardProjectWriteBatchSize"),
|
|
1397
|
+
boardProjectWritePauseMs: read("boardProjectWritePauseMs"),
|
|
1337
1398
|
roadmapIssue: read("roadmapIssue"),
|
|
1338
1399
|
claimsStaleAfter: read("claimsStaleAfter"),
|
|
1339
1400
|
claimsAhead: read("claimsAhead"),
|
|
@@ -2243,7 +2304,7 @@ function restoreRunningCommand(previous) {
|
|
|
2243
2304
|
var running = null;
|
|
2244
2305
|
|
|
2245
2306
|
// package.json
|
|
2246
|
-
var name = "@open-tomato/rafa", version = "0.
|
|
2307
|
+
var name = "@open-tomato/rafa", version = "0.40.0";
|
|
2247
2308
|
var init_package = () => {};
|
|
2248
2309
|
|
|
2249
2310
|
// src/cli/version.ts
|
|
@@ -21408,6 +21469,153 @@ var init_issue_board = __esm(() => {
|
|
|
21408
21469
|
CLOSE_REASONS = Object.freeze(["completed", "not planned"]);
|
|
21409
21470
|
});
|
|
21410
21471
|
|
|
21472
|
+
// src/board/project/retry.ts
|
|
21473
|
+
function firstMatch2(patterns, text2) {
|
|
21474
|
+
for (const pattern of patterns) {
|
|
21475
|
+
const match = pattern.exec(text2);
|
|
21476
|
+
if (match !== null)
|
|
21477
|
+
return match[0];
|
|
21478
|
+
}
|
|
21479
|
+
return;
|
|
21480
|
+
}
|
|
21481
|
+
function lastLine(text2) {
|
|
21482
|
+
const lines = text2.split(`
|
|
21483
|
+
`).map((line) => line.trim()).filter((line) => line !== "");
|
|
21484
|
+
return lines.at(-1) ?? UNKNOWN_REASON;
|
|
21485
|
+
}
|
|
21486
|
+
function classifyFailure(stderr) {
|
|
21487
|
+
const permanent = firstMatch2(NEVER_RETRIED, stderr);
|
|
21488
|
+
if (permanent !== undefined)
|
|
21489
|
+
return { kind: "permanent", reason: permanent };
|
|
21490
|
+
const retried = firstMatch2(RETRIED, stderr);
|
|
21491
|
+
if (retried !== undefined)
|
|
21492
|
+
return { kind: "retried", reason: retried };
|
|
21493
|
+
return { kind: "permanent", reason: lastLine(stderr) };
|
|
21494
|
+
}
|
|
21495
|
+
function callNumber(args) {
|
|
21496
|
+
for (let index = 0;index + 1 < args.length; index += 1) {
|
|
21497
|
+
const value = args[index + 1] ?? "";
|
|
21498
|
+
if (args[index] !== "-F" || !value.startsWith("number="))
|
|
21499
|
+
continue;
|
|
21500
|
+
const number = Number(value.slice("number=".length));
|
|
21501
|
+
if (Number.isSafeInteger(number))
|
|
21502
|
+
return number;
|
|
21503
|
+
}
|
|
21504
|
+
return;
|
|
21505
|
+
}
|
|
21506
|
+
function callSubject(args) {
|
|
21507
|
+
const number = callNumber(args);
|
|
21508
|
+
if (number !== undefined)
|
|
21509
|
+
return `#${String(number)}`;
|
|
21510
|
+
const query = args.find((arg) => arg.startsWith("query="));
|
|
21511
|
+
const field4 = query === undefined ? undefined : FIRST_FIELD.exec(query)?.[1];
|
|
21512
|
+
return field4 ?? args.slice(0, 2).join(" ");
|
|
21513
|
+
}
|
|
21514
|
+
function isWholeFrom(value, min) {
|
|
21515
|
+
return Number.isSafeInteger(value) && value >= min;
|
|
21516
|
+
}
|
|
21517
|
+
function checkOptions(options) {
|
|
21518
|
+
if (options.retries !== false && !isWholeFrom(options.retries, 1)) {
|
|
21519
|
+
throw new RangeError(`board.project.retries must be false or a whole number from 1, not ${String(options.retries)}`);
|
|
21520
|
+
}
|
|
21521
|
+
if (!isWholeFrom(options.retryWaitSeconds, 1)) {
|
|
21522
|
+
throw new RangeError(`board.project.retryWaitSeconds must be a whole number from 1, not ${String(options.retryWaitSeconds)}`);
|
|
21523
|
+
}
|
|
21524
|
+
}
|
|
21525
|
+
function retryingGhRunner(gh, options) {
|
|
21526
|
+
checkOptions(options);
|
|
21527
|
+
const { retries, retryWaitSeconds, onRetry } = options;
|
|
21528
|
+
if (retries === false)
|
|
21529
|
+
return gh;
|
|
21530
|
+
const sleep = options.sleep ?? ((ms) => Bun.sleep(ms));
|
|
21531
|
+
return async (args, stdin) => {
|
|
21532
|
+
let result = await gh(args, stdin);
|
|
21533
|
+
for (let attempt = 1;attempt <= retries && !result.ok; attempt += 1) {
|
|
21534
|
+
const reading2 = classifyFailure(result.stderr);
|
|
21535
|
+
if (reading2.kind === "permanent")
|
|
21536
|
+
return result;
|
|
21537
|
+
const waitMs = retryWaitSeconds * MS_PER_SECOND2 * 2 ** (attempt - 1);
|
|
21538
|
+
onRetry?.({
|
|
21539
|
+
attempt,
|
|
21540
|
+
of: retries,
|
|
21541
|
+
reason: reading2.reason,
|
|
21542
|
+
subject: callSubject(args),
|
|
21543
|
+
number: callNumber(args),
|
|
21544
|
+
waitMs,
|
|
21545
|
+
args
|
|
21546
|
+
});
|
|
21547
|
+
await sleep(waitMs);
|
|
21548
|
+
result = await gh(args, stdin);
|
|
21549
|
+
}
|
|
21550
|
+
return result;
|
|
21551
|
+
};
|
|
21552
|
+
}
|
|
21553
|
+
var NEVER_RETRIED, RETRIED, UNKNOWN_REASON = "unknown error", FIRST_FIELD, MS_PER_SECOND2 = 1000;
|
|
21554
|
+
var init_retry = __esm(() => {
|
|
21555
|
+
NEVER_RETRIED = Object.freeze([
|
|
21556
|
+
/RATE_LIMITED|(?:secondary )?rate limit/iu,
|
|
21557
|
+
/INSUFFICIENT_SCOPES|not been granted the required scopes|needs the "[^"]*" scope/u,
|
|
21558
|
+
/NOT_FOUND|Could not resolve to [^\n]*/u
|
|
21559
|
+
]);
|
|
21560
|
+
RETRIED = Object.freeze([
|
|
21561
|
+
/operation timed out|i\/o timeout|TLS handshake timeout/u,
|
|
21562
|
+
/connection reset|\bEOF\b/u,
|
|
21563
|
+
/\bHTTP 50[234]\b/u
|
|
21564
|
+
]);
|
|
21565
|
+
FIRST_FIELD = /\{\s*([A-Za-z_]\w*)/u;
|
|
21566
|
+
});
|
|
21567
|
+
|
|
21568
|
+
// src/board/project/project-runner.ts
|
|
21569
|
+
function retryLine(notice) {
|
|
21570
|
+
return `retrying ${notice.subject} (${String(notice.attempt)} of ${String(notice.of)}): ${notice.reason}`;
|
|
21571
|
+
}
|
|
21572
|
+
function retryEvent(notice, now) {
|
|
21573
|
+
return {
|
|
21574
|
+
type: "event",
|
|
21575
|
+
name: RETRY_EVENT,
|
|
21576
|
+
summary: retryLine(notice),
|
|
21577
|
+
data: {
|
|
21578
|
+
attempt: notice.attempt,
|
|
21579
|
+
of: notice.of,
|
|
21580
|
+
reason: notice.reason,
|
|
21581
|
+
subject: notice.subject,
|
|
21582
|
+
number: notice.number ?? null,
|
|
21583
|
+
waitMs: notice.waitMs
|
|
21584
|
+
},
|
|
21585
|
+
ts: now.toISOString()
|
|
21586
|
+
};
|
|
21587
|
+
}
|
|
21588
|
+
function retryReporter(output, mode, now = () => new Date) {
|
|
21589
|
+
return (notice) => {
|
|
21590
|
+
if (mode === "json")
|
|
21591
|
+
output.emit(retryEvent(notice, now()));
|
|
21592
|
+
else
|
|
21593
|
+
output.info(retryLine(notice));
|
|
21594
|
+
};
|
|
21595
|
+
}
|
|
21596
|
+
function commandRetrySeams(output, mode, sleep) {
|
|
21597
|
+
const onRetry = retryReporter(output, mode);
|
|
21598
|
+
return sleep === undefined ? { onRetry } : { onRetry, sleep };
|
|
21599
|
+
}
|
|
21600
|
+
function openProjectRunner(gh, config, seams = {}) {
|
|
21601
|
+
if (OPENED.has(gh))
|
|
21602
|
+
return gh;
|
|
21603
|
+
const onRetry = seams.onRetry ?? activeRetryReport;
|
|
21604
|
+
const base = { retries: config.boardProjectRetries, retryWaitSeconds: config.boardProjectRetryWaitSeconds, onRetry };
|
|
21605
|
+
const opened = retryingGhRunner(gh, seams.sleep === undefined ? base : { ...base, sleep: seams.sleep });
|
|
21606
|
+
if (opened !== gh)
|
|
21607
|
+
OPENED.add(opened);
|
|
21608
|
+
return opened;
|
|
21609
|
+
}
|
|
21610
|
+
var RETRY_EVENT = "retry", OPENED, activeRetryReport = (notice) => {
|
|
21611
|
+
retryReporter(activeOutput(), activeOutputMode())(notice);
|
|
21612
|
+
};
|
|
21613
|
+
var init_project_runner = __esm(() => {
|
|
21614
|
+
init_active();
|
|
21615
|
+
init_retry();
|
|
21616
|
+
OPENED = new WeakSet;
|
|
21617
|
+
});
|
|
21618
|
+
|
|
21411
21619
|
// src/board/project/options.ts
|
|
21412
21620
|
var STAGE_OPTIONS, HORIZON_OPTIONS;
|
|
21413
21621
|
var init_options = __esm(() => {
|
|
@@ -21471,7 +21679,7 @@ function matchProjectFields(project) {
|
|
|
21471
21679
|
mismatched: read.filter((entry) => ("problem" in entry))
|
|
21472
21680
|
};
|
|
21473
21681
|
}
|
|
21474
|
-
var PROJECT_PAGE_SIZE = 100,
|
|
21682
|
+
var PROJECT_PAGE_SIZE = 100, PROJECT_PORT_PREFIX = "board project", FIELD_DATA_TYPES, PROJECT_FIELDS, ProjectPortError;
|
|
21475
21683
|
var init_port = __esm(() => {
|
|
21476
21684
|
init_options();
|
|
21477
21685
|
FIELD_DATA_TYPES = Object.freeze({
|
|
@@ -21515,6 +21723,9 @@ function notFoundWarning(ref) {
|
|
|
21515
21723
|
function skippedFieldWarning(mismatch) {
|
|
21516
21724
|
return `The project's field "${mismatch.template.name}" was skipped and the rest were written: ${mismatch.sentence} Run \`${DOCTOR_FIX}\`.`;
|
|
21517
21725
|
}
|
|
21726
|
+
function notRefreshedWarning(refusal3) {
|
|
21727
|
+
return `#${String(refusal3.number)} not refreshed: ${refusal3.reason}`;
|
|
21728
|
+
}
|
|
21518
21729
|
var PROJECT_SCOPE_FIX = "gh auth refresh -s project", BOARD_SYNC_FIX = "rafa board sync", INIT_BOARD_FIX = "rafa init --board", DOCTOR_FIX = "rafa doctor", SCOPE_REFUSAL, PROJECT_SCOPE;
|
|
21519
21730
|
var init_refresh_warnings = __esm(() => {
|
|
21520
21731
|
init_port();
|
|
@@ -21967,10 +22178,10 @@ function appendLine(body, issue4, why = "") {
|
|
|
21967
22178
|
if (lineIndicesOf(body, issue4).length > 0)
|
|
21968
22179
|
return body;
|
|
21969
22180
|
const parts = partsOf(body);
|
|
21970
|
-
const
|
|
21971
|
-
const anchorIndex =
|
|
22181
|
+
const lastLine2 = parseRoadmapBody(body).at(-1);
|
|
22182
|
+
const anchorIndex = lastLine2 === undefined ? lastTextIndex(parts) : lastLine2.lineNumber - 1;
|
|
21972
22183
|
const anchor = parts[anchorIndex];
|
|
21973
|
-
const bullet =
|
|
22184
|
+
const bullet = lastLine2 === undefined ? DEFAULT_BULLET : BULLET.exec(anchor?.text ?? "")?.[0] ?? DEFAULT_BULLET;
|
|
21974
22185
|
const trimmedWhy = why.trim();
|
|
21975
22186
|
const text2 = trimmedWhy === "" ? `${bullet}[ ] #${String(issue4)}` : `${bullet}[ ] #${String(issue4)} ${trimmedWhy}`;
|
|
21976
22187
|
if (anchor === undefined)
|
|
@@ -24570,6 +24781,10 @@ var init_fragment_tree = __esm(() => {
|
|
|
24570
24781
|
});
|
|
24571
24782
|
|
|
24572
24783
|
// src/board/project/facts-query.ts
|
|
24784
|
+
function listSelection(list, after) {
|
|
24785
|
+
const from = after === null ? "" : `, after: $${after}`;
|
|
24786
|
+
return `${list}(first: ${String(PAGE_SIZE)}${from}${LIST_ARGUMENTS[list]})` + ` { pageInfo { hasNextPage endCursor } nodes { ${LIST_NODES[list]} } }`;
|
|
24787
|
+
}
|
|
24573
24788
|
function checkNumber(number) {
|
|
24574
24789
|
if (!Number.isSafeInteger(number) || number < 1)
|
|
24575
24790
|
throw new RangeError(`not an issue number: ${String(number)}`);
|
|
@@ -24591,6 +24806,9 @@ function graphqlArgs(query, variables) {
|
|
|
24591
24806
|
function issueAlias(number) {
|
|
24592
24807
|
return `i${checkNumber(number)}`;
|
|
24593
24808
|
}
|
|
24809
|
+
function listAlias(number, list) {
|
|
24810
|
+
return `${LIST_CODES[list]}${checkNumber(number)}`;
|
|
24811
|
+
}
|
|
24594
24812
|
function pullAlias(number) {
|
|
24595
24813
|
return `p${checkNumber(number)}`;
|
|
24596
24814
|
}
|
|
@@ -24602,6 +24820,18 @@ function issuesArgs(numbers) {
|
|
|
24602
24820
|
const query = `query($owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { nameWithOwner${issues} } }` + ` fragment facts on Issue { ${ISSUE_SELECTION} } fragment pull on PullRequest { ${PULL_FIELDS} }`;
|
|
24603
24821
|
return graphqlArgs(query, []);
|
|
24604
24822
|
}
|
|
24823
|
+
function listPagesArgs(pages) {
|
|
24824
|
+
const aliases = pages.map(({ number, list }) => listAlias(number, list));
|
|
24825
|
+
const declared = aliases.map((alias) => `, $${alias}: String!`).join("");
|
|
24826
|
+
const issues = pages.map(({ number, list }, index) => {
|
|
24827
|
+
const alias = aliases[index] ?? listAlias(number, list);
|
|
24828
|
+
return ` ${alias}: issue(number: ${String(number)}) { ${listSelection(list, alias)} }`;
|
|
24829
|
+
}).join("");
|
|
24830
|
+
const usesPull = pages.some(({ list }) => list !== "labels");
|
|
24831
|
+
const fragment = usesPull ? ` fragment pull on PullRequest { ${PULL_FIELDS} }` : "";
|
|
24832
|
+
const query = `query($owner: String!, $repo: String!${declared}) { repository(owner: $owner, name: $repo) {${issues} } }${fragment}`;
|
|
24833
|
+
return graphqlArgs(query, pages.map(({ cursor }, index) => [aliases[index] ?? "", cursor]));
|
|
24834
|
+
}
|
|
24605
24835
|
function filesArgs(pages) {
|
|
24606
24836
|
const cursors = pages.map(({ number }) => `, $c${checkNumber(number)}: String`).join("");
|
|
24607
24837
|
const pulls = pages.map(({ number }) => ` ${pullAlias(number)}: pullRequest(number: ${String(number)})` + ` { files(first: ${String(PAGE_SIZE)}, after: $c${String(number)})` + " { pageInfo { hasNextPage endCursor } nodes { path changeType } } }").join("");
|
|
@@ -24621,17 +24851,25 @@ function blobsArgs(lookups) {
|
|
|
24621
24851
|
function batchesOf(items, size) {
|
|
24622
24852
|
return Array.from({ length: Math.ceil(items.length / size) }, (_, index) => items.slice(index * size, (index + 1) * size));
|
|
24623
24853
|
}
|
|
24624
|
-
var PAGE_SIZE = 100, ISSUE_BATCH = 20, PULL_BATCH = 20, FRAGMENT_BATCH = 20, PULL_FIELDS = "number state baseRefName headRefOid", ISSUE_SELECTION;
|
|
24854
|
+
var PAGE_SIZE = 100, ISSUE_BATCH = 20, LIST_BATCH = 20, PULL_BATCH = 20, FRAGMENT_BATCH = 20, PULL_FIELDS = "number state baseRefName headRefOid", ISSUE_LISTS, LIST_CODES, LIST_ARGUMENTS, LIST_NODES, ISSUE_SELECTION;
|
|
24625
24855
|
var init_facts_query = __esm(() => {
|
|
24626
|
-
|
|
24627
|
-
|
|
24628
|
-
|
|
24629
|
-
|
|
24630
|
-
|
|
24631
|
-
|
|
24632
|
-
|
|
24633
|
-
|
|
24634
|
-
|
|
24856
|
+
ISSUE_LISTS = Object.freeze(["labels", "closedByPullRequestsReferences", "timelineItems"]);
|
|
24857
|
+
LIST_CODES = Object.freeze({
|
|
24858
|
+
labels: "la",
|
|
24859
|
+
closedByPullRequestsReferences: "cb",
|
|
24860
|
+
timelineItems: "tl"
|
|
24861
|
+
});
|
|
24862
|
+
LIST_ARGUMENTS = Object.freeze({
|
|
24863
|
+
labels: "",
|
|
24864
|
+
closedByPullRequestsReferences: ", includeClosedPrs: true",
|
|
24865
|
+
timelineItems: ", itemTypes: [CROSS_REFERENCED_EVENT]"
|
|
24866
|
+
});
|
|
24867
|
+
LIST_NODES = Object.freeze({
|
|
24868
|
+
labels: "name",
|
|
24869
|
+
closedByPullRequestsReferences: "...pull",
|
|
24870
|
+
timelineItems: "... on CrossReferencedEvent { isCrossRepository source { ... on PullRequest { ...pull body } } }"
|
|
24871
|
+
});
|
|
24872
|
+
ISSUE_SELECTION = ["number state stateReason", ...ISSUE_LISTS.map((list) => listSelection(list, null))].join(" ");
|
|
24635
24873
|
});
|
|
24636
24874
|
|
|
24637
24875
|
// src/board/epic-dependents.ts
|
|
@@ -28783,6 +29021,17 @@ var init_rules = __esm(() => {
|
|
|
28783
29021
|
function refuse8(problem) {
|
|
28784
29022
|
throw new Error(`${PREFIX29}: ${problem}`);
|
|
28785
29023
|
}
|
|
29024
|
+
function reasonOf2(error) {
|
|
29025
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29026
|
+
return message.startsWith(`${PREFIX29}: `) ? message.slice(PREFIX29.length + 2) : message;
|
|
29027
|
+
}
|
|
29028
|
+
function settle2(item, read) {
|
|
29029
|
+
try {
|
|
29030
|
+
return { item, ok: true, value: read() };
|
|
29031
|
+
} catch (error) {
|
|
29032
|
+
return { item, ok: false, reason: reasonOf2(error) };
|
|
29033
|
+
}
|
|
29034
|
+
}
|
|
28786
29035
|
function readMapping3(value, where) {
|
|
28787
29036
|
if (!isMapping(value))
|
|
28788
29037
|
refuse8(`${where} is ${describeValue(value)}, expected a mapping`);
|
|
@@ -28804,12 +29053,16 @@ function readList2(value, where) {
|
|
|
28804
29053
|
refuse8(`${where} is ${describeValue(value)}, expected a list`);
|
|
28805
29054
|
return value;
|
|
28806
29055
|
}
|
|
28807
|
-
function
|
|
29056
|
+
function readPage2(value, where) {
|
|
28808
29057
|
const connection = readMapping3(value, where);
|
|
28809
29058
|
const pageInfo = readMapping3(connection["pageInfo"], `${where}.pageInfo`);
|
|
28810
|
-
|
|
28811
|
-
|
|
28812
|
-
|
|
29059
|
+
const nodes = readList2(connection["nodes"], `${where}.nodes`);
|
|
29060
|
+
const more = pageInfo["hasNextPage"];
|
|
29061
|
+
if (more === false)
|
|
29062
|
+
return { nodes, next: null };
|
|
29063
|
+
if (more !== true)
|
|
29064
|
+
refuse8(`${where}.pageInfo.hasNextPage is ${describeValue(more)}, expected true or false`);
|
|
29065
|
+
return { nodes, next: readString4(pageInfo["endCursor"], `${where}.pageInfo.endCursor`) };
|
|
28813
29066
|
}
|
|
28814
29067
|
async function readRepository(gh, args) {
|
|
28815
29068
|
const result = await gh(args);
|
|
@@ -28824,6 +29077,21 @@ async function readRepository(gh, args) {
|
|
|
28824
29077
|
const data = readMapping3(readMapping3(parsed, "the answer")["data"], "data");
|
|
28825
29078
|
return readMapping3(data["repository"], "data.repository");
|
|
28826
29079
|
}
|
|
29080
|
+
async function readEach(gh, items, how) {
|
|
29081
|
+
const read = [];
|
|
29082
|
+
for (const batch of batchesOf(items, how.size)) {
|
|
29083
|
+
let answer3;
|
|
29084
|
+
try {
|
|
29085
|
+
answer3 = await readRepository(gh, how.argsOf(batch));
|
|
29086
|
+
} catch (error) {
|
|
29087
|
+
const alone = batch.length === 1 ? batch.map((item) => ({ item, ok: false, reason: reasonOf2(error) })) : await readEach(gh, batch, { ...how, size: 1 });
|
|
29088
|
+
read.push(...alone);
|
|
29089
|
+
continue;
|
|
29090
|
+
}
|
|
29091
|
+
read.push(...batch.map((item, index) => settle2(item, () => how.readOne(answer3, item, index))));
|
|
29092
|
+
}
|
|
29093
|
+
return read;
|
|
29094
|
+
}
|
|
28827
29095
|
function readPull(value, where) {
|
|
28828
29096
|
const pull = readMapping3(value, where);
|
|
28829
29097
|
const state = pull["state"];
|
|
@@ -28853,35 +29121,100 @@ function crossReferencedPull(value, where, issue4, repository) {
|
|
|
28853
29121
|
refuse8(`${where}.source.body is ${describeValue(body)}, expected a string`);
|
|
28854
29122
|
return bodyCloses(body, issue4, repository) ? readPull(source, `${where}.source`) : null;
|
|
28855
29123
|
}
|
|
28856
|
-
function
|
|
29124
|
+
function listWhere(number, list) {
|
|
29125
|
+
return `issue #${String(number)}.${list}`;
|
|
29126
|
+
}
|
|
29127
|
+
function readIssueFirstPages(answer3, number, repository) {
|
|
28857
29128
|
const where = `issue #${String(number)}`;
|
|
28858
|
-
const issue4 = readMapping3(
|
|
29129
|
+
const issue4 = readMapping3(answer3[issueAlias(number)], where);
|
|
28859
29130
|
const state = issue4["state"];
|
|
28860
29131
|
if (state !== "OPEN" && state !== "CLOSED")
|
|
28861
29132
|
refuse8(`${where}.state is ${describeValue(state)}, expected OPEN or CLOSED`);
|
|
28862
29133
|
const reason = issue4["stateReason"];
|
|
28863
29134
|
if (reason !== null && typeof reason !== "string")
|
|
28864
29135
|
refuse8(`${where}.stateReason is ${describeValue(reason)}, expected a string or null`);
|
|
28865
|
-
const
|
|
28866
|
-
|
|
28867
|
-
|
|
29136
|
+
const pages = Object.fromEntries(ISSUE_LISTS.map((list) => [list, readPage2(issue4[list], listWhere(number, list))]));
|
|
29137
|
+
return { head: { number, state, stateReason: reason }, repository, pages };
|
|
29138
|
+
}
|
|
29139
|
+
function listKey(number, list) {
|
|
29140
|
+
return `${String(number)}:${list}`;
|
|
29141
|
+
}
|
|
29142
|
+
function readListPage(answer3, { number, list }) {
|
|
29143
|
+
return readPage2(readMapping3(answer3[listAlias(number, list)], `issue #${String(number)}`)[list], listWhere(number, list));
|
|
29144
|
+
}
|
|
29145
|
+
async function readRemainingPages(gh, firsts, refused3) {
|
|
29146
|
+
const nodes = new Map;
|
|
29147
|
+
const seen = new Map;
|
|
29148
|
+
let pending = firsts.flatMap(({ head: { number }, pages }) => ISSUE_LISTS.flatMap((list) => {
|
|
29149
|
+
const page2 = pages[list];
|
|
29150
|
+
nodes.set(listKey(number, list), [...page2.nodes]);
|
|
29151
|
+
seen.set(listKey(number, list), new Set(page2.next === null ? [] : [page2.next]));
|
|
29152
|
+
return page2.next === null ? [] : [{ number, list, cursor: page2.next }];
|
|
29153
|
+
}));
|
|
29154
|
+
while (pending.length > 0) {
|
|
29155
|
+
const next = [];
|
|
29156
|
+
for (const settled of await readEach(gh, pending, LIST_PAGES)) {
|
|
29157
|
+
const { number, list } = settled.item;
|
|
29158
|
+
if (refused3.has(number))
|
|
29159
|
+
continue;
|
|
29160
|
+
if (!settled.ok) {
|
|
29161
|
+
refused3.set(number, settled.reason);
|
|
29162
|
+
continue;
|
|
29163
|
+
}
|
|
29164
|
+
nodes.get(listKey(number, list))?.push(...settled.value.nodes);
|
|
29165
|
+
const cursor = settled.value.next;
|
|
29166
|
+
if (cursor === null)
|
|
29167
|
+
continue;
|
|
29168
|
+
const cursors = seen.get(listKey(number, list));
|
|
29169
|
+
if (cursors?.has(cursor) === true) {
|
|
29170
|
+
refused3.set(number, `${listWhere(number, list)} answered the cursor ${JSON.stringify(cursor)} a second time, so its next page would repeat one read before`);
|
|
29171
|
+
continue;
|
|
29172
|
+
}
|
|
29173
|
+
cursors?.add(cursor);
|
|
29174
|
+
next.push({ number, list, cursor });
|
|
29175
|
+
}
|
|
29176
|
+
pending = next.filter(({ number }) => !refused3.has(number));
|
|
29177
|
+
}
|
|
29178
|
+
return nodes;
|
|
29179
|
+
}
|
|
29180
|
+
function readIssue(head, lists, repository) {
|
|
29181
|
+
const where = `issue #${String(head.number)}`;
|
|
29182
|
+
const labels = lists.labels.map((label, index) => readString4(readMapping3(label, `${where}.labels[${String(index)}]`)["name"], `${where}.labels[${String(index)}].name`));
|
|
29183
|
+
const linked = lists.closedByPullRequestsReferences.map((pull, index) => readPull(pull, `${where}.closedByPullRequestsReferences[${String(index)}]`));
|
|
29184
|
+
const mentioned = lists.timelineItems.map((event, index) => crossReferencedPull(event, `${where}.timelineItems[${String(index)}]`, head.number, repository));
|
|
28868
29185
|
const pulls = new Map([...linked, ...mentioned].flatMap((pull) => pull === null ? [] : [[pull.number, pull]]));
|
|
28869
29186
|
return {
|
|
28870
|
-
|
|
28871
|
-
state,
|
|
28872
|
-
stateReason: reason,
|
|
29187
|
+
...head,
|
|
28873
29188
|
labels,
|
|
28874
29189
|
pulls: [...pulls.values()].sort((left, right) => left.number - right.number)
|
|
28875
29190
|
};
|
|
28876
29191
|
}
|
|
28877
|
-
|
|
28878
|
-
|
|
28879
|
-
|
|
28880
|
-
|
|
28881
|
-
|
|
28882
|
-
|
|
29192
|
+
function readFirstPagesOf(answer3, number) {
|
|
29193
|
+
return readIssueFirstPages(answer3, number, readString4(answer3["nameWithOwner"], "data.repository.nameWithOwner"));
|
|
29194
|
+
}
|
|
29195
|
+
async function readIssues(gh, numbers, refused3, onRead) {
|
|
29196
|
+
const settledFirsts = [];
|
|
29197
|
+
for (const batch of batchesOf(numbers, ISSUES.size)) {
|
|
29198
|
+
settledFirsts.push(...await readEach(gh, batch, ISSUES));
|
|
29199
|
+
onRead(settledFirsts.length);
|
|
28883
29200
|
}
|
|
28884
|
-
|
|
29201
|
+
const firsts = settledFirsts.flatMap((settled) => {
|
|
29202
|
+
if (settled.ok)
|
|
29203
|
+
return [settled.value];
|
|
29204
|
+
refused3.set(settled.item, settled.reason);
|
|
29205
|
+
return [];
|
|
29206
|
+
});
|
|
29207
|
+
const nodes = await readRemainingPages(gh, firsts, refused3);
|
|
29208
|
+
return firsts.flatMap(({ head, repository }) => {
|
|
29209
|
+
if (refused3.has(head.number))
|
|
29210
|
+
return [];
|
|
29211
|
+
const lists = Object.fromEntries(ISSUE_LISTS.map((list) => [list, nodes.get(listKey(head.number, list)) ?? []]));
|
|
29212
|
+
const issue4 = settle2(head.number, () => readIssue(head, lists, repository));
|
|
29213
|
+
if (issue4.ok)
|
|
29214
|
+
return [issue4.value];
|
|
29215
|
+
refused3.set(head.number, issue4.reason);
|
|
29216
|
+
return [];
|
|
29217
|
+
});
|
|
28885
29218
|
}
|
|
28886
29219
|
function readFilesPage(value, where, prefix) {
|
|
28887
29220
|
const files = readMapping3(readMapping3(value, where)["files"], `${where}.files`);
|
|
@@ -28898,40 +29231,39 @@ function readFilesPage(value, where, prefix) {
|
|
|
28898
29231
|
next: pageInfo["hasNextPage"] === true ? readString4(pageInfo["endCursor"], `${where}.files.pageInfo.endCursor`) : null
|
|
28899
29232
|
};
|
|
28900
29233
|
}
|
|
28901
|
-
async function readAddedFragments(gh, numbers, prefix) {
|
|
29234
|
+
async function readAddedFragments(gh, numbers, prefix, failed2) {
|
|
28902
29235
|
const added = new Map(numbers.map((number) => [number, []]));
|
|
29236
|
+
const how = {
|
|
29237
|
+
size: PULL_BATCH,
|
|
29238
|
+
argsOf: filesArgs,
|
|
29239
|
+
readOne: (answer3, { number }) => readFilesPage(answer3[pullAlias(number)], `pull request #${String(number)}`, prefix)
|
|
29240
|
+
};
|
|
28903
29241
|
let pending = numbers.map((number) => ({ number, cursor: null }));
|
|
28904
29242
|
while (pending.length > 0) {
|
|
28905
29243
|
const next = [];
|
|
28906
|
-
for (const
|
|
28907
|
-
const
|
|
28908
|
-
|
|
28909
|
-
|
|
28910
|
-
|
|
28911
|
-
if (page2.next !== null)
|
|
28912
|
-
next.push({ number, cursor: page2.next });
|
|
29244
|
+
for (const settled of await readEach(gh, pending, how)) {
|
|
29245
|
+
const { number } = settled.item;
|
|
29246
|
+
if (!settled.ok) {
|
|
29247
|
+
failed2.set(number, settled.reason);
|
|
29248
|
+
continue;
|
|
28913
29249
|
}
|
|
29250
|
+
added.get(number)?.push(...settled.value.paths);
|
|
29251
|
+
if (settled.value.next !== null)
|
|
29252
|
+
next.push({ number, cursor: settled.value.next });
|
|
28914
29253
|
}
|
|
28915
29254
|
pending = next;
|
|
28916
29255
|
}
|
|
28917
29256
|
return added;
|
|
28918
29257
|
}
|
|
28919
|
-
|
|
28920
|
-
const
|
|
28921
|
-
|
|
28922
|
-
|
|
28923
|
-
|
|
28924
|
-
|
|
28925
|
-
|
|
28926
|
-
|
|
28927
|
-
|
|
28928
|
-
const text2 = headBlob === null ? null : readMapping3(headBlob, `${path3} at the head`)["text"];
|
|
28929
|
-
if (text2 !== null && typeof text2 !== "string")
|
|
28930
|
-
refuse8(`${path3} at the head has text ${describeValue(text2)}, expected a string`);
|
|
28931
|
-
return { text: text2, onBase: answer3[base] !== null };
|
|
28932
|
-
}));
|
|
28933
|
-
}
|
|
28934
|
-
return read;
|
|
29258
|
+
function readBlobsOf(answer3, { path: path3 }, index) {
|
|
29259
|
+
const { head, base } = blobAliases(index);
|
|
29260
|
+
if (!(head in answer3) || !(base in answer3))
|
|
29261
|
+
refuse8(`the blob read answered no ${head} or ${base} for ${path3}`);
|
|
29262
|
+
const headBlob = answer3[head];
|
|
29263
|
+
const text2 = headBlob === null ? null : readMapping3(headBlob, `${path3} at the head`)["text"];
|
|
29264
|
+
if (text2 !== null && typeof text2 !== "string")
|
|
29265
|
+
refuse8(`${path3} at the head has text ${describeValue(text2)}, expected a string`);
|
|
29266
|
+
return { text: text2, onBase: answer3[base] !== null };
|
|
28935
29267
|
}
|
|
28936
29268
|
function fragmentOf(path3, blobs) {
|
|
28937
29269
|
if (blobs.text === null) {
|
|
@@ -28946,22 +29278,47 @@ function decidingFragment(fragments) {
|
|
|
28946
29278
|
function blobKey(pull, path3) {
|
|
28947
29279
|
return `${String(pull)}:${path3}`;
|
|
28948
29280
|
}
|
|
29281
|
+
async function readFragments(gh, pulls, prefix, failed2) {
|
|
29282
|
+
const added = await readAddedFragments(gh, pulls.map(({ number }) => number), prefix, failed2);
|
|
29283
|
+
const lookups = pulls.filter(({ number }) => !failed2.has(number)).flatMap((pull) => (added.get(pull.number) ?? []).map((path3) => ({ pull: pull.number, path: path3, headRefOid: pull.headRefOid, baseRefName: pull.baseRefName })));
|
|
29284
|
+
const fragments = new Map((await readEach(gh, lookups, BLOBS)).flatMap((settled) => {
|
|
29285
|
+
if (settled.ok)
|
|
29286
|
+
return [[blobKey(settled.item.pull, settled.item.path), fragmentOf(settled.item.path, settled.value)]];
|
|
29287
|
+
failed2.set(settled.item.pull, settled.reason);
|
|
29288
|
+
return [];
|
|
29289
|
+
}));
|
|
29290
|
+
return { added, fragments };
|
|
29291
|
+
}
|
|
28949
29292
|
async function readIssueFacts(options, numbers) {
|
|
28950
29293
|
const { gh } = options;
|
|
28951
|
-
const
|
|
28952
|
-
const
|
|
29294
|
+
const asked = [...new Set(numbers)];
|
|
29295
|
+
const refused3 = new Map;
|
|
29296
|
+
const failed2 = new Map;
|
|
29297
|
+
const issues = await readIssues(gh, asked, refused3, options.onRead ?? (() => {
|
|
29298
|
+
return;
|
|
29299
|
+
}));
|
|
28953
29300
|
const pulls = [...new Map(issues.flatMap(({ pulls: read }) => read.map((pull) => [pull.number, pull]))).values()];
|
|
28954
|
-
const added = await
|
|
28955
|
-
const lookups = pulls.flatMap((pull) => (added.get(pull.number) ?? []).map((path3) => ({ pull: pull.number, path: path3, headRefOid: pull.headRefOid, baseRefName: pull.baseRefName })));
|
|
28956
|
-
const blobs = await readBlobs(gh, lookups);
|
|
28957
|
-
const fragments = new Map(lookups.map(({ pull, path: path3 }, index) => [blobKey(pull, path3), fragmentOf(path3, blobs[index] ?? { text: null, onBase: false })]));
|
|
29301
|
+
const { added, fragments } = await readFragments(gh, pulls, directoryPrefix(options.fragments), failed2);
|
|
28958
29302
|
const factsOf = (pull) => {
|
|
28959
29303
|
const own = [...added.get(pull.number) ?? []].sort().flatMap((path3) => fragments.get(blobKey(pull.number, path3)) ?? []);
|
|
28960
29304
|
return { number: pull.number, state: pull.state, baseRefName: pull.baseRefName, fragments: own, fragment: decidingFragment(own) };
|
|
28961
29305
|
};
|
|
28962
|
-
|
|
29306
|
+
const facts = new Map(issues.flatMap(({ pulls: read, ...issue4 }) => {
|
|
29307
|
+
const unread3 = read.find(({ number }) => failed2.has(number));
|
|
29308
|
+
if (unread3 === undefined)
|
|
29309
|
+
return [[issue4.number, { ...issue4, pullRequests: read.map(factsOf) }]];
|
|
29310
|
+
refused3.set(issue4.number, `pull request #${String(unread3.number)} could not be read: ${failed2.get(unread3.number) ?? ""}`);
|
|
29311
|
+
return [];
|
|
29312
|
+
}));
|
|
29313
|
+
return {
|
|
29314
|
+
facts,
|
|
29315
|
+
refused: asked.flatMap((number) => {
|
|
29316
|
+
const reason = refused3.get(number);
|
|
29317
|
+
return reason === undefined ? [] : [{ number, reason }];
|
|
29318
|
+
})
|
|
29319
|
+
};
|
|
28963
29320
|
}
|
|
28964
|
-
var UNREAD_LEVEL = "patch", PREFIX29 = "board project facts", ADDED = "ADDED", CLOSING_REFERENCE;
|
|
29321
|
+
var UNREAD_LEVEL = "patch", PREFIX29 = "board project facts", ADDED = "ADDED", CLOSING_REFERENCE, LIST_PAGES, ISSUES, BLOBS;
|
|
28965
29322
|
var init_facts = __esm(() => {
|
|
28966
29323
|
init_config_sections();
|
|
28967
29324
|
init_fragment_tree();
|
|
@@ -28970,6 +29327,9 @@ var init_facts = __esm(() => {
|
|
|
28970
29327
|
init_rules();
|
|
28971
29328
|
init_facts_query();
|
|
28972
29329
|
CLOSING_REFERENCE = /\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?):?\s+(?:([\w.-]+\/[\w.-]+))?#(\d+)\b/giu;
|
|
29330
|
+
LIST_PAGES = { size: LIST_BATCH, argsOf: listPagesArgs, readOne: readListPage };
|
|
29331
|
+
ISSUES = { size: ISSUE_BATCH, argsOf: issuesArgs, readOne: readFirstPagesOf };
|
|
29332
|
+
BLOBS = { size: FRAGMENT_BATCH, argsOf: blobsArgs, readOne: readBlobsOf };
|
|
28973
29333
|
});
|
|
28974
29334
|
|
|
28975
29335
|
// src/board/project/gh.ts
|
|
@@ -29002,7 +29362,7 @@ function readList3(value, where) {
|
|
|
29002
29362
|
refuse9(`${where} is ${describeValue(value)}, expected a list`);
|
|
29003
29363
|
return value;
|
|
29004
29364
|
}
|
|
29005
|
-
function
|
|
29365
|
+
function readOnePage(value, where) {
|
|
29006
29366
|
const connection = readMapping4(value, where);
|
|
29007
29367
|
if (readMapping4(connection["pageInfo"], `${where}.pageInfo`)["hasNextPage"] !== false) {
|
|
29008
29368
|
refuse9(`${where} holds more than ${String(PROJECT_PAGE_SIZE)} entries, one page`);
|
|
@@ -29061,7 +29421,7 @@ function readProject(owner, value, where) {
|
|
|
29061
29421
|
url: readString5(project["url"], `${where}.url`),
|
|
29062
29422
|
closed: readBoolean2(project["closed"], `${where}.closed`),
|
|
29063
29423
|
public: readBoolean2(project["public"], `${where}.public`),
|
|
29064
|
-
fields:
|
|
29424
|
+
fields: readOnePage(project["fields"], `${where}.fields`).map((field5, index) => readField(field5, `${where}.fields.nodes[${String(index)}]`))
|
|
29065
29425
|
};
|
|
29066
29426
|
}
|
|
29067
29427
|
function findArgs(ref6) {
|
|
@@ -29159,7 +29519,7 @@ function readContent(item, where) {
|
|
|
29159
29519
|
}
|
|
29160
29520
|
function readItem2(value, where) {
|
|
29161
29521
|
const item = readMapping4(value, where);
|
|
29162
|
-
const values =
|
|
29522
|
+
const values = readOnePage(item["fieldValues"], `${where}.fieldValues`).map((node, index) => readValue(node, `${where}.fieldValues.nodes[${String(index)}]`));
|
|
29163
29523
|
return {
|
|
29164
29524
|
id: readString5(item["id"], `${where}.id`),
|
|
29165
29525
|
archived: readBoolean2(item["isArchived"], `${where}.isArchived`),
|
|
@@ -29254,6 +29614,128 @@ var init_gh2 = __esm(() => {
|
|
|
29254
29614
|
NUMBERED_TYPES = Object.freeze({ ISSUE: "issue", PULL_REQUEST: "pull-request" });
|
|
29255
29615
|
});
|
|
29256
29616
|
|
|
29617
|
+
// src/board/project/progress.ts
|
|
29618
|
+
function formatElapsed(elapsedMs) {
|
|
29619
|
+
const seconds = Math.floor(Math.max(0, elapsedMs) / MS_PER_SECOND3);
|
|
29620
|
+
const hours = Math.floor(seconds / SECONDS_PER_HOUR);
|
|
29621
|
+
const minutes = Math.floor(seconds % SECONDS_PER_HOUR / SECONDS_PER_MINUTE);
|
|
29622
|
+
const rest = seconds % SECONDS_PER_MINUTE;
|
|
29623
|
+
if (hours > 0)
|
|
29624
|
+
return `${String(hours)}h ${String(minutes)}m ${String(rest)}s`;
|
|
29625
|
+
if (minutes > 0)
|
|
29626
|
+
return `${String(minutes)}m ${String(rest)}s`;
|
|
29627
|
+
return `${String(rest)}s`;
|
|
29628
|
+
}
|
|
29629
|
+
function waitLine(waitMs) {
|
|
29630
|
+
return `waiting ${String(Math.ceil(Math.max(0, waitMs) / MS_PER_SECOND3))} s for GitHub's write limit`;
|
|
29631
|
+
}
|
|
29632
|
+
function progressEvent(line, now) {
|
|
29633
|
+
return {
|
|
29634
|
+
type: "event",
|
|
29635
|
+
name: PROGRESS_EVENT,
|
|
29636
|
+
summary: line.text,
|
|
29637
|
+
data: { ...line.data },
|
|
29638
|
+
ts: now.toISOString()
|
|
29639
|
+
};
|
|
29640
|
+
}
|
|
29641
|
+
function phaseReporter(options) {
|
|
29642
|
+
const label = PROGRESS_PHASES[options.phase];
|
|
29643
|
+
const total2 = String(options.total);
|
|
29644
|
+
const gapMs = options.progressSeconds === false ? null : options.progressSeconds * MS_PER_SECOND3;
|
|
29645
|
+
let startedAt = options.now();
|
|
29646
|
+
let lastLineAt = startedAt;
|
|
29647
|
+
let doneSoFar = 0;
|
|
29648
|
+
const base = (step, done, at) => ({
|
|
29649
|
+
phase: options.phase,
|
|
29650
|
+
step,
|
|
29651
|
+
done,
|
|
29652
|
+
total: options.total,
|
|
29653
|
+
elapsedMs: at - startedAt
|
|
29654
|
+
});
|
|
29655
|
+
return {
|
|
29656
|
+
start: () => {
|
|
29657
|
+
startedAt = options.now();
|
|
29658
|
+
lastLineAt = startedAt;
|
|
29659
|
+
return { text: `${label}: ${total2}`, data: base("start", 0, startedAt) };
|
|
29660
|
+
},
|
|
29661
|
+
advance: (done) => {
|
|
29662
|
+
doneSoFar = done;
|
|
29663
|
+
if (gapMs === null)
|
|
29664
|
+
return;
|
|
29665
|
+
const at = options.now();
|
|
29666
|
+
if (at - lastLineAt < gapMs)
|
|
29667
|
+
return;
|
|
29668
|
+
lastLineAt = at;
|
|
29669
|
+
const data = base("progress", done, at);
|
|
29670
|
+
return { text: `${label}: ${String(done)}/${total2}, ${formatElapsed(data.elapsedMs)}`, data };
|
|
29671
|
+
},
|
|
29672
|
+
end: ({ done, refused: refused3 }) => {
|
|
29673
|
+
const data = { ...base("end", done, options.now()), refused: refused3 };
|
|
29674
|
+
return {
|
|
29675
|
+
text: `${label}: ${String(done)}/${total2}, ${String(refused3)} refused, ${formatElapsed(data.elapsedMs)}`,
|
|
29676
|
+
data
|
|
29677
|
+
};
|
|
29678
|
+
},
|
|
29679
|
+
wait: (waitMs) => {
|
|
29680
|
+
const data = { ...base("wait", doneSoFar, options.now()), waitMs };
|
|
29681
|
+
return { text: waitLine(waitMs), data };
|
|
29682
|
+
}
|
|
29683
|
+
};
|
|
29684
|
+
}
|
|
29685
|
+
function openPhase(feed, phase, total2) {
|
|
29686
|
+
if (feed === undefined)
|
|
29687
|
+
return SILENT_PHASE;
|
|
29688
|
+
const reporter = phaseReporter({ phase, total: total2, now: feed.now, progressSeconds: feed.progressSeconds });
|
|
29689
|
+
feed.sink(reporter.start());
|
|
29690
|
+
return {
|
|
29691
|
+
advance: (done) => {
|
|
29692
|
+
const line = reporter.advance(done);
|
|
29693
|
+
if (line !== undefined)
|
|
29694
|
+
feed.sink(line);
|
|
29695
|
+
},
|
|
29696
|
+
wait: (waitMs) => {
|
|
29697
|
+
feed.sink(reporter.wait(waitMs));
|
|
29698
|
+
},
|
|
29699
|
+
end: (result) => {
|
|
29700
|
+
feed.sink(reporter.end(result));
|
|
29701
|
+
}
|
|
29702
|
+
};
|
|
29703
|
+
}
|
|
29704
|
+
function progressSink(output, mode, stamp2 = () => new Date) {
|
|
29705
|
+
return (line) => {
|
|
29706
|
+
if (mode === "json")
|
|
29707
|
+
output.emit(progressEvent(line, stamp2()));
|
|
29708
|
+
else
|
|
29709
|
+
output.info(line.text);
|
|
29710
|
+
};
|
|
29711
|
+
}
|
|
29712
|
+
function commandProgressFeed(output, mode, progressSeconds, clocks = {}) {
|
|
29713
|
+
return {
|
|
29714
|
+
sink: progressSink(output, mode, clocks.stamp),
|
|
29715
|
+
now: clocks.now ?? (() => Date.now()),
|
|
29716
|
+
progressSeconds
|
|
29717
|
+
};
|
|
29718
|
+
}
|
|
29719
|
+
var PROGRESS_EVENT = "progress", PROGRESS_PHASES, SILENT_PHASE, MS_PER_SECOND3 = 1000, SECONDS_PER_MINUTE = 60, SECONDS_PER_HOUR = 3600;
|
|
29720
|
+
var init_progress2 = __esm(() => {
|
|
29721
|
+
PROGRESS_PHASES = Object.freeze({
|
|
29722
|
+
adds: "adding issues",
|
|
29723
|
+
facts: "reading facts",
|
|
29724
|
+
writes: "writing fields"
|
|
29725
|
+
});
|
|
29726
|
+
SILENT_PHASE = Object.freeze({
|
|
29727
|
+
advance: () => {
|
|
29728
|
+
return;
|
|
29729
|
+
},
|
|
29730
|
+
wait: () => {
|
|
29731
|
+
return;
|
|
29732
|
+
},
|
|
29733
|
+
end: () => {
|
|
29734
|
+
return;
|
|
29735
|
+
}
|
|
29736
|
+
});
|
|
29737
|
+
});
|
|
29738
|
+
|
|
29257
29739
|
// src/board/project/refresh-values.ts
|
|
29258
29740
|
function projectValuesOf(facts, board) {
|
|
29259
29741
|
return {
|
|
@@ -29359,8 +29841,16 @@ function writeBatchArgs(projectId2, batch) {
|
|
|
29359
29841
|
const query = `mutation(${declarations}) { ${parts.map((part) => part.mutation).join(" ")} }`;
|
|
29360
29842
|
return graphqlArgs2(query, [["-f", "project", projectId2], ...parts.flatMap((part) => part.fields)]);
|
|
29361
29843
|
}
|
|
29362
|
-
function
|
|
29363
|
-
|
|
29844
|
+
function requirePace(batchSize, pauseMs) {
|
|
29845
|
+
if (!Number.isSafeInteger(batchSize) || batchSize < 1) {
|
|
29846
|
+
throw new RangeError(`not a batch size of writes: ${String(batchSize)}, expected a whole number from 1`);
|
|
29847
|
+
}
|
|
29848
|
+
if (!Number.isSafeInteger(pauseMs) || pauseMs < 0) {
|
|
29849
|
+
throw new RangeError(`not a pause between write requests: ${String(pauseMs)}, expected a whole number from 0`);
|
|
29850
|
+
}
|
|
29851
|
+
}
|
|
29852
|
+
function batchesOf2(writes, batchSize) {
|
|
29853
|
+
return Array.from({ length: Math.ceil(writes.length / batchSize) }, (_, index) => writes.slice(index * batchSize, (index + 1) * batchSize));
|
|
29364
29854
|
}
|
|
29365
29855
|
function isRateLimited(stdout, stderr) {
|
|
29366
29856
|
const answer3 = parsed(stdout);
|
|
@@ -29397,21 +29887,31 @@ async function sendBatch(gh, args, size) {
|
|
|
29397
29887
|
function itemCount(writes) {
|
|
29398
29888
|
return new Set(writes.map((write) => write.itemId)).size;
|
|
29399
29889
|
}
|
|
29400
|
-
async function writeProjectFields(gh, projectId2, writes,
|
|
29401
|
-
const
|
|
29402
|
-
|
|
29890
|
+
async function writeProjectFields(gh, projectId2, writes, options) {
|
|
29891
|
+
const { batchSize, pauseMs } = options;
|
|
29892
|
+
requirePace(batchSize, pauseMs);
|
|
29893
|
+
const sleep = options.sleep ?? ((ms) => Bun.sleep(ms));
|
|
29894
|
+
const batches = batchesOf2(writes, batchSize);
|
|
29403
29895
|
const requests = batches.map((batch) => writeBatchArgs(projectId2, batch));
|
|
29896
|
+
const phase = openPhase(options.progress, "writes", writes.length);
|
|
29404
29897
|
let sent = 0;
|
|
29405
29898
|
for (const [index, batch] of batches.entries()) {
|
|
29406
|
-
if (index > 0)
|
|
29407
|
-
|
|
29899
|
+
if (index > 0) {
|
|
29900
|
+
if (pauseMs > 0)
|
|
29901
|
+
phase.wait(pauseMs);
|
|
29902
|
+
await sleep(pauseMs);
|
|
29903
|
+
}
|
|
29408
29904
|
const outcome2 = await sendBatch(gh, requests[index] ?? [], batch.length);
|
|
29409
29905
|
if (outcome2.rateLimited) {
|
|
29410
29906
|
const unwritten = [...batch.filter((_, at) => !outcome2.landed.has(at)), ...batches.slice(index + 1).flat()];
|
|
29411
|
-
|
|
29907
|
+
const written4 = sent + outcome2.landed.size;
|
|
29908
|
+
phase.end({ done: written4, refused: writes.length - written4 });
|
|
29909
|
+
return { written: written4, notUpdated: itemCount(unwritten), rateLimited: true, detail: outcome2.detail };
|
|
29412
29910
|
}
|
|
29413
29911
|
sent += batch.length;
|
|
29912
|
+
phase.advance(sent);
|
|
29414
29913
|
}
|
|
29914
|
+
phase.end({ done: sent, refused: 0 });
|
|
29415
29915
|
return { written: sent, notUpdated: 0, rateLimited: false, detail: "" };
|
|
29416
29916
|
}
|
|
29417
29917
|
var RATE_LIMITED = "RATE_LIMITED", RATE_LIMIT_TEXT, MUTATIONS, VALUE_INPUTS;
|
|
@@ -29419,6 +29919,7 @@ var init_writes = __esm(() => {
|
|
|
29419
29919
|
init_config_sections();
|
|
29420
29920
|
init_gh2();
|
|
29421
29921
|
init_port();
|
|
29922
|
+
init_progress2();
|
|
29422
29923
|
RATE_LIMIT_TEXT = /\brate limit/iu;
|
|
29423
29924
|
MUTATIONS = Object.freeze({ set: "updateProjectV2ItemFieldValue", clear: "clearProjectV2ItemFieldValue" });
|
|
29424
29925
|
VALUE_INPUTS = Object.freeze({
|
|
@@ -29429,6 +29930,15 @@ var init_writes = __esm(() => {
|
|
|
29429
29930
|
});
|
|
29430
29931
|
|
|
29431
29932
|
// src/board/project/refresh.ts
|
|
29933
|
+
function writesOptionsOf(options) {
|
|
29934
|
+
const { sleep, progress } = options;
|
|
29935
|
+
return {
|
|
29936
|
+
batchSize: options.config.boardProjectWriteBatchSize,
|
|
29937
|
+
pauseMs: options.config.boardProjectWritePauseMs,
|
|
29938
|
+
...sleep === undefined ? {} : { sleep },
|
|
29939
|
+
...progress === undefined ? {} : { progress }
|
|
29940
|
+
};
|
|
29941
|
+
}
|
|
29432
29942
|
function issueNumbers2(issues) {
|
|
29433
29943
|
const bad = issues.find((issue4) => !Number.isSafeInteger(issue4) || issue4 < 1);
|
|
29434
29944
|
if (bad !== undefined)
|
|
@@ -29476,16 +29986,17 @@ async function readRefreshBoard(config, gh, repository) {
|
|
|
29476
29986
|
async function changesFor(options, repository, project, present, read) {
|
|
29477
29987
|
const { config, gh } = options;
|
|
29478
29988
|
const numbers = [...present.keys()];
|
|
29479
|
-
const
|
|
29989
|
+
const phase = openPhase(options.progress, "facts", numbers.length);
|
|
29990
|
+
const { facts, refused: refused3 } = await readIssueFacts({ gh, fragments: config.releaseFragments, onRead: phase.advance }, numbers);
|
|
29991
|
+
phase.end({ done: facts.size, refused: refused3.length });
|
|
29480
29992
|
const board = read ?? await readRefreshBoard(config, gh, repository);
|
|
29481
29993
|
const { matched } = matchProjectFields(project);
|
|
29482
|
-
|
|
29483
|
-
const
|
|
29994
|
+
const changes = numbers.flatMap((issue4) => {
|
|
29995
|
+
const issueFacts = facts.get(issue4);
|
|
29484
29996
|
const item = present.get(issue4);
|
|
29485
|
-
|
|
29486
|
-
throw new Error(`${PREFIX30}: no facts were read for #${String(issue4)}`);
|
|
29487
|
-
return projectChangesOf(issue4, item, projectValuesOf(read2, board), matched);
|
|
29997
|
+
return issueFacts === undefined || item === undefined ? [] : projectChangesOf(issue4, item, projectValuesOf(issueFacts, board), matched);
|
|
29488
29998
|
});
|
|
29999
|
+
return { changes, refused: refused3 };
|
|
29489
30000
|
}
|
|
29490
30001
|
function rankShifted(issue4, item, rankField, rank) {
|
|
29491
30002
|
const values = { stage: null, horizon: null, rank, blockedBy: null, progress: null };
|
|
@@ -29517,13 +30028,14 @@ async function refreshOn(options, repository, ref6, asked, widening) {
|
|
|
29517
30028
|
}));
|
|
29518
30029
|
const missing2 = numbers.filter((issue4) => !present.has(issue4));
|
|
29519
30030
|
const { mismatched: skipped2 } = matchProjectFields(project);
|
|
29520
|
-
const changes = present.size === 0 ?
|
|
29521
|
-
const writes = changes.length === 0 || options.dryRun === true ? NOTHING_WRITTEN : await writeProjectFields(gh, project.id, changes.map(({ write }) => write), options
|
|
30031
|
+
const { changes, refused: refused3 } = present.size === 0 ? NOTHING_READ : await changesFor(options, repository, project, present, board);
|
|
30032
|
+
const writes = changes.length === 0 || options.dryRun === true ? NOTHING_WRITTEN : await writeProjectFields(gh, project.id, changes.map(({ write }) => write), writesOptionsOf(options));
|
|
29522
30033
|
const warnings = [
|
|
30034
|
+
...refused3.map(notRefreshedWarning),
|
|
29523
30035
|
...writes.rateLimited ? [rateLimitWarning(writes.notUpdated)] : [],
|
|
29524
30036
|
...skipped2.map(skippedFieldWarning)
|
|
29525
30037
|
];
|
|
29526
|
-
return { kind: "refreshed", project: ref6, changes, writes, missing: missing2, skipped: skipped2, warnings };
|
|
30038
|
+
return { kind: "refreshed", project: ref6, changes, writes, missing: missing2, skipped: skipped2, refused: refused3, warnings };
|
|
29527
30039
|
}
|
|
29528
30040
|
async function refreshProjectItems(options, issues, widening = {}) {
|
|
29529
30041
|
const { config, gh } = options;
|
|
@@ -29549,7 +30061,7 @@ async function refreshProjectItems(options, issues, widening = {}) {
|
|
|
29549
30061
|
throw error;
|
|
29550
30062
|
}
|
|
29551
30063
|
}
|
|
29552
|
-
var PREFIX30 = "board project refresh", NOTHING_WRITTEN, NO_UNLABELLED_SEARCH = () => Promise.resolve([]);
|
|
30064
|
+
var PREFIX30 = "board project refresh", NOTHING_READ, NOTHING_WRITTEN, NO_UNLABELLED_SEARCH = () => Promise.resolve([]);
|
|
29553
30065
|
var init_refresh = __esm(() => {
|
|
29554
30066
|
init_move_native();
|
|
29555
30067
|
init_boards();
|
|
@@ -29560,16 +30072,24 @@ var init_refresh = __esm(() => {
|
|
|
29560
30072
|
init_facts();
|
|
29561
30073
|
init_gh2();
|
|
29562
30074
|
init_port();
|
|
30075
|
+
init_progress2();
|
|
29563
30076
|
init_refresh_values();
|
|
29564
30077
|
init_refresh_warnings();
|
|
29565
30078
|
init_rules();
|
|
29566
30079
|
init_writes();
|
|
30080
|
+
NOTHING_READ = Object.freeze({ changes: [], refused: [] });
|
|
29567
30081
|
NOTHING_WRITTEN = Object.freeze({ written: 0, notUpdated: 0, rateLimited: false, detail: "" });
|
|
29568
30082
|
});
|
|
29569
30083
|
|
|
29570
30084
|
// src/board/project/issue-board-refresh.ts
|
|
29571
30085
|
function refreshIssueItems(options, issues, widening = {}) {
|
|
29572
|
-
return refreshProjectItems(options, issues, widening);
|
|
30086
|
+
return refreshProjectItems(retrying(options), issues, widening);
|
|
30087
|
+
}
|
|
30088
|
+
function retrying(options) {
|
|
30089
|
+
if (options.config.boardProjectNumber === null)
|
|
30090
|
+
return options;
|
|
30091
|
+
const seams = options.sleep === undefined ? {} : { sleep: options.sleep };
|
|
30092
|
+
return { ...options, gh: openProjectRunner(options.gh, options.config, seams) };
|
|
29573
30093
|
}
|
|
29574
30094
|
function refreshFailedWarning(issue4, error) {
|
|
29575
30095
|
return `The project was not updated for #${String(issue4)}: ${messageOf(error)}. Run \`${BOARD_SYNC_FIX}\` to catch up.`;
|
|
@@ -29609,7 +30129,7 @@ function createRefreshingGhIssueBoard(options) {
|
|
|
29609
30129
|
});
|
|
29610
30130
|
const refreshOptions = sleep === undefined ? { config, gh } : { config, gh, sleep };
|
|
29611
30131
|
return withProjectRefresh(createGhIssueBoard({ gh }), {
|
|
29612
|
-
refresh: (issues) => refreshProjectItems(refreshOptions, issues),
|
|
30132
|
+
refresh: (issues) => refreshProjectItems(retrying(refreshOptions), issues),
|
|
29613
30133
|
warn
|
|
29614
30134
|
});
|
|
29615
30135
|
}
|
|
@@ -29617,6 +30137,7 @@ var init_issue_board_refresh = __esm(() => {
|
|
|
29617
30137
|
init_active();
|
|
29618
30138
|
init_config_sections();
|
|
29619
30139
|
init_issue_board();
|
|
30140
|
+
init_project_runner();
|
|
29620
30141
|
init_refresh_warnings();
|
|
29621
30142
|
init_refresh();
|
|
29622
30143
|
});
|
|
@@ -31941,8 +32462,17 @@ async function addIssues(options, ref6, issues) {
|
|
|
31941
32462
|
const project = await port.find(ref6);
|
|
31942
32463
|
if (project === null)
|
|
31943
32464
|
return null;
|
|
31944
|
-
|
|
31945
|
-
|
|
32465
|
+
const phase = openPhase(options.progress, "adds", issues.length);
|
|
32466
|
+
let added = 0;
|
|
32467
|
+
try {
|
|
32468
|
+
for (const number of issues) {
|
|
32469
|
+
await port.addItem(project.id, { repository, number });
|
|
32470
|
+
added += 1;
|
|
32471
|
+
phase.advance(added);
|
|
32472
|
+
}
|
|
32473
|
+
} finally {
|
|
32474
|
+
phase.end({ done: added, refused: issues.length - added });
|
|
32475
|
+
}
|
|
31946
32476
|
return issues;
|
|
31947
32477
|
}
|
|
31948
32478
|
async function addMissing(options, first, synced) {
|
|
@@ -31959,6 +32489,7 @@ async function addMissing(options, first, synced) {
|
|
|
31959
32489
|
...synced,
|
|
31960
32490
|
changes: [...first.changes, ...second.changes],
|
|
31961
32491
|
added,
|
|
32492
|
+
refused: [...first.refused, ...second.refused],
|
|
31962
32493
|
writes: addedWrites(first.writes, second.writes),
|
|
31963
32494
|
warnings: [...first.warnings, ...second.warnings.filter((line) => !first.warnings.includes(line))]
|
|
31964
32495
|
};
|
|
@@ -31979,6 +32510,7 @@ async function syncProject(options) {
|
|
|
31979
32510
|
changes: first.changes,
|
|
31980
32511
|
missing: first.missing,
|
|
31981
32512
|
added: [],
|
|
32513
|
+
refused: first.refused,
|
|
31982
32514
|
writes: first.writes,
|
|
31983
32515
|
warnings: first.warnings
|
|
31984
32516
|
});
|
|
@@ -31987,6 +32519,7 @@ var WHOLE_PROJECT;
|
|
|
31987
32519
|
var init_sync = __esm(() => {
|
|
31988
32520
|
init_move_native();
|
|
31989
32521
|
init_gh2();
|
|
32522
|
+
init_progress2();
|
|
31990
32523
|
init_refresh_warnings();
|
|
31991
32524
|
init_refresh();
|
|
31992
32525
|
WHOLE_PROJECT = Object.freeze({ everyItem: true, openIssues: true });
|
|
@@ -31999,17 +32532,21 @@ function counted4(count2, noun) {
|
|
|
31999
32532
|
function changeLine(change) {
|
|
32000
32533
|
return `#${String(change.issue)} ${change.name}: ${change.from ?? EMPTY_VALUE} \u2192 ${change.to ?? EMPTY_VALUE}`;
|
|
32001
32534
|
}
|
|
32535
|
+
function refusedPart(result) {
|
|
32536
|
+
return result.refused.length === 0 ? "" : `; ${counted4(result.refused.length, "issue")} not refreshed`;
|
|
32537
|
+
}
|
|
32002
32538
|
function closingLine(result) {
|
|
32003
32539
|
const project = `project #${String(result.project.number)}`;
|
|
32004
32540
|
const adds = result.dryRun ? result.missing : result.added;
|
|
32005
32541
|
const changes = counted4(result.changes.length, "change");
|
|
32006
32542
|
const issues = counted4(adds.length, "issue");
|
|
32543
|
+
const inStep = result.changes.length === 0 && adds.length === 0 && result.refused.length === 0;
|
|
32007
32544
|
if (result.dryRun) {
|
|
32008
|
-
return
|
|
32545
|
+
return inStep ? `Dry run on ${project}: in step, nothing to change.` : `Dry run on ${project}: ${changes} and ${issues} to add${refusedPart(result)}; nothing written.`;
|
|
32009
32546
|
}
|
|
32010
32547
|
if (result.rateLimited)
|
|
32011
32548
|
return `Stopped on ${project}: ${String(result.written)} of ${changes} written; the rate limit refused the rest.`;
|
|
32012
|
-
return
|
|
32549
|
+
return inStep ? `Synced ${project}: in step, nothing to change.` : `Synced ${project}: ${changes} written and ${issues} added${refusedPart(result)}.`;
|
|
32013
32550
|
}
|
|
32014
32551
|
function syncLines(result) {
|
|
32015
32552
|
const adds = result.dryRun ? result.missing.map((issue4) => `#${String(issue4)} is not on the project: would be added`) : result.added.map((issue4) => `#${String(issue4)} added to the project`);
|
|
@@ -32025,6 +32562,7 @@ function syncResultOf(synced) {
|
|
|
32025
32562
|
changes: synced.changes.map(plainChange),
|
|
32026
32563
|
missing: synced.missing,
|
|
32027
32564
|
added: synced.added,
|
|
32565
|
+
refused: synced.refused.map(({ number, reason }) => ({ issue: number, reason })),
|
|
32028
32566
|
written: synced.writes.written,
|
|
32029
32567
|
rateLimited: synced.writes.rateLimited,
|
|
32030
32568
|
notUpdated: synced.writes.notUpdated,
|
|
@@ -32042,9 +32580,10 @@ async function runBoardSync(context, seams) {
|
|
|
32042
32580
|
if (config.boardProjectNumber === null) {
|
|
32043
32581
|
throw new CommandExit(1, `\u274C board.project.number is not set, so there is no project to sync. Run \`${PROJECT_INIT_FIX}\` to create one.`);
|
|
32044
32582
|
}
|
|
32045
|
-
const gh = seams.gh ?? createGhRunner({ cwd: project.root });
|
|
32583
|
+
const gh = openProjectRunner(seams.gh ?? createGhRunner({ cwd: project.root }), config, commandRetrySeams(context.output, context.outputMode, seams.sleep));
|
|
32046
32584
|
const dryRun = context.flags[DRY_RUN_FLAG3] === true;
|
|
32047
|
-
const
|
|
32585
|
+
const progress = commandProgressFeed(context.output, context.outputMode, config.boardProjectProgressSeconds, seams.now === undefined ? {} : { now: seams.now });
|
|
32586
|
+
const synced = await syncProject(seams.sleep === undefined ? { config, gh, dryRun, progress } : { config, gh, dryRun, progress, sleep: seams.sleep }).catch((error) => {
|
|
32048
32587
|
throw new CommandExit(BOARD_SYNC_REFUSAL_EXIT, `\u274C Could not sync the project: ${messageOf(error)}`);
|
|
32049
32588
|
});
|
|
32050
32589
|
if (synced.kind !== "synced") {
|
|
@@ -32074,7 +32613,7 @@ function createBoardSyncCommand(seams = {}) {
|
|
|
32074
32613
|
subject: "board",
|
|
32075
32614
|
action: "sync",
|
|
32076
32615
|
summary: "bring the repository's GitHub project in step with its issues",
|
|
32077
|
-
description: "Refreshes every item of this repository on the GitHub project board.project.number names, writing" + " only the Stage, Horizon, Rank, Blocked by and Progress values that differ from what rafa reads of the" + " issues, then adds every open issue missing from the project and fills its fields. It repairs what changed" + " outside rafa: a label edited in the web UI, an issue closed by hand, the Roadmap issue's order edited in" + " its body. Prints one line per change and per issue added, then a closing count. With `--dry-run` it" + " prints the same lines and writes nothing. With `--output=json` the changes are the data of the terminal" + " result event. Refused with exit code 1 when board.project.number is unset, and with exit code 2 when the
|
|
32616
|
+
description: "Refreshes every item of this repository on the GitHub project board.project.number names, writing" + " only the Stage, Horizon, Rank, Blocked by and Progress values that differ from what rafa reads of the" + " issues, then adds every open issue missing from the project and fills its fields. It repairs what changed" + " outside rafa: a label edited in the web UI, an issue closed by hand, the Roadmap issue's order edited in" + " its body. Prints one line per change and per issue added, then a closing count. With `--dry-run` it" + " prints the same lines and writes nothing. With `--output=json` the changes are the data of the terminal" + " result event. An issue whose facts could not be read is named in a warning, `#<n> not refreshed:" + " <reason>`, while the others are synced; the exit code stays 0 and the next run reads it again. Adding" + " the issues, reading their facts and writing their fields each print a start line with the total, a" + " progress line at most every board.project.progressSeconds, as `reading facts: 146/283, 6m 40s`, and an" + " end line; with `--output=json` each is a `progress` event. Refused" + " with exit code 1 when board.project.number is unset, and with exit code 2 when the token lacks the" + " project scope, the number names no project, or the rate limit stopped the writes.",
|
|
32078
32617
|
args: [],
|
|
32079
32618
|
flags: [
|
|
32080
32619
|
{
|
|
@@ -32107,6 +32646,8 @@ function createBoardSyncCommand(seams = {}) {
|
|
|
32107
32646
|
var USAGE10 = "rafa board sync [--dry-run]", DRY_RUN_FLAG3 = "dry-run", BOARD_SYNC_REFUSAL_EXIT = 2, PROJECT_INIT_FIX = "rafa init --board --project", EMPTY_VALUE = "(empty)", sync_default;
|
|
32108
32647
|
var init_sync2 = __esm(() => {
|
|
32109
32648
|
init_github();
|
|
32649
|
+
init_progress2();
|
|
32650
|
+
init_project_runner();
|
|
32110
32651
|
init_refresh_warnings();
|
|
32111
32652
|
init_sync();
|
|
32112
32653
|
init_command();
|
|
@@ -36398,7 +36939,7 @@ function settleWhy(waiting) {
|
|
|
36398
36939
|
return `${count2} ${wait} on ${waiting.base} and ${fold} into ${waiting.version}`;
|
|
36399
36940
|
}
|
|
36400
36941
|
function readFollowUps(reading2) {
|
|
36401
|
-
const { liveLoopBranches, rafaCheckout, runtimeInstalled, settle:
|
|
36942
|
+
const { liveLoopBranches, rafaCheckout, runtimeInstalled, settle: settle3, version: version2 } = reading2;
|
|
36402
36943
|
const followUps = [];
|
|
36403
36944
|
if (version2 !== null && rafaCheckout && !runtimeInstalled) {
|
|
36404
36945
|
followUps.push({
|
|
@@ -36407,8 +36948,8 @@ function readFollowUps(reading2) {
|
|
|
36407
36948
|
why: selfUpdateWhy(version2, liveLoopBranches)
|
|
36408
36949
|
});
|
|
36409
36950
|
}
|
|
36410
|
-
if (
|
|
36411
|
-
followUps.push({ id: "release-settle", command: RELEASE_SETTLE_COMMAND, why: settleWhy(
|
|
36951
|
+
if (settle3 !== null) {
|
|
36952
|
+
followUps.push({ id: "release-settle", command: RELEASE_SETTLE_COMMAND, why: settleWhy(settle3) });
|
|
36412
36953
|
}
|
|
36413
36954
|
return Object.freeze(followUps.map((followUp) => Object.freeze(followUp)));
|
|
36414
36955
|
}
|
|
@@ -37296,7 +37837,7 @@ function parseBranchLine(line) {
|
|
|
37296
37837
|
if (unix === "" || !Number.isInteger(seconds)) {
|
|
37297
37838
|
return `git for-each-ref wrote no commit date for ${name2}: ${JSON.stringify(unix)}`;
|
|
37298
37839
|
}
|
|
37299
|
-
const lastCommit = new Date(seconds *
|
|
37840
|
+
const lastCommit = new Date(seconds * MS_PER_SECOND4);
|
|
37300
37841
|
const current = head === "*";
|
|
37301
37842
|
if (upstreamField === "") {
|
|
37302
37843
|
return { current, branch: { name: name2, upstream: null, gone: false, ahead: null, lastCommit } };
|
|
@@ -37313,7 +37854,7 @@ function aheadOf(track) {
|
|
|
37313
37854
|
}
|
|
37314
37855
|
return Number(count2);
|
|
37315
37856
|
}
|
|
37316
|
-
var BRANCH_FORMAT, REMOTE3 = "origin", FIELD_COUNT = 5,
|
|
37857
|
+
var BRANCH_FORMAT, REMOTE3 = "origin", FIELD_COUNT = 5, MS_PER_SECOND4 = 1000, GONE_TRACK = "gone";
|
|
37317
37858
|
var init_branches = __esm(() => {
|
|
37318
37859
|
init_sources();
|
|
37319
37860
|
init_git();
|
|
@@ -44773,41 +45314,76 @@ async function missingIssues(options, repository, project) {
|
|
|
44773
45314
|
const held = heldIssues(await createGhProjectPort(gh).items(project.id), repository);
|
|
44774
45315
|
const ranked = board.closed.filter((issue4) => rankOf(board.ranks, issue4) !== null);
|
|
44775
45316
|
const unread4 = board.closed.filter((issue4) => rankOf(board.ranks, issue4) === null && !held.has(issue4));
|
|
44776
|
-
const facts = await readIssueFacts({ gh, fragments: config.releaseFragments }, unread4);
|
|
45317
|
+
const { facts } = await readIssueFacts({ gh, fragments: config.releaseFragments }, unread4);
|
|
44777
45318
|
const inReview = unread4.filter((issue4) => {
|
|
44778
45319
|
const read = facts.get(issue4);
|
|
44779
45320
|
return read !== undefined && stageOf(read) === "In review";
|
|
44780
45321
|
});
|
|
44781
|
-
|
|
45322
|
+
const missing2 = [...new Set([...board.open, ...ranked, ...inReview])].filter((issue4) => !held.has(issue4)).sort((a, b) => a - b);
|
|
45323
|
+
return { held, missing: missing2 };
|
|
44782
45324
|
}
|
|
44783
45325
|
async function itemsStep(options, repository, project) {
|
|
44784
45326
|
const sleep = options.sleep ?? ((ms) => Bun.sleep(ms));
|
|
44785
|
-
let
|
|
45327
|
+
let wanted;
|
|
44786
45328
|
try {
|
|
44787
|
-
|
|
45329
|
+
wanted = await missingIssues(options, repository, project);
|
|
44788
45330
|
} catch (error) {
|
|
44789
|
-
return partOf2("items", ITEMS_PART, "refused", `the issues to add could not be read: ${refusalOf2(error)}`);
|
|
45331
|
+
return { part: partOf2("items", ITEMS_PART, "refused", `the issues to add could not be read: ${refusalOf2(error)}`), holds: null };
|
|
44790
45332
|
}
|
|
45333
|
+
const { held, missing: missing2 } = wanted;
|
|
44791
45334
|
if (missing2.length === 0)
|
|
44792
|
-
return partOf2("items", ITEMS_PART, "present", "the project holds every issue it shows");
|
|
45335
|
+
return { part: partOf2("items", ITEMS_PART, "present", "the project holds every issue it shows"), holds: held.size };
|
|
44793
45336
|
const port = createGhProjectPort(options.gh);
|
|
45337
|
+
const phase = openPhase(options.progress, "adds", missing2.length);
|
|
44794
45338
|
let added = 0;
|
|
44795
45339
|
try {
|
|
44796
45340
|
for (const number of missing2) {
|
|
44797
45341
|
if (added > 0)
|
|
44798
|
-
await sleep(
|
|
45342
|
+
await sleep(options.config.boardProjectWritePauseMs);
|
|
44799
45343
|
await port.addItem(project.id, { repository, number });
|
|
44800
45344
|
added += 1;
|
|
45345
|
+
phase.advance(added);
|
|
44801
45346
|
}
|
|
44802
45347
|
} catch (error) {
|
|
45348
|
+
phase.end({ done: added, refused: missing2.length - added });
|
|
44803
45349
|
const went = `${issueCount(added)} of ${String(missing2.length)} added`;
|
|
44804
|
-
|
|
45350
|
+
const why = `${went}, then #${String(missing2[added])} was refused: ${refusalOf2(error)}; run \`${PROJECT_STEP_FIX}\` to add the rest`;
|
|
45351
|
+
return { part: partOf2("items", ITEMS_PART, "refused", why), holds: held.size + added };
|
|
45352
|
+
}
|
|
45353
|
+
phase.end({ done: added, refused: 0 });
|
|
45354
|
+
return { part: partOf2("items", ITEMS_PART, "created", `added ${issueCount(added)} to the project`), holds: held.size + added };
|
|
45355
|
+
}
|
|
45356
|
+
function withListed(part, listed4) {
|
|
45357
|
+
return listed4.length === 0 ? part : { ...part, listed: listed4 };
|
|
45358
|
+
}
|
|
45359
|
+
function refusedClause(refused3) {
|
|
45360
|
+
return refused3 === 0 ? "" : `; ${issueCount(refused3)} not refreshed`;
|
|
45361
|
+
}
|
|
45362
|
+
function refreshedPart(refreshed, holds4) {
|
|
45363
|
+
const { writes, changes, skipped: skipped2, refused: refused3 } = refreshed;
|
|
45364
|
+
const listed4 = refused3.map(notRefreshedWarning);
|
|
45365
|
+
if (writes.rateLimited)
|
|
45366
|
+
return withListed(partOf2("fields", FIELDS_PART, "refused", rateLimitWarning(writes.notUpdated)), listed4);
|
|
45367
|
+
if (changes.length === 0 && refused3.length > 0 && (holds4 === null || holds4 <= refused3.length)) {
|
|
45368
|
+
return withListed(partOf2("fields", FIELDS_PART, "refused", `no item was filled: ${issueCount(refused3.length)} not refreshed`), listed4);
|
|
44805
45369
|
}
|
|
44806
|
-
|
|
45370
|
+
if (changes.length === 0) {
|
|
45371
|
+
const held = skipped2.length === 0 ? "every value is as the rules give it" : "every value written is as the rules give it";
|
|
45372
|
+
return withListed(partOf2("fields", FIELDS_PART, "present", `${held}${refusedClause(refused3.length)}`), listed4);
|
|
45373
|
+
}
|
|
45374
|
+
const issues = new Set(changes.map(({ issue: issue4 }) => issue4)).size;
|
|
45375
|
+
const values = writes.written === 1 ? "1 value" : `${String(writes.written)} values`;
|
|
45376
|
+
return withListed(partOf2("fields", FIELDS_PART, "created", `wrote ${values} to ${issueCount(issues)}${refusedClause(refused3.length)}`), listed4);
|
|
44807
45377
|
}
|
|
44808
|
-
async function fieldsStep(options, project) {
|
|
45378
|
+
async function fieldsStep(options, project, holds4) {
|
|
44809
45379
|
const config = { ...options.config, boardProjectNumber: project.number };
|
|
44810
|
-
const
|
|
45380
|
+
const { sleep, progress } = options;
|
|
45381
|
+
const refreshOptions = {
|
|
45382
|
+
config,
|
|
45383
|
+
gh: options.gh,
|
|
45384
|
+
...sleep === undefined ? {} : { sleep },
|
|
45385
|
+
...progress === undefined ? {} : { progress }
|
|
45386
|
+
};
|
|
44811
45387
|
let refreshed;
|
|
44812
45388
|
try {
|
|
44813
45389
|
refreshed = await refreshProjectItems(refreshOptions, [], { everyItem: true });
|
|
@@ -44819,24 +45395,13 @@ async function fieldsStep(options, project) {
|
|
|
44819
45395
|
if (refreshed.kind !== "refreshed") {
|
|
44820
45396
|
return { part: partOf2("fields", FIELDS_PART, "refused", refreshed.warnings.join(" ") || "the refresh sent no call"), problems: [] };
|
|
44821
45397
|
}
|
|
44822
|
-
|
|
44823
|
-
const problems = refreshed.warnings.slice(writes.rateLimited ? 1 : 0);
|
|
44824
|
-
if (writes.rateLimited) {
|
|
44825
|
-
return { part: partOf2("fields", FIELDS_PART, "refused", rateLimitWarning(writes.notUpdated)), problems };
|
|
44826
|
-
}
|
|
44827
|
-
if (changes.length === 0) {
|
|
44828
|
-
const held = skipped2.length === 0 ? "every value is as the rules give it" : "every value written is as the rules give it";
|
|
44829
|
-
return { part: partOf2("fields", FIELDS_PART, "present", held), problems };
|
|
44830
|
-
}
|
|
44831
|
-
const issues = new Set(changes.map(({ issue: issue4 }) => issue4)).size;
|
|
44832
|
-
const values = writes.written === 1 ? "1 value" : `${String(writes.written)} values`;
|
|
44833
|
-
return { part: partOf2("fields", FIELDS_PART, "created", `wrote ${values} to ${issueCount(issues)}`), problems };
|
|
45398
|
+
return { part: refreshedPart(refreshed, holds4), problems: refreshed.skipped.map(skippedFieldWarning) };
|
|
44834
45399
|
}
|
|
44835
45400
|
async function onProject(options, repository, project) {
|
|
44836
45401
|
const items2 = await itemsStep(options, repository, project);
|
|
44837
|
-
const fields = await fieldsStep(options, project);
|
|
45402
|
+
const fields = await fieldsStep(options, project, items2.holds);
|
|
44838
45403
|
const setting = writeProjectNumber(options.root, project.number);
|
|
44839
|
-
return { parts: [items2, fields.part, setting], problems: fields.problems };
|
|
45404
|
+
return { parts: [items2.part, fields.part, setting], problems: fields.problems };
|
|
44840
45405
|
}
|
|
44841
45406
|
async function setUpProject(options) {
|
|
44842
45407
|
const { gh, config } = options;
|
|
@@ -44870,8 +45435,11 @@ function projectPartLine(part) {
|
|
|
44870
45435
|
const row2 = ` ${part.outcome.padEnd(OUTCOME_WIDTH3, " ")} ${part.name}`;
|
|
44871
45436
|
return part.outcome === "present" ? row2 : `${row2}: ${part.detail}`;
|
|
44872
45437
|
}
|
|
45438
|
+
function projectPartLines(part) {
|
|
45439
|
+
return [projectPartLine(part), ...(part.listed ?? []).map((line) => `${LISTED_INDENT}${line}`)];
|
|
45440
|
+
}
|
|
44873
45441
|
function renderProjectSetup(report) {
|
|
44874
|
-
return [PROJECT_HEADING, ...report.parts.
|
|
45442
|
+
return [PROJECT_HEADING, ...report.parts.flatMap((part) => projectPartLines(part)), ...report.problems];
|
|
44875
45443
|
}
|
|
44876
45444
|
function noProject(status, asked, warnings = []) {
|
|
44877
45445
|
return { status, asked, report: null, warnings: Object.freeze([...warnings]) };
|
|
@@ -44889,6 +45457,13 @@ function withWrittenRoadmap(root, config) {
|
|
|
44889
45457
|
const written4 = readRoadmapSetting(root).issue;
|
|
44890
45458
|
return written4 === null ? config : { ...config, roadmapIssue: written4 };
|
|
44891
45459
|
}
|
|
45460
|
+
function retrySeamsOf(options) {
|
|
45461
|
+
const { sleep, onRetry } = options;
|
|
45462
|
+
return {
|
|
45463
|
+
...sleep === undefined ? {} : { sleep },
|
|
45464
|
+
...onRetry === undefined ? {} : { onRetry }
|
|
45465
|
+
};
|
|
45466
|
+
}
|
|
44892
45467
|
async function runProjectStep(options) {
|
|
44893
45468
|
const { wanted, board, root, isTerminal, openPrompter } = options;
|
|
44894
45469
|
if (board.status !== "ran") {
|
|
@@ -44898,7 +45473,16 @@ async function runProjectStep(options) {
|
|
|
44898
45473
|
return noProject("declined", false);
|
|
44899
45474
|
const run = async (asked) => {
|
|
44900
45475
|
const setUp = options.setUp ?? setUpProject;
|
|
44901
|
-
const
|
|
45476
|
+
const config = withWrittenRoadmap(root, options.config);
|
|
45477
|
+
const gh = openProjectRunner(options.openGh(), config, retrySeamsOf(options));
|
|
45478
|
+
const { sleep, progress } = options;
|
|
45479
|
+
const report = await setUp({
|
|
45480
|
+
root,
|
|
45481
|
+
config,
|
|
45482
|
+
gh,
|
|
45483
|
+
...sleep === undefined ? {} : { sleep },
|
|
45484
|
+
...progress === undefined ? {} : { progress }
|
|
45485
|
+
});
|
|
44902
45486
|
return { status: "ran", asked, report, warnings: [] };
|
|
44903
45487
|
};
|
|
44904
45488
|
if (wanted === true)
|
|
@@ -44919,11 +45503,12 @@ function renderProjectStep(result2) {
|
|
|
44919
45503
|
return [`The GitHub project question needs a terminal; run ${PROJECT_STEP_FIX} to create it.`];
|
|
44920
45504
|
return [];
|
|
44921
45505
|
}
|
|
44922
|
-
var PROJECT_STEP_FIX = "rafa init --board --project", SCOPE_PART = "project scope", COPY_PART = "project", ITEMS_PART = "project issues", FIELDS_PART = "project fields", PROJECT_SCOPE2 = "project", SCOPE_ARGS, LOGGED_IN = "success", PROJECT_HEADING = "GitHub project:", OUTCOME_WIDTH3 = 7, PROJECT_QUESTION = "Also create a GitHub project with roadmap and kanban views? [y/N] ", PROJECT_NO_BOARD_WARNING;
|
|
45506
|
+
var PROJECT_STEP_FIX = "rafa init --board --project", SCOPE_PART = "project scope", COPY_PART = "project", ITEMS_PART = "project issues", FIELDS_PART = "project fields", PROJECT_SCOPE2 = "project", SCOPE_ARGS, LOGGED_IN = "success", PROJECT_HEADING = "GitHub project:", OUTCOME_WIDTH3 = 7, LISTED_INDENT, PROJECT_QUESTION = "Also create a GitHub project with roadmap and kanban views? [y/N] ", PROJECT_NO_BOARD_WARNING;
|
|
44923
45507
|
var init_init_board_project = __esm(() => {
|
|
44924
45508
|
init_facts();
|
|
44925
45509
|
init_gh2();
|
|
44926
|
-
|
|
45510
|
+
init_progress2();
|
|
45511
|
+
init_project_runner();
|
|
44927
45512
|
init_refresh_warnings();
|
|
44928
45513
|
init_refresh();
|
|
44929
45514
|
init_rules();
|
|
@@ -44933,6 +45518,7 @@ var init_init_board_project = __esm(() => {
|
|
|
44933
45518
|
init_init_board_project_setting();
|
|
44934
45519
|
init_init_board();
|
|
44935
45520
|
SCOPE_ARGS = Object.freeze(["auth", "status", "--active", "--json", "hosts"]);
|
|
45521
|
+
LISTED_INDENT = " ".repeat(2 + OUTCOME_WIDTH3 + 2);
|
|
44936
45522
|
PROJECT_NO_BOARD_WARNING = "--project creates the GitHub project with the GitHub board," + ` and the board step did not run, so no project was created; run ${PROJECT_STEP_FIX}.`;
|
|
44937
45523
|
});
|
|
44938
45524
|
|
|
@@ -44987,9 +45573,10 @@ function fieldsRow(project, template) {
|
|
|
44987
45573
|
return rowOf8("fields", FIELDS_ROW, "missing", `${sentences} ${fix}`);
|
|
44988
45574
|
}
|
|
44989
45575
|
async function readDoctorProject(input) {
|
|
44990
|
-
const {
|
|
44991
|
-
if (gh === null || number === null)
|
|
45576
|
+
const { number, template } = input;
|
|
45577
|
+
if (input.gh === null || number === null)
|
|
44992
45578
|
return null;
|
|
45579
|
+
const gh = openProjectRunner(input.gh, input.config, input.retry);
|
|
44993
45580
|
const scope = await readScopeRow(gh);
|
|
44994
45581
|
if (scope.outcome !== "present") {
|
|
44995
45582
|
const project = notRead("project", `${PROJECT_ROW} ${String(number)}`, scope);
|
|
@@ -45016,6 +45603,7 @@ var SCOPE_ROW = "project scope", PROJECT_ROW = "project", FIELDS_ROW = "project
|
|
|
45016
45603
|
var init_doctor_project = __esm(() => {
|
|
45017
45604
|
init_gh2();
|
|
45018
45605
|
init_port();
|
|
45606
|
+
init_project_runner();
|
|
45019
45607
|
init_refresh_warnings();
|
|
45020
45608
|
init_config_sections();
|
|
45021
45609
|
init_move_native();
|
|
@@ -46214,7 +46802,7 @@ function failure6(why) {
|
|
|
46214
46802
|
function short2(sha) {
|
|
46215
46803
|
return sha.slice(0, SHORT_SHA);
|
|
46216
46804
|
}
|
|
46217
|
-
function
|
|
46805
|
+
function reasonOf3(data, field5, summary) {
|
|
46218
46806
|
const value = data[field5];
|
|
46219
46807
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : summary;
|
|
46220
46808
|
}
|
|
@@ -46236,8 +46824,8 @@ function readLoopEnding(root, sessionId) {
|
|
|
46236
46824
|
return typeof number === "number" && Number.isSafeInteger(number) && number > 0 ? { kind: "pr", number } : { kind: "none", reason: `its pr event names no pull request number: ${describeValue(number)}` };
|
|
46237
46825
|
}
|
|
46238
46826
|
if (event.name === "error")
|
|
46239
|
-
return { kind: "error", reason:
|
|
46240
|
-
return { kind: event.name === "halt" ? "halt" : "no-pr", reason:
|
|
46827
|
+
return { kind: "error", reason: reasonOf3(event.data, "message", event.summary) };
|
|
46828
|
+
return { kind: event.name === "halt" ? "halt" : "no-pr", reason: reasonOf3(event.data, "reason", event.summary) };
|
|
46241
46829
|
}
|
|
46242
46830
|
function noPullRequestLine(issue4, ending) {
|
|
46243
46831
|
const how = ending.kind === "none" ? "ended without a pull request" : `ended on ${ending.kind}`;
|
|
@@ -47190,7 +47778,7 @@ async function runDoctor(context, seams) {
|
|
|
47190
47778
|
const modeSet = preflight.resolved.sources.boardRelationships !== "default";
|
|
47191
47779
|
const board = await readDoctorBoard(gh, project.root, preflight.config.roadmapIssue, preflight.config.boardRelationships, modeSet);
|
|
47192
47780
|
const { boardProjectNumber: number, boardProjectTemplate: template } = preflight.config;
|
|
47193
|
-
const projectRows = await readDoctorProject({ gh, number, template });
|
|
47781
|
+
const projectRows = await readDoctorProject({ gh, number, template, config: preflight.config, retry: commandRetrySeams(context.output, context.outputMode) });
|
|
47194
47782
|
const readings = { ...board, project: projectRows, cleanup, refs, release, tiers, effortSchema, effortSync };
|
|
47195
47783
|
writeText(context, renderDoctor(preflight));
|
|
47196
47784
|
await announceRisk(context, preflight, seams);
|
|
@@ -47257,6 +47845,7 @@ function createDoctorCommand(seams = DEFAULT_DOCTOR_SEAMS) {
|
|
|
47257
47845
|
}
|
|
47258
47846
|
var DEFAULT_DOCTOR_SEAMS, NOTHING_CHECKED = "Nothing was checked.", NO_ITEMS3, NO_START_TIER, doctor_default;
|
|
47259
47847
|
var init_doctor = __esm(() => {
|
|
47848
|
+
init_project_runner();
|
|
47260
47849
|
init_command();
|
|
47261
47850
|
init_version();
|
|
47262
47851
|
init_config_load();
|
|
@@ -47984,13 +48573,13 @@ function estimateFrom(secondsPerTask, left) {
|
|
|
47984
48573
|
}
|
|
47985
48574
|
function byTaskEstimate(row3, counts) {
|
|
47986
48575
|
const minutes2 = row3?.perTask.minutes.avg ?? null;
|
|
47987
|
-
const estimate = estimateFrom(minutes2 === null ? null : minutes2 *
|
|
48576
|
+
const estimate = estimateFrom(minutes2 === null ? null : minutes2 * SECONDS_PER_MINUTE2, tasksLeft(counts));
|
|
47988
48577
|
return estimate === null || row3 === undefined ? null : { ...estimate, sessions: row3.tasks };
|
|
47989
48578
|
}
|
|
47990
48579
|
function byProgressEstimate(planStartedAt, counts, now) {
|
|
47991
48580
|
if (counts.done === 0)
|
|
47992
48581
|
return null;
|
|
47993
|
-
const elapsedSeconds = Math.max(0, (now.getTime() - Date.parse(planStartedAt)) /
|
|
48582
|
+
const elapsedSeconds = Math.max(0, (now.getTime() - Date.parse(planStartedAt)) / MS_PER_SECOND5);
|
|
47994
48583
|
const estimate = estimateFrom(elapsedSeconds / counts.done, tasksLeft(counts));
|
|
47995
48584
|
return estimate === null ? null : { ...estimate, planStartedAt, elapsedSeconds: Math.round(elapsedSeconds) };
|
|
47996
48585
|
}
|
|
@@ -48046,7 +48635,7 @@ function readStatusWidget(root, inputs, isAlive) {
|
|
|
48046
48635
|
const seams = isAlive === undefined ? {} : { isAlive };
|
|
48047
48636
|
return statusWidget(root, readSessions(root, seams), inputs);
|
|
48048
48637
|
}
|
|
48049
|
-
var
|
|
48638
|
+
var MS_PER_SECOND5 = 1000, SECONDS_PER_MINUTE2 = 60;
|
|
48050
48639
|
var init_dashboard_status = __esm(() => {
|
|
48051
48640
|
init_loop_sessions();
|
|
48052
48641
|
init_plan_files();
|
|
@@ -50497,7 +51086,8 @@ async function refreshProjectAfterEpic(context, seams, target) {
|
|
|
50497
51086
|
});
|
|
50498
51087
|
if (config.boardProjectNumber === null)
|
|
50499
51088
|
return null;
|
|
50500
|
-
const
|
|
51089
|
+
const retry = commandRetrySeams(context.output, context.outputMode, seams.sleep);
|
|
51090
|
+
const openGh = () => openProjectRunner(seams.gh ?? createGhRunner({ cwd: project.root }), config, retry);
|
|
50501
51091
|
warnings = await refreshLines(config, openGh, seams.projectRefresh ?? refreshIssueItems, target, named4);
|
|
50502
51092
|
} catch (error) {
|
|
50503
51093
|
warnings = [epicProjectProblemLine(named4, messageOf(error))];
|
|
@@ -50510,6 +51100,7 @@ var init_epic_project = __esm(() => {
|
|
|
50510
51100
|
init_github();
|
|
50511
51101
|
init_add_issue();
|
|
50512
51102
|
init_issue_board_refresh();
|
|
51103
|
+
init_project_runner();
|
|
50513
51104
|
init_refresh_warnings();
|
|
50514
51105
|
init_config_sections();
|
|
50515
51106
|
init_issue_tracker();
|
|
@@ -51741,7 +52332,7 @@ function summariseEpicCost(rows2, members) {
|
|
|
51741
52332
|
}
|
|
51742
52333
|
return {
|
|
51743
52334
|
runs: seen.size,
|
|
51744
|
-
wallSeconds: Math.round(minutes2 *
|
|
52335
|
+
wallSeconds: Math.round(minutes2 * SECONDS_PER_MINUTE3),
|
|
51745
52336
|
runsWithoutTime,
|
|
51746
52337
|
tokens: tokens2
|
|
51747
52338
|
};
|
|
@@ -51761,7 +52352,7 @@ function renderEpicCost(cost, estimate) {
|
|
|
51761
52352
|
MEMBERSHIP_NOTE
|
|
51762
52353
|
];
|
|
51763
52354
|
}
|
|
51764
|
-
var MEMBERSHIP_NOTE, NO_ESTIMATE = "none written",
|
|
52355
|
+
var MEMBERSHIP_NOTE, NO_ESTIMATE = "none written", SECONDS_PER_MINUTE3 = 60;
|
|
51765
52356
|
var init_epic_cost = __esm(() => {
|
|
51766
52357
|
init_naming();
|
|
51767
52358
|
init_loop_sessions();
|
|
@@ -52954,7 +53545,7 @@ function resultOf5(run, action, fields = {}) {
|
|
|
52954
53545
|
...fields
|
|
52955
53546
|
};
|
|
52956
53547
|
}
|
|
52957
|
-
async function
|
|
53548
|
+
async function settle3(run, action, ref14, foundBy, supersedes) {
|
|
52958
53549
|
const { store } = run.route;
|
|
52959
53550
|
const { key } = run.filing;
|
|
52960
53551
|
if (store === null || key === null)
|
|
@@ -52966,13 +53557,13 @@ async function fileNew(run, extras = {}) {
|
|
|
52966
53557
|
const { filing } = run;
|
|
52967
53558
|
const draft = extras.supersedes === undefined && extras.duplicates === undefined ? filing.draft : { ...filing.draft, body: issueText(ISSUE_OPENING, { ...filing.values, ...extras }, run.redact) };
|
|
52968
53559
|
const created = await step(run, `the ${run.route.channel} tracker create`, () => run.route.tracker.create(draft));
|
|
52969
|
-
return created.ok ?
|
|
53560
|
+
return created.ok ? settle3(run, "filed", created.value, null, extras.supersedes) : resultOf5(run, "failed", { problem: created.problem });
|
|
52970
53561
|
}
|
|
52971
53562
|
async function commentOn2(run, ref14, foundBy, action = "commented", comment = run.filing.comment) {
|
|
52972
53563
|
const commented = await step(run, `the ${run.route.channel} tracker comment`, () => run.route.tracker.comment(ref14, comment));
|
|
52973
53564
|
if (!commented.ok)
|
|
52974
53565
|
return resultOf5(run, "failed", { ref: ref14, foundBy, problem: commented.problem });
|
|
52975
|
-
return foundBy === "store" ? resultOf5(run, action, { ref: ref14, foundBy }) :
|
|
53566
|
+
return foundBy === "store" ? resultOf5(run, action, { ref: ref14, foundBy }) : settle3(run, action, ref14, foundBy);
|
|
52976
53567
|
}
|
|
52977
53568
|
async function lookUp2(run, key, searchText) {
|
|
52978
53569
|
const { route, filing } = run;
|
|
@@ -54902,6 +55493,11 @@ var init_scaffold = __esm(() => {
|
|
|
54902
55493
|
"# project:",
|
|
54903
55494
|
`# template: ${CONFIG_DEFAULTS.boardProjectTemplate} # the project URL rafa init --board --project copies`,
|
|
54904
55495
|
"# number: # the project rafa mirrors the board to; unset until rafa init --board --project",
|
|
55496
|
+
`# retries: ${String(CONFIG_DEFAULTS.boardProjectRetries)} # 1..10 | false, tries again after a failed project call`,
|
|
55497
|
+
`# retryWaitSeconds: ${String(CONFIG_DEFAULTS.boardProjectRetryWaitSeconds)} # 1..60, the first wait before a retry; each later one doubles`,
|
|
55498
|
+
`# progressSeconds: ${String(CONFIG_DEFAULTS.boardProjectProgressSeconds)} # 1..300 | false, the most seconds between two progress lines`,
|
|
55499
|
+
`# writeBatchSize: ${String(CONFIG_DEFAULTS.boardProjectWriteBatchSize)} # 1..100, field writes per request`,
|
|
55500
|
+
`# writePauseMs: ${String(CONFIG_DEFAULTS.boardProjectWritePauseMs)} # 0..60000, the pause between two write requests`,
|
|
54905
55501
|
"# roadmap:",
|
|
54906
55502
|
"# issue: # the issue plan create --next reads; unset is the one titled Roadmap",
|
|
54907
55503
|
"# claims:",
|
|
@@ -55217,7 +55813,9 @@ async function runInit(context, seams) {
|
|
|
55217
55813
|
config: scopes.config,
|
|
55218
55814
|
openGh: () => seams.gh(scopes.written.root),
|
|
55219
55815
|
isTerminal: seams.isTerminal,
|
|
55220
|
-
openPrompter: seams.openPrompter
|
|
55816
|
+
openPrompter: seams.openPrompter,
|
|
55817
|
+
...commandRetrySeams(context.output, context.outputMode, seams.sleep),
|
|
55818
|
+
progress: commandProgressFeed(context.output, context.outputMode, scopes.config.boardProjectProgressSeconds, seams.now === undefined ? {} : { now: seams.now })
|
|
55221
55819
|
});
|
|
55222
55820
|
const result2 = {
|
|
55223
55821
|
...scopes.written,
|
|
@@ -55254,7 +55852,7 @@ function createInitCommand(seams = DEFAULT_INIT_SEAMS) {
|
|
|
55254
55852
|
subject: "init",
|
|
55255
55853
|
action: "init",
|
|
55256
55854
|
summary: "set up a rafa project: its root, .rafa/config.yaml, the tree and the .gitignore entry",
|
|
55257
|
-
description: "Sets up a rafa project. On a terminal it lists the root candidates, the git toplevel or" + " the working directory outside a repository and then the outermost monorepo root above it, each" + " refused one with its reason, and reads a candidate number or a path typed freely. `--root=<path>`" + " names the root instead, absolute or relative to the working directory, and `--yes` takes the" + " first candidate; without a terminal one of the two is needed. Under the root it writes" + " `.rafa/config.yaml` with every setting commented out at its default, the tree `specs/`, `plans/`," + " `runs/`, `effort/` and `instincts/` under `.rafa/`, and the rafa block in `.gitignore` from the" + " `tracking` settings; under the home it writes `~/.rafa/config.yaml` and `~/.rafa/instincts/` when" + " they are missing. Only what is missing or stale is written, so a rerun changes no byte and says" + " so. It warns when `~/.rafa/bin` is not on PATH ahead of `~/.bun/bin`, and when a plan under" + " `plan.dir` routes to an agent that resolves only in `~/.claude/agents` and rafa does not ship," + " naming `rafa agent vendor <name>`; it writes nothing under `.claude/` itself. A repository whose pull request provider is `gh` ends with one" + " question about setting up the GitHub board, which `--board` and `--no-board` answer for a" + " script, and then, once the board has run, one question about installing the epic guard" + " workflow `.github/workflows/epic-guard.yml`, which removes a second `epic:` label from an issue" + " and comments why; `--epic-guard` and `--no-epic-guard` answer that one. When `board.relationships`" + " is set, the board is then read for relationships held in the other mode: every write that moves" + " them into the configured one is printed and a terminal is asked once, nothing is written on a no," + " and once every write went through a second question asks whether to remove the old marks. Last, once the" + " board has run, one question asks whether to copy the GitHub project template to the repository's" + " owner, link it, add the issues and fill their fields; `--project` and `--no-project` answer that one." + " On a terminal it also asks once whether every pull request bumps the version and gains" + " a changelog entry, and writes the answer as `release.enabled`; `--release` and `--no-release`" + " answer that one, and `--yes` leaves it unset. With `--output=json` the" + " root and every path checked are the data of the terminal result event.",
|
|
55855
|
+
description: "Sets up a rafa project. On a terminal it lists the root candidates, the git toplevel or" + " the working directory outside a repository and then the outermost monorepo root above it, each" + " refused one with its reason, and reads a candidate number or a path typed freely. `--root=<path>`" + " names the root instead, absolute or relative to the working directory, and `--yes` takes the" + " first candidate; without a terminal one of the two is needed. Under the root it writes" + " `.rafa/config.yaml` with every setting commented out at its default, the tree `specs/`, `plans/`," + " `runs/`, `effort/` and `instincts/` under `.rafa/`, and the rafa block in `.gitignore` from the" + " `tracking` settings; under the home it writes `~/.rafa/config.yaml` and `~/.rafa/instincts/` when" + " they are missing. Only what is missing or stale is written, so a rerun changes no byte and says" + " so. It warns when `~/.rafa/bin` is not on PATH ahead of `~/.bun/bin`, and when a plan under" + " `plan.dir` routes to an agent that resolves only in `~/.claude/agents` and rafa does not ship," + " naming `rafa agent vendor <name>`; it writes nothing under `.claude/` itself. A repository whose pull request provider is `gh` ends with one" + " question about setting up the GitHub board, which `--board` and `--no-board` answer for a" + " script, and then, once the board has run, one question about installing the epic guard" + " workflow `.github/workflows/epic-guard.yml`, which removes a second `epic:` label from an issue" + " and comments why; `--epic-guard` and `--no-epic-guard` answer that one. When `board.relationships`" + " is set, the board is then read for relationships held in the other mode: every write that moves" + " them into the configured one is printed and a terminal is asked once, nothing is written on a no," + " and once every write went through a second question asks whether to remove the old marks. Last, once the" + " board has run, one question asks whether to copy the GitHub project template to the repository's" + " owner, link it, add the issues and fill their fields; `--project` and `--no-project` answer that one." + " Adding the issues, reading their facts and writing their fields each print a start line with the" + " total, a progress line at most every board.project.progressSeconds and an end line, one `progress`" + " event each with `--output=json`." + " On a terminal it also asks once whether every pull request bumps the version and gains" + " a changelog entry, and writes the answer as `release.enabled`; `--release` and `--no-release`" + " answer that one, and `--yes` leaves it unset. With `--output=json` the" + " root and every path checked are the data of the terminal result event.",
|
|
55258
55856
|
args: [],
|
|
55259
55857
|
flags: [
|
|
55260
55858
|
{
|
|
@@ -55279,7 +55877,7 @@ function createInitCommand(seams = DEFAULT_INIT_SEAMS) {
|
|
|
55279
55877
|
},
|
|
55280
55878
|
{
|
|
55281
55879
|
name: "project",
|
|
55282
|
-
description: "Create the GitHub project without asking, once the board has run: copy" + " `board.project.template` to the repository's owner, link the repository, add its issues, fill" + " their fields and save `board.project.number`. `--no-project` leaves it out. Without either, a" + " terminal is asked once and a run with no terminal leaves it out.",
|
|
55880
|
+
description: "Create the GitHub project without asking, once the board has run: copy" + " `board.project.template` to the repository's owner, link the repository, add its issues, fill" + " their fields and save `board.project.number`. `--no-project` leaves it out. Without either, a" + " terminal is asked once and a run with no terminal leaves it out. The adds, the facts reads and the" + " field writes print their progress, as `adding issues: 146/283, 6m 40s`.",
|
|
55283
55881
|
type: "boolean"
|
|
55284
55882
|
},
|
|
55285
55883
|
{
|
|
@@ -55328,6 +55926,8 @@ var DEFAULT_INIT_SEAMS, NOTHING_WRITTEN3 = "Nothing was written.", SOURCE_PHRASE
|
|
|
55328
55926
|
var init_init = __esm(() => {
|
|
55329
55927
|
init_github();
|
|
55330
55928
|
init_vendorable();
|
|
55929
|
+
init_progress2();
|
|
55930
|
+
init_project_runner();
|
|
55331
55931
|
init_command();
|
|
55332
55932
|
init_confirm();
|
|
55333
55933
|
init_config_load();
|
|
@@ -56454,7 +57054,7 @@ async function addCreatedToProject(context, seams, ref15) {
|
|
|
56454
57054
|
});
|
|
56455
57055
|
const lines2 = await addAndRefreshIssue({
|
|
56456
57056
|
config,
|
|
56457
|
-
openGh: () => seams.gh ?? createGhRunner({ cwd: project.root })
|
|
57057
|
+
openGh: () => openProjectRunner(seams.gh ?? createGhRunner({ cwd: project.root }), config, commandRetrySeams(context.output, context.outputMode, seams.sleep))
|
|
56458
57058
|
}, issue4);
|
|
56459
57059
|
for (const line of lines2)
|
|
56460
57060
|
context.output.warn(line);
|
|
@@ -56536,6 +57136,7 @@ var init_create = __esm(() => {
|
|
|
56536
57136
|
init_github();
|
|
56537
57137
|
init_issue_values();
|
|
56538
57138
|
init_add_issue();
|
|
57139
|
+
init_project_runner();
|
|
56539
57140
|
init_config_sections();
|
|
56540
57141
|
init_triage2();
|
|
56541
57142
|
init_plan_files();
|
|
@@ -63448,10 +64049,10 @@ async function runNextChain(options) {
|
|
|
63448
64049
|
const homeStop = home === null ? null : await turn(home, null);
|
|
63449
64050
|
return homeStop === null ? stopOn("loop-started", state) : stopOn(homeStop, home ?? state);
|
|
63450
64051
|
}
|
|
63451
|
-
const
|
|
63452
|
-
const settleStop =
|
|
64052
|
+
const settle4 = followsMerge(state.action) ? options.afterMerge?.() ?? null : null;
|
|
64053
|
+
const settleStop = settle4 === null ? null : await turn(settle4, null);
|
|
63453
64054
|
if (settleStop !== null)
|
|
63454
|
-
return stopOn(settleStop,
|
|
64055
|
+
return stopOn(settleStop, settle4 ?? state);
|
|
63455
64056
|
if (steps.length >= MAX_ACTIONS)
|
|
63456
64057
|
return stopOn("capped", state);
|
|
63457
64058
|
previous = state;
|
|
@@ -64882,6 +65483,10 @@ function openPrContext(context, seams = DEFAULT_PR_SEAMS) {
|
|
|
64882
65483
|
versionGuard: mergeGuardSettings(config),
|
|
64883
65484
|
projectRefresh: {
|
|
64884
65485
|
boardProjectNumber: config.boardProjectNumber,
|
|
65486
|
+
boardProjectRetries: config.boardProjectRetries,
|
|
65487
|
+
boardProjectRetryWaitSeconds: config.boardProjectRetryWaitSeconds,
|
|
65488
|
+
boardProjectWriteBatchSize: config.boardProjectWriteBatchSize,
|
|
65489
|
+
boardProjectWritePauseMs: config.boardProjectWritePauseMs,
|
|
64885
65490
|
boardRelationships: config.boardRelationships,
|
|
64886
65491
|
roadmapIssue: config.roadmapIssue,
|
|
64887
65492
|
releaseFragments: config.releaseFragments
|
|
@@ -65748,7 +66353,7 @@ async function refreshProjectAfterMerge(options) {
|
|
|
65748
66353
|
const closed = [...new Set(closedIssuesIn(options.body))];
|
|
65749
66354
|
if (config.boardProjectNumber === null || closed.length === 0)
|
|
65750
66355
|
return null;
|
|
65751
|
-
const gh = options.openGh();
|
|
66356
|
+
const gh = openProjectRunner(options.openGh(), config, options.retry);
|
|
65752
66357
|
const wanted = new Set(closed);
|
|
65753
66358
|
const warnings = [];
|
|
65754
66359
|
let listed5 = [];
|
|
@@ -65770,6 +66375,7 @@ async function refreshProjectAfterMerge(options) {
|
|
|
65770
66375
|
}
|
|
65771
66376
|
var init_merge_project = __esm(() => {
|
|
65772
66377
|
init_issue_board_refresh();
|
|
66378
|
+
init_project_runner();
|
|
65773
66379
|
init_refresh_warnings();
|
|
65774
66380
|
init_select3();
|
|
65775
66381
|
init_roadmap_board();
|
|
@@ -66537,7 +67143,14 @@ async function runMerge2(context, seams) {
|
|
|
66537
67143
|
const roadmapTicks = await reportTick(context, pr, seams, detail);
|
|
66538
67144
|
const steps = cleanUpAfterMerge(git, detail, { info: info2, warn: warn4 });
|
|
66539
67145
|
const board = await reportAfterCleanUp(context, pr, seams, detail);
|
|
66540
|
-
await refreshProjectAfterMerge({
|
|
67146
|
+
await refreshProjectAfterMerge({
|
|
67147
|
+
body: detail.body,
|
|
67148
|
+
config: pr.projectRefresh,
|
|
67149
|
+
openGh: () => openGh(pr, seams),
|
|
67150
|
+
unblocked: board.unblocked,
|
|
67151
|
+
warn: warn4,
|
|
67152
|
+
retry: commandRetrySeams(context.output, context.outputMode)
|
|
67153
|
+
});
|
|
66541
67154
|
const followUps = reportFollowUps({
|
|
66542
67155
|
root: pr.project.root,
|
|
66543
67156
|
home: pr.project.home,
|
|
@@ -66622,6 +67235,7 @@ function createPrMergeCommand(seams = DEFAULT_MERGE_SEAMS) {
|
|
|
66622
67235
|
var USAGE43, YES_ANSWERS6, DEFAULT_MERGE_SEAMS, merge_default2;
|
|
66623
67236
|
var init_merge4 = __esm(() => {
|
|
66624
67237
|
init_github();
|
|
67238
|
+
init_project_runner();
|
|
66625
67239
|
init_roadmap_tick();
|
|
66626
67240
|
init_roadmap();
|
|
66627
67241
|
init_command();
|
|
@@ -69467,7 +70081,7 @@ function pollWord(polls) {
|
|
|
69467
70081
|
return polls === 1 ? "1 poll" : `${polls} polls`;
|
|
69468
70082
|
}
|
|
69469
70083
|
function secondsWord(elapsedMs) {
|
|
69470
|
-
return `${Math.round(elapsedMs /
|
|
70084
|
+
return `${Math.round(elapsedMs / MS_PER_SECOND6)}s`;
|
|
69471
70085
|
}
|
|
69472
70086
|
function verdictWord(verdict) {
|
|
69473
70087
|
return verdict === "timeout" || verdict === "pending" ? "still running" : verdict;
|
|
@@ -69579,7 +70193,7 @@ function createPrWaitCommand(seams = DEFAULT_WAIT_SEAMS) {
|
|
|
69579
70193
|
};
|
|
69580
70194
|
return Object.freeze(command);
|
|
69581
70195
|
}
|
|
69582
|
-
var USAGE49, TIMEOUT_FLAG2 = "timeout", DEFAULT_WAIT_TIMEOUT_MIN, MS_PER_MIN = 60000,
|
|
70196
|
+
var USAGE49, TIMEOUT_FLAG2 = "timeout", DEFAULT_WAIT_TIMEOUT_MIN, MS_PER_MIN = 60000, MS_PER_SECOND6 = 1000, WAIT_EXIT_CODES, DEFAULT_WAIT_SEAMS, wait_default2;
|
|
69583
70197
|
var init_wait2 = __esm(() => {
|
|
69584
70198
|
init_command();
|
|
69585
70199
|
init_ending();
|
|
@@ -69782,7 +70396,7 @@ function readString7(value, where) {
|
|
|
69782
70396
|
refuse19(`${where} is ${describeValue(value)}, expected a string`);
|
|
69783
70397
|
return value;
|
|
69784
70398
|
}
|
|
69785
|
-
function
|
|
70399
|
+
function readOnePage2(value, where) {
|
|
69786
70400
|
const connection = readMapping6(value, where);
|
|
69787
70401
|
if (readMapping6(connection["pageInfo"], `${where}.pageInfo`)["hasNextPage"] !== false) {
|
|
69788
70402
|
refuse19(`${where} holds more entries than one page`);
|
|
@@ -69794,7 +70408,7 @@ function readPull2(value, where, repository) {
|
|
|
69794
70408
|
if (pull2["state"] !== "MERGED")
|
|
69795
70409
|
return null;
|
|
69796
70410
|
const merge2 = pull2["mergeCommit"];
|
|
69797
|
-
const linked =
|
|
70411
|
+
const linked = readOnePage2(pull2["closingIssuesReferences"], `${where}.closingIssuesReferences`).flatMap((node, index) => {
|
|
69798
70412
|
const at = `${where}.closingIssuesReferences[${String(index)}]`;
|
|
69799
70413
|
const issue4 = readMapping6(node, at);
|
|
69800
70414
|
const owner = readString7(readMapping6(issue4["repository"], `${at}.repository`)["nameWithOwner"], `${at}.repository.nameWithOwner`);
|
|
@@ -69829,7 +70443,7 @@ async function readBatch(gh, commits, branch) {
|
|
|
69829
70443
|
const object = answer5[commitAlias(index)];
|
|
69830
70444
|
if (object === null || object === undefined)
|
|
69831
70445
|
return [];
|
|
69832
|
-
const pulls =
|
|
70446
|
+
const pulls = readOnePage2(readMapping6(object, where)["associatedPullRequests"], `${where}.associatedPullRequests`).map((pull2, at) => readPull2(pull2, `${where}.associatedPullRequests[${String(at)}]`, repository)).filter((pull2) => pull2 !== null);
|
|
69833
70447
|
return broughtBy(pulls, commit, branch);
|
|
69834
70448
|
});
|
|
69835
70449
|
}
|
|
@@ -69851,7 +70465,7 @@ async function refreshProjectAfterSettle(options) {
|
|
|
69851
70465
|
const commits = releasedCommits(options.delivered);
|
|
69852
70466
|
if (config.boardProjectNumber === null || commits === null || commits.length === 0)
|
|
69853
70467
|
return null;
|
|
69854
|
-
const gh = options.openGh();
|
|
70468
|
+
const gh = openProjectRunner(options.openGh(), config, options.retry);
|
|
69855
70469
|
let pulls;
|
|
69856
70470
|
try {
|
|
69857
70471
|
pulls = await readPulls(gh, commits, branch);
|
|
@@ -69871,6 +70485,7 @@ async function refreshProjectAfterSettle(options) {
|
|
|
69871
70485
|
var COMMIT_BATCH = 20, COMMIT_PULL_LIMIT = 10, CLOSING_LIMIT = 100, PREFIX42 = "release settle project";
|
|
69872
70486
|
var init_settle_project = __esm(() => {
|
|
69873
70487
|
init_issue_board_refresh();
|
|
70488
|
+
init_project_runner();
|
|
69874
70489
|
init_refresh_warnings();
|
|
69875
70490
|
init_roadmap();
|
|
69876
70491
|
init_config_sections();
|
|
@@ -70028,7 +70643,8 @@ async function runSettle(context, seams = DEFAULT_RELEASE_SETTLE_SEAMS) {
|
|
|
70028
70643
|
branch,
|
|
70029
70644
|
config,
|
|
70030
70645
|
openGh: () => (seams.gh ?? ((cwd) => createGhRunner({ cwd })))(project.root),
|
|
70031
|
-
refresh: seams.refresh
|
|
70646
|
+
refresh: seams.refresh,
|
|
70647
|
+
retry: commandRetrySeams(context.output, context.outputMode)
|
|
70032
70648
|
});
|
|
70033
70649
|
return { ...ran.value, project: refreshed };
|
|
70034
70650
|
}
|
|
@@ -70087,6 +70703,7 @@ function createReleaseSettleCommand(seams = DEFAULT_RELEASE_SETTLE_SEAMS) {
|
|
|
70087
70703
|
var RELEASE_SETTLE_USAGE = "rafa release settle [--dry-run]", COMMAND_NAME17 = "rafa release settle", DRY_RUN_FLAG9 = "dry-run", INDENT17 = " ", SHORT_HASH4 = 12, DEFAULT_RELEASE_SETTLE_SEAMS, settle_default;
|
|
70088
70704
|
var init_settle2 = __esm(() => {
|
|
70089
70705
|
init_github();
|
|
70706
|
+
init_project_runner();
|
|
70090
70707
|
init_command();
|
|
70091
70708
|
init_pr();
|
|
70092
70709
|
init_settle_pr();
|
|
@@ -71759,7 +72376,7 @@ function actionLines(actions) {
|
|
|
71759
72376
|
return marker === null ? [] : [`${marker} ${action.path}: ${action.detail}`];
|
|
71760
72377
|
});
|
|
71761
72378
|
}
|
|
71762
|
-
function
|
|
72379
|
+
function checkOptions2(context, projectRoot3) {
|
|
71763
72380
|
return { projectRoot: projectRoot3, pathDirs: pathDirectories(context.env["PATH"]) };
|
|
71764
72381
|
}
|
|
71765
72382
|
function report5(context, result2, lines2) {
|
|
@@ -71771,7 +72388,7 @@ function report5(context, result2, lines2) {
|
|
|
71771
72388
|
context.output.info(line);
|
|
71772
72389
|
}
|
|
71773
72390
|
function runPlan(context, scope, backfillDir, projectRoot3) {
|
|
71774
|
-
const plan2 = planDerivation(scope.dir,
|
|
72391
|
+
const plan2 = planDerivation(scope.dir, checkOptions2(context, projectRoot3));
|
|
71775
72392
|
const candidates = selectProposals(scope.dir).length;
|
|
71776
72393
|
const actions = plan2.actions.map(actionData);
|
|
71777
72394
|
const result2 = {
|
|
@@ -71840,7 +72457,7 @@ function rowPaths(files, root) {
|
|
|
71840
72457
|
return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row3) => row3.status === ANSWERED_ROW).map((row3) => join109(root, ...row3.path.split("/"))));
|
|
71841
72458
|
}
|
|
71842
72459
|
function runApply(context, scope, backfillDir, projectRoot3) {
|
|
71843
|
-
const options =
|
|
72460
|
+
const options = checkOptions2(context, projectRoot3);
|
|
71844
72461
|
const backupDir = backupDirectory(scope.base);
|
|
71845
72462
|
const repoRoot = projectOf13(context).root;
|
|
71846
72463
|
const backups = [];
|