ravensight-playtest 0.2.6 → 0.2.8

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.
@@ -274,7 +274,7 @@ export async function uploadRunDir(runDir, options) {
274
274
  const {
275
275
  api, gameId, jobId, runId = null,
276
276
  includeVideo = false, includeTranscript = false,
277
- dryRun = false, force = false, only = null, allowedPaths = null,
277
+ dryRun = false, force = false, only = null, allowedPaths = null, exclude = null, excludeReason = 'excluded',
278
278
  onFile, repoRoot, fetch: fetchImpl, sleep
279
279
  } = options;
280
280
 
@@ -295,6 +295,14 @@ export async function uploadRunDir(runDir, options) {
295
295
  files = files.filter(file => wanted.has(file.path));
296
296
  }
297
297
 
298
+ if (Array.isArray(exclude) && exclude.length > 0) {
299
+ const unwanted = new Set(exclude);
300
+ for (const file of files) {
301
+ if (unwanted.has(file.path)) skipped.push({ path: file.path, reason: excludeReason });
302
+ }
303
+ files = files.filter(file => !unwanted.has(file.path));
304
+ }
305
+
298
306
  if (!force) {
299
307
  const done = await uploadedKeys(jobId, journalOptions);
300
308
  const remaining = [];
@@ -14,7 +14,10 @@ import { paths } from '../paths.js';
14
14
  * was.
15
15
  *
16
16
  * Each line is `{ at, kind, run_id, path, sha256, size, status, detail }`.
17
- * `status` is one of `queued`, `uploaded`, `failed`, `skipped`.
17
+ * `status` is one of `queued`, `uploaded`, `failed`, `skipped`, `local_edit`.
18
+ * A `local_edit` is a file the CLI changed on disk after it was delivered
19
+ * (dropped findings marked in a run's report): the delivered copy is the
20
+ * record, so the new hash counts as done and is never sent again.
18
21
  *
19
22
  * Idempotency is by sha256: a path recorded `uploaded` with the same hash is
20
23
  * not sent again, which is what makes `resume` and the manual `upload <job>`
@@ -25,9 +28,13 @@ export const STATUS = Object.freeze({
25
28
  QUEUED: 'queued',
26
29
  UPLOADED: 'uploaded',
27
30
  FAILED: 'failed',
28
- SKIPPED: 'skipped'
31
+ SKIPPED: 'skipped',
32
+ LOCAL_EDIT: 'local_edit'
29
33
  });
30
34
 
35
+ /** Statuses that mean "nothing left to send at this hash". */
36
+ const DONE = new Set([STATUS.UPLOADED, STATUS.LOCAL_EDIT]);
37
+
31
38
  /**
32
39
  * Append one entry.
33
40
  * @param {string} jobId
@@ -70,7 +77,8 @@ export async function readQueue(jobId, options = {}) {
70
77
  }
71
78
 
72
79
  /**
73
- * The set of `<runId>|<path>|<sha256>` triples already recorded as uploaded.
80
+ * The set of `<runId>|<path>|<sha256>` triples already recorded as uploaded,
81
+ * or as a local edit of a file that was.
74
82
  * The sha256 is part of the key on purpose: a corrected file at the same path
75
83
  * has a different hash and must be sent again.
76
84
  * @param {string} jobId
@@ -80,7 +88,7 @@ export async function readQueue(jobId, options = {}) {
80
88
  export async function uploadedKeys(jobId, options = {}) {
81
89
  const done = new Set();
82
90
  for (const entry of await readQueue(jobId, options)) {
83
- if (entry.status === STATUS.UPLOADED) {
91
+ if (DONE.has(entry.status)) {
84
92
  done.add(keyFor(entry.run_id || null, entry.path, entry.sha256));
85
93
  }
86
94
  }
@@ -105,7 +113,7 @@ export async function pending(jobId, options = {}) {
105
113
  for (const entry of entries) {
106
114
  if (!entry.path) continue;
107
115
  const key = keyFor(entry.run_id || null, entry.path, entry.sha256);
108
- if (entry.status === STATUS.UPLOADED) done.add(key);
116
+ if (DONE.has(entry.status)) done.add(key);
109
117
  latest.set(key, entry);
110
118
  }
111
119
  return [...latest.entries()]