@nonameolsson/nightjar 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +405 -2
- package/dist/account.d.ts +12 -0
- package/dist/account.js +57 -0
- package/dist/account.js.map +1 -0
- package/dist/adapter-module.d.ts +18 -0
- package/dist/adapter-module.js +83 -0
- package/dist/adapter-module.js.map +1 -0
- package/dist/adapters.d.ts +15 -0
- package/dist/adapters.js +160 -0
- package/dist/adapters.js.map +1 -0
- package/dist/args.d.ts +13 -0
- package/dist/args.js +84 -0
- package/dist/args.js.map +1 -0
- package/dist/ask.d.ts +6 -0
- package/dist/ask.js +27 -0
- package/dist/ask.js.map +1 -0
- package/dist/azure-devops/api.d.ts +34 -0
- package/dist/azure-devops/api.js +98 -0
- package/dist/azure-devops/api.js.map +1 -0
- package/dist/azure-devops/code-host.d.ts +36 -0
- package/dist/azure-devops/code-host.js +185 -0
- package/dist/azure-devops/code-host.js.map +1 -0
- package/dist/azure-devops/fake-azure-devops.d.ts +90 -0
- package/dist/azure-devops/fake-azure-devops.js +728 -0
- package/dist/azure-devops/fake-azure-devops.js.map +1 -0
- package/dist/azure-devops/index.d.ts +8 -0
- package/dist/azure-devops/index.js +11 -0
- package/dist/azure-devops/index.js.map +1 -0
- package/dist/azure-devops/sign-in.d.ts +11 -0
- package/dist/azure-devops/sign-in.js +68 -0
- package/dist/azure-devops/sign-in.js.map +1 -0
- package/dist/azure-devops/text.d.ts +1 -0
- package/dist/azure-devops/text.js +41 -0
- package/dist/azure-devops/text.js.map +1 -0
- package/dist/azure-devops/tracker.d.ts +44 -0
- package/dist/azure-devops/tracker.js +333 -0
- package/dist/azure-devops/tracker.js.map +1 -0
- package/dist/build.d.ts +75 -0
- package/dist/build.js +698 -0
- package/dist/build.js.map +1 -0
- package/dist/check.d.ts +8 -0
- package/dist/check.js +25 -0
- package/dist/check.js.map +1 -0
- package/dist/checks.d.ts +45 -0
- package/dist/checks.js +243 -0
- package/dist/checks.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/code-host.d.ts +19 -0
- package/dist/code-host.js +2 -0
- package/dist/code-host.js.map +1 -0
- package/dist/config.d.ts +86 -0
- package/dist/config.js +294 -0
- package/dist/config.js.map +1 -0
- package/dist/contract/case.d.ts +4 -0
- package/dist/contract/case.js +2 -0
- package/dist/contract/case.js.map +1 -0
- package/dist/contract/code-host.d.ts +24 -0
- package/dist/contract/code-host.js +108 -0
- package/dist/contract/code-host.js.map +1 -0
- package/dist/contract/command.d.ts +2 -0
- package/dist/contract/command.js +36 -0
- package/dist/contract/command.js.map +1 -0
- package/dist/contract/feature-writer.d.ts +3 -0
- package/dist/contract/feature-writer.js +101 -0
- package/dist/contract/feature-writer.js.map +1 -0
- package/dist/contract/run.d.ts +18 -0
- package/dist/contract/run.js +89 -0
- package/dist/contract/run.js.map +1 -0
- package/dist/contract/tracker.d.ts +30 -0
- package/dist/contract/tracker.js +250 -0
- package/dist/contract/tracker.js.map +1 -0
- package/dist/create.d.ts +9 -0
- package/dist/create.js +112 -0
- package/dist/create.js.map +1 -0
- package/dist/doctor.d.ts +4 -0
- package/dist/doctor.js +42 -0
- package/dist/doctor.js.map +1 -0
- package/dist/fakes/code-host.d.ts +21 -0
- package/dist/fakes/code-host.js +42 -0
- package/dist/fakes/code-host.js.map +1 -0
- package/dist/fakes/harness.d.ts +7 -0
- package/dist/fakes/harness.js +68 -0
- package/dist/fakes/harness.js.map +1 -0
- package/dist/fakes/machine.d.ts +11 -0
- package/dist/fakes/machine.js +101 -0
- package/dist/fakes/machine.js.map +1 -0
- package/dist/fakes/tracker.d.ts +40 -0
- package/dist/fakes/tracker.js +116 -0
- package/dist/fakes/tracker.js.map +1 -0
- package/dist/feature-file.d.ts +12 -0
- package/dist/feature-file.js +84 -0
- package/dist/feature-file.js.map +1 -0
- package/dist/git.d.ts +9 -0
- package/dist/git.js +12 -0
- package/dist/git.js.map +1 -0
- package/dist/github/api.d.ts +37 -0
- package/dist/github/api.js +66 -0
- package/dist/github/api.js.map +1 -0
- package/dist/github/code-host.d.ts +19 -0
- package/dist/github/code-host.js +105 -0
- package/dist/github/code-host.js.map +1 -0
- package/dist/github/fake-gh.d.ts +17 -0
- package/dist/github/fake-gh.js +51 -0
- package/dist/github/fake-gh.js.map +1 -0
- package/dist/github/fake-github.d.ts +58 -0
- package/dist/github/fake-github.js +285 -0
- package/dist/github/fake-github.js.map +1 -0
- package/dist/github/labels.d.ts +3 -0
- package/dist/github/labels.js +44 -0
- package/dist/github/labels.js.map +1 -0
- package/dist/github/tracker.d.ts +28 -0
- package/dist/github/tracker.js +208 -0
- package/dist/github/tracker.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +19 -0
- package/dist/init.js +225 -0
- package/dist/init.js.map +1 -0
- package/dist/ledger.d.ts +13 -0
- package/dist/ledger.js +49 -0
- package/dist/ledger.js.map +1 -0
- package/dist/main.d.ts +11 -0
- package/dist/main.js +215 -0
- package/dist/main.js.map +1 -0
- package/dist/person-config.d.ts +9 -0
- package/dist/person-config.js +46 -0
- package/dist/person-config.js.map +1 -0
- package/dist/plan.d.ts +9 -0
- package/dist/plan.js +27 -0
- package/dist/plan.js.map +1 -0
- package/dist/ports.d.ts +16 -0
- package/dist/ports.js +104 -0
- package/dist/ports.js.map +1 -0
- package/dist/prompt.d.ts +166 -0
- package/dist/prompt.js +217 -0
- package/dist/prompt.js.map +1 -0
- package/dist/queue.d.ts +20 -0
- package/dist/queue.js +94 -0
- package/dist/queue.js.map +1 -0
- package/dist/say.d.ts +2 -0
- package/dist/say.js +4 -0
- package/dist/say.js.map +1 -0
- package/dist/serve.d.ts +10 -0
- package/dist/serve.js +85 -0
- package/dist/serve.js.map +1 -0
- package/dist/session.d.ts +39 -0
- package/dist/session.js +144 -0
- package/dist/session.js.map +1 -0
- package/dist/settings.d.ts +10 -0
- package/dist/settings.js +92 -0
- package/dist/settings.js.map +1 -0
- package/dist/signals.d.ts +5 -0
- package/dist/signals.js +13 -0
- package/dist/signals.js.map +1 -0
- package/dist/skills.d.ts +4 -0
- package/dist/skills.js +51 -0
- package/dist/skills.js.map +1 -0
- package/dist/status-shape.d.ts +53 -0
- package/dist/status-shape.js +3 -0
- package/dist/status-shape.js.map +1 -0
- package/dist/status.d.ts +23 -0
- package/dist/status.js +56 -0
- package/dist/status.js.map +1 -0
- package/dist/tracker.d.ts +56 -0
- package/dist/tracker.js +12 -0
- package/dist/tracker.js.map +1 -0
- package/dist/workflow.d.ts +33 -0
- package/dist/workflow.js +53 -0
- package/dist/workflow.js.map +1 -0
- package/dist/worktree.d.ts +44 -0
- package/dist/worktree.js +193 -0
- package/dist/worktree.js.map +1 -0
- package/docs/ticket-contract.md +95 -0
- package/package.json +74 -5
- package/plugin/nightjar-status/.claude-plugin/plugin.json +5 -0
- package/plugin/nightjar-status/hooks/format.ts +48 -0
- package/plugin/nightjar-status/hooks/hooks.json +1 -0
- package/plugin/nightjar-status/hooks/register.ts +51 -0
- package/schema/factory.schema.json +437 -0
- package/skills/nightjar-feature/SKILL.md +73 -0
- package/src/status-shape.ts +44 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class ContractRefusal extends Error {
|
|
2
|
+
}
|
|
3
|
+
export interface CaseResult {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly ok: boolean;
|
|
6
|
+
readonly error?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SuiteResult {
|
|
9
|
+
readonly title: string;
|
|
10
|
+
readonly results: readonly CaseResult[];
|
|
11
|
+
}
|
|
12
|
+
export interface Report {
|
|
13
|
+
readonly suites: readonly SuiteResult[];
|
|
14
|
+
readonly total: number;
|
|
15
|
+
readonly failed: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function runContract(exports: Record<string, unknown>): Promise<Report>;
|
|
18
|
+
export declare function formatReport(report: Report): string;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { codeHostContract } from './code-host.js';
|
|
2
|
+
import { canCreate } from '../tracker.js';
|
|
3
|
+
import { featureWriterContract } from './feature-writer.js';
|
|
4
|
+
import { trackerContract } from './tracker.js';
|
|
5
|
+
import { why } from '../say.js';
|
|
6
|
+
// A module exports the harnesses of the Adapters it wants checked.
|
|
7
|
+
export class ContractRefusal extends Error {
|
|
8
|
+
}
|
|
9
|
+
async function runSuite(title, cases, harness) {
|
|
10
|
+
const results = [];
|
|
11
|
+
for (const c of cases) {
|
|
12
|
+
try {
|
|
13
|
+
await c.run(harness);
|
|
14
|
+
results.push({ name: c.name, ok: true });
|
|
15
|
+
}
|
|
16
|
+
catch (fault) {
|
|
17
|
+
results.push({
|
|
18
|
+
name: c.name,
|
|
19
|
+
ok: false,
|
|
20
|
+
error: why(fault)
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { title, results };
|
|
25
|
+
}
|
|
26
|
+
function harnessOf(exports, name) {
|
|
27
|
+
const found = exports[name];
|
|
28
|
+
if (found !== undefined && typeof found !== 'function') {
|
|
29
|
+
throw new ContractRefusal(`exports ${name}, which is not a function`);
|
|
30
|
+
}
|
|
31
|
+
return found;
|
|
32
|
+
}
|
|
33
|
+
// A harness that cannot build a Tracker over an empty world has failed every case already, so it is asked nothing more.
|
|
34
|
+
async function makesFeatures(harness) {
|
|
35
|
+
let subject;
|
|
36
|
+
try {
|
|
37
|
+
subject = await harness({ person: 'ann', trusted: ['ann'], items: [] });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
return canCreate(subject.tracker);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await subject.close?.();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// The creation suite runs too when the Tracker makes Features.
|
|
50
|
+
export async function runContract(exports) {
|
|
51
|
+
const tracker = harnessOf(exports, 'trackerHarness');
|
|
52
|
+
const codeHost = harnessOf(exports, 'codeHostHarness');
|
|
53
|
+
if (tracker === undefined && codeHost === undefined) {
|
|
54
|
+
throw new ContractRefusal('exports neither trackerHarness nor codeHostHarness');
|
|
55
|
+
}
|
|
56
|
+
const suites = [];
|
|
57
|
+
if (tracker !== undefined) {
|
|
58
|
+
suites.push(await runSuite('Tracker', trackerContract, tracker));
|
|
59
|
+
if (await makesFeatures(tracker)) {
|
|
60
|
+
suites.push(await runSuite('Tracker creation', featureWriterContract, tracker));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (codeHost !== undefined) {
|
|
64
|
+
suites.push(await runSuite('Code host', codeHostContract, codeHost));
|
|
65
|
+
}
|
|
66
|
+
const all = suites.flatMap((s) => s.results);
|
|
67
|
+
return { suites, total: all.length, failed: all.filter((r) => !r.ok).length };
|
|
68
|
+
}
|
|
69
|
+
const indent = (text, by) => text
|
|
70
|
+
.split('\n')
|
|
71
|
+
.map((line) => `${by}${line}`.trimEnd())
|
|
72
|
+
.join('\n');
|
|
73
|
+
export function formatReport(report) {
|
|
74
|
+
const lines = [];
|
|
75
|
+
for (const suite of report.suites) {
|
|
76
|
+
lines.push(`${suite.title} contract`);
|
|
77
|
+
for (const r of suite.results) {
|
|
78
|
+
lines.push(` ${r.ok ? 'ok ' : 'FAIL'} ${r.name}`);
|
|
79
|
+
if (r.error !== undefined)
|
|
80
|
+
lines.push(indent(r.error.trim(), ' '));
|
|
81
|
+
}
|
|
82
|
+
lines.push('');
|
|
83
|
+
}
|
|
84
|
+
lines.push(report.failed === 0
|
|
85
|
+
? `All ${String(report.total)} behaviours pass.`
|
|
86
|
+
: `${String(report.failed)} of ${String(report.total)} behaviours fail.`);
|
|
87
|
+
return lines.join('\n');
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/contract/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Signal } from '../signals.js';
|
|
2
|
+
import type { ItemId, Tracker } from '../tracker.js';
|
|
3
|
+
import type { ContractCase } from './case.js';
|
|
4
|
+
export interface WorldComment {
|
|
5
|
+
readonly author: string;
|
|
6
|
+
readonly body: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WorldItem {
|
|
9
|
+
readonly key: string;
|
|
10
|
+
readonly title: string;
|
|
11
|
+
readonly body?: string;
|
|
12
|
+
readonly open?: boolean;
|
|
13
|
+
readonly assignees?: readonly string[];
|
|
14
|
+
readonly signals?: readonly Signal[];
|
|
15
|
+
readonly children?: readonly string[];
|
|
16
|
+
readonly blockedBy?: readonly string[];
|
|
17
|
+
readonly comments?: readonly WorldComment[];
|
|
18
|
+
}
|
|
19
|
+
export interface TrackerWorld {
|
|
20
|
+
readonly person: string;
|
|
21
|
+
readonly trusted: readonly string[];
|
|
22
|
+
readonly items: readonly WorldItem[];
|
|
23
|
+
}
|
|
24
|
+
export interface TrackerSubject {
|
|
25
|
+
readonly tracker: Tracker;
|
|
26
|
+
readonly id: (key: string) => ItemId;
|
|
27
|
+
readonly close?: () => Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export type TrackerHarness = (world: TrackerWorld) => Promise<TrackerSubject>;
|
|
30
|
+
export declare const trackerContract: readonly ContractCase<TrackerHarness>[];
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// The Tracker contract (docs/adr/0001): what every Tracker Adapter must do, fake, built in or a repo's own.
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { SIGNALS } from '../signals.js';
|
|
4
|
+
const ANN = 'ann';
|
|
5
|
+
function given(world) {
|
|
6
|
+
return { person: ANN, trusted: [ANN], items: [], ...world };
|
|
7
|
+
}
|
|
8
|
+
function trackerCase(name, world, check) {
|
|
9
|
+
return {
|
|
10
|
+
name,
|
|
11
|
+
run: async (harness) => {
|
|
12
|
+
const subject = await harness(world);
|
|
13
|
+
try {
|
|
14
|
+
await check(subject);
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
await subject.close?.();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export const trackerContract = [
|
|
23
|
+
trackerCase('names the signed-in person', given({ person: 'ann' }), async ({ tracker }) => {
|
|
24
|
+
assert.equal(await tracker.me(), 'ann');
|
|
25
|
+
}),
|
|
26
|
+
trackerCase('lists the open Features assigned to a person that carry the Go, oldest first', given({
|
|
27
|
+
items: [
|
|
28
|
+
{ key: 'first', title: 'First', assignees: [ANN], signals: ['go'], children: ['a'] },
|
|
29
|
+
{ key: 'theirs', title: 'Theirs', assignees: ['bob'], signals: ['go'], children: ['b'] },
|
|
30
|
+
{ key: 'no-go', title: 'No Go', assignees: [ANN], signals: ['ready'], children: ['c'] },
|
|
31
|
+
{
|
|
32
|
+
key: 'closed',
|
|
33
|
+
title: 'Closed',
|
|
34
|
+
open: false,
|
|
35
|
+
assignees: [ANN],
|
|
36
|
+
signals: ['go'],
|
|
37
|
+
children: ['d']
|
|
38
|
+
},
|
|
39
|
+
// one assignee each, as an Azure DevOps work item has
|
|
40
|
+
{
|
|
41
|
+
key: 'second',
|
|
42
|
+
title: 'Second',
|
|
43
|
+
body: 'The spec.',
|
|
44
|
+
assignees: [ANN],
|
|
45
|
+
signals: ['go'],
|
|
46
|
+
children: ['e']
|
|
47
|
+
},
|
|
48
|
+
...['a', 'b', 'c', 'd', 'e'].map((key) => ({ key, title: `Ticket ${key}` }))
|
|
49
|
+
]
|
|
50
|
+
}), async ({ tracker, id }) => {
|
|
51
|
+
assert.deepEqual(await tracker.assignedFeatures(ANN), [
|
|
52
|
+
{ id: id('first'), title: 'First', body: '' },
|
|
53
|
+
{ id: id('second'), title: 'Second', body: 'The spec.' }
|
|
54
|
+
]);
|
|
55
|
+
assert.deepEqual((await tracker.assignedFeatures('bob')).map((f) => f.id), [id('theirs')]);
|
|
56
|
+
}),
|
|
57
|
+
trackerCase('reads a Feature with its title and body', given({
|
|
58
|
+
items: [
|
|
59
|
+
{ key: 'spec', title: 'A spec', body: 'What to build.\n\n- [ ] it works', children: ['a'] },
|
|
60
|
+
{ key: 'bare', title: 'No body', children: ['a'] },
|
|
61
|
+
{ key: 'a', title: 'Ticket a' }
|
|
62
|
+
]
|
|
63
|
+
}), async ({ tracker, id }) => {
|
|
64
|
+
assert.deepEqual(await tracker.feature(id('spec')), {
|
|
65
|
+
id: id('spec'),
|
|
66
|
+
title: 'A spec',
|
|
67
|
+
body: 'What to build.\n\n- [ ] it works'
|
|
68
|
+
});
|
|
69
|
+
assert.deepEqual(await tracker.feature(id('bare')), {
|
|
70
|
+
id: id('bare'),
|
|
71
|
+
title: 'No body',
|
|
72
|
+
body: ''
|
|
73
|
+
});
|
|
74
|
+
}),
|
|
75
|
+
trackerCase('says who a Feature is assigned to and which Signals it carries', given({
|
|
76
|
+
items: [
|
|
77
|
+
{ key: 'mine', title: 'Mine', assignees: [ANN], signals: ['go'], children: ['a'] },
|
|
78
|
+
{ key: 'theirs', title: 'Theirs', assignees: ['bob'], children: ['a'] },
|
|
79
|
+
{ key: 'nobody', title: 'Nobody', signals: ['working'], children: ['a'] },
|
|
80
|
+
{ key: 'a', title: 'Ticket a' }
|
|
81
|
+
]
|
|
82
|
+
}), async ({ tracker, id }) => {
|
|
83
|
+
assert.deepEqual(await tracker.standing(id('mine')), {
|
|
84
|
+
assignees: [ANN],
|
|
85
|
+
signals: ['go']
|
|
86
|
+
});
|
|
87
|
+
assert.deepEqual(await tracker.standing(id('theirs')), { assignees: ['bob'], signals: [] });
|
|
88
|
+
assert.deepEqual(await tracker.standing(id('nobody')), {
|
|
89
|
+
assignees: [],
|
|
90
|
+
signals: ['working']
|
|
91
|
+
});
|
|
92
|
+
}),
|
|
93
|
+
trackerCase("reads a Feature's Tickets in its own child order, open or closed, with their Signals", given({
|
|
94
|
+
items: [
|
|
95
|
+
{ key: 'feature', title: 'Feature', children: ['c', 'a', 'b'] },
|
|
96
|
+
{ key: 'a', title: 'Ticket a', body: 'Build a.', open: false },
|
|
97
|
+
{ key: 'b', title: 'Ticket b', signals: ['ready'] },
|
|
98
|
+
{ key: 'c', title: 'Ticket c', body: '**Model:** opus', signals: ['needsInfo'] },
|
|
99
|
+
{ key: 'other', title: 'Another Feature', children: ['d'] },
|
|
100
|
+
{ key: 'd', title: 'Ticket d' }
|
|
101
|
+
]
|
|
102
|
+
}), async ({ tracker, id }) => {
|
|
103
|
+
assert.deepEqual(await tracker.tickets(id('feature')), [
|
|
104
|
+
{
|
|
105
|
+
id: id('c'),
|
|
106
|
+
title: 'Ticket c',
|
|
107
|
+
body: '**Model:** opus',
|
|
108
|
+
open: true,
|
|
109
|
+
signals: ['needsInfo'],
|
|
110
|
+
blockedBy: []
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: id('a'),
|
|
114
|
+
title: 'Ticket a',
|
|
115
|
+
body: 'Build a.',
|
|
116
|
+
open: false,
|
|
117
|
+
signals: [],
|
|
118
|
+
blockedBy: []
|
|
119
|
+
},
|
|
120
|
+
{ id: id('b'), title: 'Ticket b', body: '', open: true, signals: ['ready'], blockedBy: [] }
|
|
121
|
+
]);
|
|
122
|
+
}),
|
|
123
|
+
trackerCase('gives each Ticket the items that block it, open or closed, in this Feature or another', given({
|
|
124
|
+
items: [
|
|
125
|
+
{ key: 'feature', title: 'Feature', children: ['a', 'b', 'c'] },
|
|
126
|
+
{ key: 'a', title: 'Ticket a' },
|
|
127
|
+
{ key: 'b', title: 'Ticket b', blockedBy: ['a'] },
|
|
128
|
+
{ key: 'c', title: 'Ticket c', blockedBy: ['elsewhere', 'a'] },
|
|
129
|
+
{ key: 'other', title: 'Another Feature', children: ['elsewhere'] },
|
|
130
|
+
{ key: 'elsewhere', title: 'Ticket elsewhere', open: false }
|
|
131
|
+
]
|
|
132
|
+
}), async ({ tracker, id }) => {
|
|
133
|
+
const tickets = await tracker.tickets(id('feature'));
|
|
134
|
+
assert.deepEqual(tickets.map((t) => ({
|
|
135
|
+
id: t.id,
|
|
136
|
+
blockedBy: [...t.blockedBy].sort((x, y) => x.id.localeCompare(y.id))
|
|
137
|
+
})), [
|
|
138
|
+
{ id: id('a'), blockedBy: [] },
|
|
139
|
+
{ id: id('b'), blockedBy: [{ id: id('a'), open: true }] },
|
|
140
|
+
{
|
|
141
|
+
id: id('c'),
|
|
142
|
+
blockedBy: [
|
|
143
|
+
{ id: id('a'), open: true },
|
|
144
|
+
{ id: id('elsewhere'), open: false }
|
|
145
|
+
].sort((x, y) => x.id.localeCompare(y.id))
|
|
146
|
+
}
|
|
147
|
+
]);
|
|
148
|
+
}),
|
|
149
|
+
trackerCase('reads the comments on a Feature or Ticket oldest first, each trusted only if its author is', given({
|
|
150
|
+
trusted: [ANN, 'cat'],
|
|
151
|
+
items: [
|
|
152
|
+
{
|
|
153
|
+
key: 'feature',
|
|
154
|
+
title: 'Feature',
|
|
155
|
+
children: ['a', 'b'],
|
|
156
|
+
comments: [
|
|
157
|
+
{ author: ANN, body: 'First' },
|
|
158
|
+
{ author: 'bob', body: 'Second' },
|
|
159
|
+
{ author: 'cat', body: 'Third' },
|
|
160
|
+
{ author: ANN, body: 'Fourth' }
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
{ key: 'a', title: 'Ticket a', comments: [{ author: 'bob', body: 'Do it my way.' }] },
|
|
164
|
+
{ key: 'b', title: 'Ticket b' }
|
|
165
|
+
]
|
|
166
|
+
}), async ({ tracker, id }) => {
|
|
167
|
+
const onFeature = await tracker.comments(id('feature'));
|
|
168
|
+
assert.deepEqual(onFeature.map((c) => [c.author, c.body, c.trusted]), [
|
|
169
|
+
[ANN, 'First', true],
|
|
170
|
+
['bob', 'Second', false],
|
|
171
|
+
['cat', 'Third', true],
|
|
172
|
+
[ANN, 'Fourth', true]
|
|
173
|
+
]);
|
|
174
|
+
const times = onFeature.map((c) => Date.parse(c.at));
|
|
175
|
+
assert.ok(times.every((t, i) => !Number.isNaN(t) && t >= (times[i - 1] ?? t)), `each comment's time is a date, none before the one above it: ${onFeature.map((c) => c.at).join(', ')}`);
|
|
176
|
+
assert.deepEqual((await tracker.comments(id('a'))).map((c) => [c.author, c.body, c.trusted]), [['bob', 'Do it my way.', false]]);
|
|
177
|
+
assert.deepEqual(await tracker.comments(id('b')), []);
|
|
178
|
+
}),
|
|
179
|
+
trackerCase('adds each Signal to a Ticket as a mark of its own', given({
|
|
180
|
+
items: [
|
|
181
|
+
{ key: 'feature', title: 'Feature', children: [...SIGNALS] },
|
|
182
|
+
...SIGNALS.map((s) => ({ key: s, title: `Ticket ${s}` }))
|
|
183
|
+
]
|
|
184
|
+
}), async ({ tracker, id }) => {
|
|
185
|
+
for (const s of SIGNALS)
|
|
186
|
+
await tracker.addSignal(id(s), s);
|
|
187
|
+
assert.deepEqual((await tracker.tickets(id('feature'))).map((t) => t.signals), SIGNALS.map((s) => [s]));
|
|
188
|
+
}),
|
|
189
|
+
trackerCase('keeps a Signal added twice once, takes one off, and takes off one the item lacks without a fault', given({
|
|
190
|
+
items: [
|
|
191
|
+
{ key: 'feature', title: 'Feature', children: ['a'] },
|
|
192
|
+
{ key: 'a', title: 'Ticket a', signals: ['ready'] }
|
|
193
|
+
]
|
|
194
|
+
}), async ({ tracker, id }) => {
|
|
195
|
+
const signals = async () => [...((await tracker.tickets(id('feature')))[0]?.signals ?? [])].sort();
|
|
196
|
+
await tracker.addSignal(id('a'), 'working');
|
|
197
|
+
await tracker.addSignal(id('a'), 'working');
|
|
198
|
+
assert.deepEqual(await signals(), ['ready', 'working']);
|
|
199
|
+
await tracker.removeSignal(id('a'), 'ready');
|
|
200
|
+
assert.deepEqual(await signals(), ['working']);
|
|
201
|
+
await tracker.removeSignal(id('a'), 'needsInfo');
|
|
202
|
+
assert.deepEqual(await signals(), ['working']);
|
|
203
|
+
}),
|
|
204
|
+
trackerCase('gives a Feature the Go and takes it off again', given({
|
|
205
|
+
items: [
|
|
206
|
+
{ key: 'feature', title: 'Feature', assignees: [ANN], children: ['a'] },
|
|
207
|
+
{ key: 'a', title: 'Ticket a' }
|
|
208
|
+
]
|
|
209
|
+
}), async ({ tracker, id }) => {
|
|
210
|
+
const listed = async () => (await tracker.assignedFeatures(ANN)).map((f) => f.id);
|
|
211
|
+
assert.deepEqual(await listed(), []);
|
|
212
|
+
await tracker.addSignal(id('feature'), 'go');
|
|
213
|
+
assert.deepEqual(await listed(), [id('feature')]);
|
|
214
|
+
await tracker.removeSignal(id('feature'), 'go');
|
|
215
|
+
assert.deepEqual(await listed(), []);
|
|
216
|
+
}),
|
|
217
|
+
trackerCase('comments as the signed-in person, below the comments already there, with the body unchanged', given({
|
|
218
|
+
items: [
|
|
219
|
+
{ key: 'feature', title: 'Feature', children: ['a'] },
|
|
220
|
+
{ key: 'a', title: 'Ticket a', comments: [{ author: 'bob', body: 'Before.' }] }
|
|
221
|
+
]
|
|
222
|
+
}), async ({ tracker, id }) => {
|
|
223
|
+
const body = 'Two questions:\n\n1. "Which" one?\n2. `$(rm -rf /)` @here & <b>this</b>';
|
|
224
|
+
await tracker.comment(id('a'), body);
|
|
225
|
+
await tracker.comment(id('feature'), 'Built nothing.');
|
|
226
|
+
const me = await tracker.me();
|
|
227
|
+
assert.deepEqual((await tracker.comments(id('a'))).map((c) => [c.author, c.body, c.trusted]), [
|
|
228
|
+
['bob', 'Before.', false],
|
|
229
|
+
[me, body, true]
|
|
230
|
+
]);
|
|
231
|
+
assert.deepEqual((await tracker.comments(id('feature'))).map((c) => [c.author, c.body]), [[me, 'Built nothing.']]);
|
|
232
|
+
}),
|
|
233
|
+
trackerCase('gives each Ticket a reference of its own that names its id, for the Code host to place', given({
|
|
234
|
+
items: [
|
|
235
|
+
{ key: 'feature', title: 'Feature', children: ['a', 'b'] },
|
|
236
|
+
{ key: 'a', title: 'Ticket a' },
|
|
237
|
+
{ key: 'b', title: 'Ticket b' }
|
|
238
|
+
]
|
|
239
|
+
}), ({ tracker, id }) => {
|
|
240
|
+
const a = tracker.reference(id('a'));
|
|
241
|
+
const b = tracker.reference(id('b'));
|
|
242
|
+
assert.equal(a.id, id('a'));
|
|
243
|
+
assert.equal(b.id, id('b'));
|
|
244
|
+
assert.ok(a.text.includes(id('a')), `${a.text} names ${id('a')}`);
|
|
245
|
+
assert.notEqual(a.text, b.text);
|
|
246
|
+
assert.deepEqual(tracker.reference(id('a')), a);
|
|
247
|
+
return Promise.resolve();
|
|
248
|
+
})
|
|
249
|
+
];
|
|
250
|
+
//# sourceMappingURL=tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/contract/tracker.ts"],"names":[],"mappings":"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"}
|
package/dist/create.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type FeaturePlan } from './feature-file.js';
|
|
2
|
+
import type { FeatureWriter, ItemId, Tracker } from './tracker.js';
|
|
3
|
+
export declare const CREATE_USAGE = "usage: nightjar create [--dry-run] FILE\n\n FILE a Feature and its Tickets as Markdown, in the shape of docs/ticket-contract.md\n --dry-run read the file and say what it would make, making nothing";
|
|
4
|
+
export interface Made {
|
|
5
|
+
readonly feature: ItemId;
|
|
6
|
+
readonly tickets: readonly ItemId[];
|
|
7
|
+
}
|
|
8
|
+
export declare function makeFeature(tracker: Tracker & FeatureWriter, plan: FeaturePlan, say: (line: string) => void): Promise<Made>;
|
|
9
|
+
export declare function runCreateCommand(argv: readonly string[]): Promise<number>;
|
package/dist/create.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// `nightjar create FILE`: the Feature gets no Signal, so nothing is built until a person gives it the Go.
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { makeAdapters } from './adapters.js';
|
|
5
|
+
import { ticketLine } from './build.js';
|
|
6
|
+
import { ConfigError, loadConfig } from './config.js';
|
|
7
|
+
import { FeatureFileError, readFeatureFile } from './feature-file.js';
|
|
8
|
+
import { run } from './git.js';
|
|
9
|
+
import { say, why } from './say.js';
|
|
10
|
+
export const CREATE_USAGE = `usage: nightjar create [--dry-run] FILE
|
|
11
|
+
|
|
12
|
+
FILE a Feature and its Tickets as Markdown, in the shape of docs/ticket-contract.md
|
|
13
|
+
--dry-run read the file and say what it would make, making nothing`;
|
|
14
|
+
const listed = (texts) => texts.length < 2 ? texts.join('') : `${texts.slice(0, -1).join(', ')} and ${texts.at(-1) ?? ''}`;
|
|
15
|
+
// Each Ticket is linked to its blockers before it is marked ready, so it is never ready half made.
|
|
16
|
+
export async function makeFeature(tracker, plan, say) {
|
|
17
|
+
const ref = (id) => tracker.reference(id).text;
|
|
18
|
+
const made = [];
|
|
19
|
+
try {
|
|
20
|
+
const feature = await tracker.createFeature(plan.feature);
|
|
21
|
+
made.push(feature);
|
|
22
|
+
say(`made the Feature ${ref(feature)} ${plan.feature.title}`);
|
|
23
|
+
const ids = new Map();
|
|
24
|
+
for (const ticket of plan.tickets) {
|
|
25
|
+
const id = await tracker.createTicket(feature, ticket);
|
|
26
|
+
made.push(id);
|
|
27
|
+
ids.set(ticket.number, id);
|
|
28
|
+
const blockers = ticket.blockedBy.flatMap((n) => ids.get(n) ?? []);
|
|
29
|
+
for (const blocker of blockers)
|
|
30
|
+
await tracker.block(id, blocker);
|
|
31
|
+
await tracker.addSignal(id, 'ready');
|
|
32
|
+
const blocked = blockers.length === 0 ? '' : `, blocked by ${listed(blockers.map(ref))}`;
|
|
33
|
+
say(`made Ticket ${String(ticket.number)} as ${ref(id)} ${ticket.title}${blocked}, ready`);
|
|
34
|
+
}
|
|
35
|
+
return { feature, tickets: made.slice(1) };
|
|
36
|
+
}
|
|
37
|
+
catch (fault) {
|
|
38
|
+
const before = made.length === 0 ? 'nothing' : made.map(ref).join(', ');
|
|
39
|
+
throw new Error(`${why(fault)}; made before it: ${before}. Nothing was undone.`, {
|
|
40
|
+
cause: fault
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const refuse = (text) => {
|
|
45
|
+
console.error(`nightjar: ${text}`);
|
|
46
|
+
return 2;
|
|
47
|
+
};
|
|
48
|
+
function dryRun(plan) {
|
|
49
|
+
say(`would make the Feature ${plan.feature.title}`);
|
|
50
|
+
for (const t of plan.tickets) {
|
|
51
|
+
const model = ticketLine(t.body, 'Model');
|
|
52
|
+
const effort = ticketLine(t.body, 'Effort');
|
|
53
|
+
const runs = [model && `on ${model}`, effort && `at ${effort}`].filter(Boolean).join(' ');
|
|
54
|
+
const blockers = t.blockedBy.map((n) => `Ticket ${String(n)}`);
|
|
55
|
+
const blocked = blockers.length === 0 ? '' : `, blocked by ${listed(blockers)}`;
|
|
56
|
+
say(`would make Ticket ${String(t.number)} ${t.title}${blocked}${runs ? `, ${runs}` : ''}, ready`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// 0 when all is made, 1 when the Tracker failed part way, 2 when nothing was tried.
|
|
60
|
+
export async function runCreateCommand(argv) {
|
|
61
|
+
const dry = argv.includes('--dry-run');
|
|
62
|
+
const rest = argv.filter((a) => a !== '--dry-run');
|
|
63
|
+
const [path] = rest;
|
|
64
|
+
if (path === undefined || rest.length > 1 || path.startsWith('-')) {
|
|
65
|
+
const why = path === undefined ? 'say which file' : 'one file at a time';
|
|
66
|
+
return refuse(`${why}\n\n${CREATE_USAGE}`);
|
|
67
|
+
}
|
|
68
|
+
let plan;
|
|
69
|
+
try {
|
|
70
|
+
plan = readFeatureFile(readFileSync(resolve(path), 'utf8'));
|
|
71
|
+
}
|
|
72
|
+
catch (fault) {
|
|
73
|
+
if (!(fault instanceof FeatureFileError))
|
|
74
|
+
return refuse(`cannot read ${path}`);
|
|
75
|
+
const lines = fault.message.split('\n').map((line) => `${path}: ${line}`);
|
|
76
|
+
return refuse(lines.join('\nnightjar: '));
|
|
77
|
+
}
|
|
78
|
+
if (dry) {
|
|
79
|
+
dryRun(plan);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const env = { ...process.env, GIT_TERMINAL_PROMPT: '0' };
|
|
83
|
+
const top = await run('git', ['rev-parse', '--show-toplevel'], process.cwd(), env);
|
|
84
|
+
if (!top.ok)
|
|
85
|
+
return refuse('not inside a git checkout');
|
|
86
|
+
const root = top.out.trim();
|
|
87
|
+
let writer;
|
|
88
|
+
let go;
|
|
89
|
+
try {
|
|
90
|
+
const config = loadConfig(root);
|
|
91
|
+
go = config.signals.go;
|
|
92
|
+
writer = (await makeAdapters(config, root, env)).writer;
|
|
93
|
+
}
|
|
94
|
+
catch (fault) {
|
|
95
|
+
if (fault instanceof ConfigError)
|
|
96
|
+
return refuse(fault.message);
|
|
97
|
+
throw fault;
|
|
98
|
+
}
|
|
99
|
+
if (typeof writer === 'string')
|
|
100
|
+
return refuse(writer);
|
|
101
|
+
try {
|
|
102
|
+
const made = await makeFeature(writer, plan, say);
|
|
103
|
+
const ref = writer.reference(made.feature).text;
|
|
104
|
+
say(`${ref} carries no Signal: assign it to yourself and give it the Go (${go}) to build it.`);
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
catch (fault) {
|
|
108
|
+
console.error(`nightjar: ${why(fault)}`);
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
|
package/dist/doctor.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CheckOptions, type Line } from './checks.js';
|
|
2
|
+
export declare function printLines(lines: readonly Line[]): void;
|
|
3
|
+
export declare const failures: (lines: readonly Line[]) => number;
|
|
4
|
+
export declare function runDoctor(options: Omit<CheckOptions, 'failFast'>): Promise<number>;
|
package/dist/doctor.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// `nightjar doctor`: runs every check, says how to fix each that fails, and lists what it would build.
|
|
2
|
+
import { checkMachine } from './checks.js';
|
|
3
|
+
import { dryRun } from './queue.js';
|
|
4
|
+
import { say, why } from './say.js';
|
|
5
|
+
const MARKS = { ok: 'ok ', fail: 'FAIL', skip: 'skip' };
|
|
6
|
+
// Failures go to stderr, the rest to stdout; a line that wraps is indented under its name.
|
|
7
|
+
export function printLines(lines) {
|
|
8
|
+
for (const line of lines) {
|
|
9
|
+
const text = line.detail.split('\n').join('\n ');
|
|
10
|
+
const out = ` ${MARKS[line.status]} ${line.name}: ${text}`;
|
|
11
|
+
if (line.status === 'fail')
|
|
12
|
+
console.error(out);
|
|
13
|
+
else
|
|
14
|
+
console.log(out);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export const failures = (lines) => lines.filter((l) => l.status === 'fail').length;
|
|
18
|
+
export async function runDoctor(options) {
|
|
19
|
+
const checked = await checkMachine({ ...options, failFast: false });
|
|
20
|
+
printLines(checked.lines);
|
|
21
|
+
const failed = failures(checked.lines);
|
|
22
|
+
if (checked.ready === null) {
|
|
23
|
+
const count = failed === 1 ? '1 check' : `${String(failed)} checks`;
|
|
24
|
+
console.error(`nightjar: ${count} failed; fix it, then run \`nightjar doctor\` again.`);
|
|
25
|
+
return 2;
|
|
26
|
+
}
|
|
27
|
+
const { adapters, assignee } = checked.ready;
|
|
28
|
+
try {
|
|
29
|
+
await dryRun({ tracker: adapters.tracker, person: assignee, say });
|
|
30
|
+
}
|
|
31
|
+
catch (fault) {
|
|
32
|
+
console.error(` FAIL Features: ${why(fault)}`);
|
|
33
|
+
return 2;
|
|
34
|
+
}
|
|
35
|
+
// a broken Workflow stops no build, but doctor says so in its code
|
|
36
|
+
if (failed > 0) {
|
|
37
|
+
console.error('nightjar: a Workflow cannot run; fix it, then run `nightjar doctor` again.');
|
|
38
|
+
return 2;
|
|
39
|
+
}
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,OAAO,EAAE,YAAY,EAAgC,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,KAAK,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAW,CAAC;AAElE,2FAA2F;AAC3F,MAAM,UAAU,UAAU,CAAC,KAAsB;IAChD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,GAAG,GAAG,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC7D,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;;YAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAsB,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;AAEpG,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAuC;IACtE,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QACpE,OAAO,CAAC,KAAK,CAAC,aAAa,KAAK,sDAAsD,CAAC,CAAC;QACxF,OAAO,CAAC,CAAC;IACV,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7C,IAAI,CAAC;QACJ,MAAM,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,qBAAqB,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,CAAC;IACV,CAAC;IACD,mEAAmE;IACnE,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;QAC5F,OAAO,CAAC,CAAC;IACV,CAAC;IACD,OAAO,CAAC,CAAC;AACV,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CodeHost, DraftRequest, Pull } from '../code-host.js';
|
|
2
|
+
import type { TicketReference } from '../tracker.js';
|
|
3
|
+
export interface FakePull extends Pull, DraftRequest {
|
|
4
|
+
readonly draft: true;
|
|
5
|
+
readonly references: readonly TicketReference[];
|
|
6
|
+
readonly comments: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export declare class FakeCodeHost implements CodeHost {
|
|
9
|
+
readonly pushes: {
|
|
10
|
+
readonly folder: string;
|
|
11
|
+
readonly branch: string;
|
|
12
|
+
}[];
|
|
13
|
+
pulls: FakePull[];
|
|
14
|
+
private change;
|
|
15
|
+
push: (folder: string, branch: string) => Promise<void>;
|
|
16
|
+
openPull: (branch: string) => Promise<Pull | null>;
|
|
17
|
+
createDraft: (request: DraftRequest) => Promise<Pull>;
|
|
18
|
+
editBody: (pull: Pull, body: string) => Promise<void>;
|
|
19
|
+
placeReferences: (pull: Pull, references: readonly TicketReference[]) => Promise<void>;
|
|
20
|
+
comment: (pull: Pull, body: string) => Promise<void>;
|
|
21
|
+
}
|