@sdods/integrations 0.7.1 → 0.8.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.
@@ -0,0 +1,150 @@
1
+ import type { Octokit } from '@octokit/rest';
2
+ import type { EvidenceFile, IntegrationLogger, PublishedEvidence, SkippedEvidence } from './types.js';
3
+ /**
4
+ * Issue evidence committed to a branch (#82). Screenshots in an issue render inline in a private
5
+ * repository only when GitHub serves them to the reader's session; `blob/<branch>/<path>?raw=true`
6
+ * does, release assets and Actions artifacts do not.
7
+ *
8
+ * Everything goes through the git data API, so no clone is needed:
9
+ * - the branch is an orphan (a root commit with only a README) created on first use;
10
+ * - one commit per run adds `runs/<runId>/<scenario>/<file>` and updates `runs/index.json` on top of
11
+ * the current head, and the ref moves with `force: false`. When another job moved it first, GitHub
12
+ * answers 422 (not a fast-forward); the tree and commit are rebuilt on the new head and retried.
13
+ * - `prune` rewrites the branch as a new orphan commit holding only the runs to keep.
14
+ *
15
+ * Traces are never passed here: they carry credentials (#101).
16
+ */
17
+ export declare const EVIDENCE_INDEX = "runs/index.json";
18
+ export interface EvidenceIndex {
19
+ runs: Record<string, {
20
+ uploadedAt: string;
21
+ project?: string;
22
+ files: number;
23
+ bytes: number;
24
+ }>;
25
+ }
26
+ export interface EvidenceCaps {
27
+ maxFileBytes: number;
28
+ maxRunBytes: number;
29
+ }
30
+ export interface GitHubBranchEvidenceOptions {
31
+ octokit: Octokit;
32
+ owner: string;
33
+ repo: string;
34
+ branch: string;
35
+ /** web origin for links, e.g. `https://github.com` */
36
+ serverUrl?: string;
37
+ logger?: IntegrationLogger;
38
+ /** bounded attempts for the ref update (default 5) */
39
+ maxAttempts?: number;
40
+ sleep?: (ms: number) => Promise<void>;
41
+ now?: () => Date;
42
+ /** uploads log a reminder to prune when the branch holds runs older than this */
43
+ retainDays?: number;
44
+ }
45
+ export interface PruneOptions {
46
+ olderThanMs: number;
47
+ dryRun?: boolean;
48
+ }
49
+ export interface PruneResult {
50
+ branch: string;
51
+ removed: Array<{
52
+ runId: string;
53
+ uploadedAt: string;
54
+ }>;
55
+ kept: string[];
56
+ /** run directories missing from `runs/index.json`; kept, since their age is unknown */
57
+ unknown: string[];
58
+ commitSha?: string;
59
+ dryRun: boolean;
60
+ }
61
+ export interface EvidenceCheckResult {
62
+ ok: boolean;
63
+ detail: string;
64
+ }
65
+ /**
66
+ * Apply the size caps. Screenshots go first, then GIF previews, then videos, so a few large
67
+ * videos never crowd out the images that render inline.
68
+ */
69
+ export declare function planEvidence(files: EvidenceFile[], caps: EvidenceCaps): {
70
+ upload: EvidenceFile[];
71
+ skipped: SkippedEvidence[];
72
+ };
73
+ export declare class GitHubBranchEvidence {
74
+ readonly owner: string;
75
+ readonly repo: string;
76
+ readonly branch: string;
77
+ private readonly octokit;
78
+ private readonly serverUrl;
79
+ private readonly maxAttempts;
80
+ private readonly sleep;
81
+ private readonly now;
82
+ /** replaced per run with the integration context's logger */
83
+ logger?: IntegrationLogger;
84
+ private readonly retainDays?;
85
+ constructor(opts: GitHubBranchEvidenceOptions);
86
+ get fullName(): string;
87
+ /** A link that renders inline for anyone who can read the repository. */
88
+ url(path: string): string;
89
+ /** Commit a run's files in one commit and return their links. Files over the caps are skipped. */
90
+ publishRun(run: {
91
+ id: string;
92
+ projectSlug?: string;
93
+ }, files: EvidenceFile[], caps: EvidenceCaps): Promise<PublishedEvidence>;
94
+ private staleRuns;
95
+ /**
96
+ * Build a commit on the current head and move the ref with `force: false`. A 422 means another
97
+ * job moved the branch in between: re-read the head and rebuild, with backoff, a bounded number
98
+ * of times.
99
+ */
100
+ private commitWithRetry;
101
+ /** The branch head, creating the orphan branch when it does not exist. */
102
+ ensureBranch(): Promise<string>;
103
+ private defaultBranch?;
104
+ /** The repository's default branch, read once. */
105
+ private repoDefaultBranch;
106
+ private defaultBranchMessage;
107
+ /** Uploads and prune never touch the default branch: prune would erase its history. */
108
+ private assertNotDefaultBranch;
109
+ /**
110
+ * Prune force-rewrites the branch, so it only runs on a branch SDODS created: one whose root
111
+ * README.md is the one written with the orphan commit.
112
+ */
113
+ private assertCreatedBySdods;
114
+ private isEmptyRepo;
115
+ private emptyRepoMessage;
116
+ private headSha;
117
+ private blob;
118
+ /** Root entries, `runs/` entries and the parsed index of a tree. */
119
+ private readLayout;
120
+ private listTree;
121
+ /**
122
+ * Rewrite the branch as a new orphan commit without the runs uploaded before the cutoff.
123
+ * Kept run directories are reused by tree sha, so nothing is uploaded again. Just before the
124
+ * force update the head is compared with the one the new tree was built from, and the rewrite is
125
+ * rebuilt when it moved. That narrows the race with a concurrent upload but cannot close it: a
126
+ * force update has no compare-and-swap, so a run pushed between that check and the update is
127
+ * lost. Prune when CI is quiet. GitHub garbage-collects the dropped objects later, and issues
128
+ * that linked them stop rendering those images.
129
+ */
130
+ prune(opts: PruneOptions): Promise<PruneResult>;
131
+ /**
132
+ * For `sdods integrations test`: the token can push to the evidence repository, and the branch
133
+ * exists or will be created on the first upload. Nothing is created here, except that a token
134
+ * whose repository response has no `permissions` is checked by writing one unreferenced blob.
135
+ */
136
+ check(issueRepoPrivate?: boolean): Promise<EvidenceCheckResult>;
137
+ }
138
+ /**
139
+ * `90min`, `36h`, `14d`, `2w` or a bare number of days → milliseconds. A bare `m` is refused: it
140
+ * reads as months to some people and minutes to others, and `3m` meant as months prunes nearly
141
+ * everything.
142
+ */
143
+ export declare function parseAge(text: string): number;
144
+ /** A path segment safe in a git tree and a URL. */
145
+ export declare function safeSegment(text: string): string;
146
+ /** `runs/<id>/<scenario-slug>/`: readable, and unique through the fingerprint. */
147
+ export declare function scenarioSlug(scenarioName: string, fingerprint: string): string;
148
+ export declare function evidenceKey(fingerprint: string, relPath: string): string;
149
+ export declare function formatBytes(bytes: number): string;
150
+ //# sourceMappingURL=evidence.d.ts.map