@saptools/service-flow 0.1.68 → 0.1.70
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/CHANGELOG.md +14 -0
- package/README.md +11 -5
- package/TECHNICAL-NOTE.md +13 -0
- package/dist/{chunk-AEM4JY22.js → chunk-GSLFY6J2.js} +6986 -5503
- package/dist/chunk-GSLFY6J2.js.map +1 -0
- package/dist/cli.js +334 -122
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/{002-doctor-lifecycle.ts → doctor-lifecycle.ts} +1 -1
- package/src/cli/{001-doctor-projection.ts → doctor-projection.ts} +1 -1
- package/src/cli/doctor.ts +5 -5
- package/src/cli/index-summary.ts +22 -0
- package/src/cli.ts +155 -91
- package/src/db/{009-binding-fact-semantics.ts → binding-fact-semantics.ts} +6 -1
- package/src/db/binding-helper-provenance.ts +17 -0
- package/src/db/{012-binding-reference-proof.ts → binding-reference-proof.ts} +4 -0
- package/src/db/{000-call-fact-repository.ts → call-fact-repository.ts} +49 -23
- package/src/db/{003-current-fact-semantics.ts → current-fact-semantics.ts} +5 -4
- package/src/db/{001-fact-lifecycle.ts → fact-lifecycle.ts} +3 -3
- package/src/db/index-publication-failure.ts +91 -0
- package/src/db/{007-package-fact-semantics.ts → package-fact-semantics.ts} +6 -6
- package/src/db/{010-package-symbol-surface-semantics.ts → package-symbol-surface-semantics.ts} +2 -2
- package/src/db/{004-package-target-invalidation.ts → package-target-invalidation.ts} +11 -1
- package/src/db/{008-relative-fact-semantics.ts → relative-fact-semantics.ts} +9 -6
- package/src/db/{006-relative-symbol-resolution.ts → relative-symbol-resolution.ts} +28 -7
- package/src/db/repositories.ts +24 -7
- package/src/db/{011-symbol-call-semantics.ts → symbol-call-semantics.ts} +1 -1
- package/src/index.ts +3 -3
- package/src/indexer/cds-extension-resolver.ts +27 -3
- package/src/indexer/repository-indexer.ts +70 -9
- package/src/indexer/workspace-indexer.ts +142 -30
- package/src/linker/call-edge-insertion.ts +568 -0
- package/src/linker/{002-call-evidence.ts → call-evidence.ts} +2 -2
- package/src/linker/cross-repo-linker.ts +6 -169
- package/src/linker/dynamic-edge-resolver.ts +1 -1
- package/src/linker/{004-event-subscription-handler-linker.ts → event-subscription-handler-linker.ts} +32 -11
- package/src/linker/event-template-link.ts +72 -0
- package/src/linker/external-http-target.ts +1 -1
- package/src/linker/helper-package-linker.ts +1 -1
- package/src/linker/{000-implementation-candidates.ts → implementation-candidates.ts} +1 -1
- package/src/linker/{001-implementation-evidence-projection.ts → implementation-evidence-projection.ts} +1 -1
- package/src/linker/odata-path-normalizer.ts +1 -1
- package/src/linker/{005-odata-path-structure.ts → odata-path-structure.ts} +1 -1
- package/src/linker/{003-package-import-symbol-resolver.ts → package-import-symbol-resolver.ts} +3 -3
- package/src/linker/service-resolver.ts +2 -2
- package/src/output/{001-compact-json-output.ts → compact-json-output.ts} +1 -1
- package/src/parsers/{006-binding-identity.ts → binding-identity.ts} +9 -4
- package/src/parsers/{011-binding-lexical-scope.ts → binding-lexical-scope.ts} +1 -1
- package/src/parsers/{021-binding-visibility.ts → binding-visibility.ts} +18 -2
- package/src/parsers/{000-direct-query-execution.ts → direct-query-execution.ts} +11 -0
- package/src/parsers/{005-event-subscription-facts.ts → event-subscription-facts.ts} +2 -2
- package/src/parsers/{016-local-symbol-reference.ts → local-symbol-reference.ts} +2 -2
- package/src/parsers/operation-path-analysis.ts +1 -1
- package/src/parsers/outbound-call-classifier.ts +692 -0
- package/src/parsers/outbound-call-parser.ts +146 -509
- package/src/parsers/outbound-expression-analysis.ts +700 -0
- package/src/parsers/{018-package-commonjs-syntax.ts → package-commonjs-syntax.ts} +1 -1
- package/src/parsers/{012-package-fact-contract.ts → package-fact-contract.ts} +3 -3
- package/src/parsers/{010-package-public-surface-analysis.ts → package-public-surface-analysis.ts} +2 -2
- package/src/parsers/{003-package-public-surface.ts → package-public-surface.ts} +3 -3
- package/src/parsers/{008-package-surface-publication.ts → package-surface-publication.ts} +1 -1
- package/src/parsers/{001-query-entity-resolution.ts → query-entity-resolution.ts} +1 -1
- package/src/parsers/{015-service-binding-collector.ts → service-binding-collector.ts} +3 -3
- package/src/parsers/{014-service-binding-helper-flow.ts → service-binding-helper-flow.ts} +72 -6
- package/src/parsers/service-binding-parser-helpers.ts +1 -1
- package/src/parsers/service-binding-parser.ts +2 -2
- package/src/parsers/{007-source-fact-reconciliation.ts → source-fact-reconciliation.ts} +3 -3
- package/src/parsers/{020-stable-local-value.ts → stable-local-value.ts} +2 -2
- package/src/parsers/{009-symbol-call-facts.ts → symbol-call-facts.ts} +3 -3
- package/src/parsers/{017-symbol-derived-contexts.ts → symbol-derived-contexts.ts} +2 -2
- package/src/parsers/symbol-parser.ts +43 -11
- package/src/trace/{014-compact-contract.ts → compact-contract.ts} +6 -0
- package/src/trace/{021-compact-decision-normalization.ts → compact-decision-normalization.ts} +77 -11
- package/src/trace/{020-compact-field-projection.ts → compact-field-projection.ts} +77 -4
- package/src/trace/{024-compact-observation-decision.ts → compact-observation-decision.ts} +10 -5
- package/src/trace/{016-compact-projector.ts → compact-projector.ts} +6 -7
- package/src/trace/{018-compact-trace.ts → compact-trace.ts} +3 -3
- package/src/trace/{006-contextual-projection.ts → contextual-projection.ts} +1 -1
- package/src/trace/{008-contextual-runtime-state.ts → contextual-runtime-state.ts} +1 -1
- package/src/trace/{001-dynamic-identity.ts → dynamic-identity.ts} +2 -2
- package/src/trace/{003-dynamic-references.ts → dynamic-references.ts} +2 -2
- package/src/trace/dynamic-targets.ts +6 -6
- package/src/trace/event-runtime-resolution.ts +151 -0
- package/src/trace/{011-event-subscriber-traversal.ts → event-subscriber-traversal.ts} +101 -9
- package/src/trace/evidence.ts +2 -2
- package/src/trace/implementation-hints.ts +10 -7
- package/src/trace/{005-implementation-selection.ts → implementation-selection.ts} +2 -2
- package/src/trace/{007-implementation-start-diagnostic.ts → implementation-start-diagnostic.ts} +1 -0
- package/src/trace/local-call-expansion.ts +37 -0
- package/src/trace/{009-selected-handler-provenance.ts → selected-handler-provenance.ts} +1 -1
- package/src/trace/selectors.ts +2 -1
- package/src/trace/{017-trace-context.ts → trace-context.ts} +2 -2
- package/src/trace/{015-trace-edge-recorder.ts → trace-edge-recorder.ts} +62 -5
- package/src/trace/{019-trace-edge-semantics.ts → trace-edge-semantics.ts} +9 -13
- package/src/trace/trace-engine.ts +10 -10
- package/src/trace/{022-trace-fact-preflight.ts → trace-fact-preflight.ts} +2 -2
- package/src/trace/{025-trace-implementation-scope.ts → trace-implementation-scope.ts} +1 -1
- package/src/trace/{028-trace-operation-execution.ts → trace-operation-execution.ts} +10 -10
- package/src/trace/{013-trace-root-scopes.ts → trace-root-scopes.ts} +5 -6
- package/src/trace/{027-trace-scope-execution.ts → trace-scope-execution.ts} +44 -44
- package/src/trace/{029-trace-start-implementation.ts → trace-start-implementation.ts} +7 -7
- package/src/trace/{026-trace-start-scope.ts → trace-start-scope.ts} +6 -5
- package/src/trace/{010-traversal-scope.ts → traversal-scope.ts} +1 -1
- package/src/types.ts +2 -1
- package/src/version.ts +1 -1
- package/dist/chunk-AEM4JY22.js.map +0 -1
- /package/src/cli/{000-clean.ts → clean.ts} +0 -0
- /package/src/cli/{003-doctor-package-resolution.ts → doctor-package-resolution.ts} +0 -0
- /package/src/db/{002-fact-json-inventory.ts → fact-json-inventory.ts} +0 -0
- /package/src/db/{005-schema-structure.ts → schema-structure.ts} +0 -0
- /package/src/output/{000-stdout-policy.ts → stdout-policy.ts} +0 -0
- /package/src/parsers/{019-binding-assignment-targets.ts → binding-assignment-targets.ts} +0 -0
- /package/src/parsers/{013-executable-body-eligibility.ts → executable-body-eligibility.ts} +0 -0
- /package/src/parsers/{004-fact-identity.ts → fact-identity.ts} +0 -0
- /package/src/parsers/{002-symbol-import-bindings.ts → symbol-import-bindings.ts} +0 -0
- /package/src/trace/{004-dynamic-candidate-sources.ts → dynamic-candidate-sources.ts} +0 -0
- /package/src/trace/{000-dynamic-target-types.ts → dynamic-target-types.ts} +0 -0
- /package/src/trace/{023-nested-event-scopes.ts → nested-event-scopes.ts} +0 -0
- /package/src/trace/{002-trace-diagnostics.ts → trace-diagnostics.ts} +0 -0
- /package/src/trace/{012-trace-graph-lookups.ts → trace-graph-lookups.ts} +0 -0
- /package/src/utils/{000-bounded-projection.ts → bounded-projection.ts} +0 -0
- /package/src/utils/{001-placeholders.ts → placeholders.ts} +0 -0
|
@@ -27,14 +27,14 @@ import {
|
|
|
27
27
|
loadPackageJsonSnapshot,
|
|
28
28
|
} from '../parsers/package-json-parser.js';
|
|
29
29
|
import { parseServiceBindings } from '../parsers/service-binding-parser.js';
|
|
30
|
-
import { reconcileSourceFacts } from '../parsers/
|
|
30
|
+
import { reconcileSourceFacts } from '../parsers/source-fact-reconciliation.js';
|
|
31
31
|
import {
|
|
32
32
|
analyzeRepositoryPackageSurface,
|
|
33
33
|
mergePackageSymbolEvidence,
|
|
34
|
-
} from '../parsers/
|
|
34
|
+
} from '../parsers/package-surface-publication.js';
|
|
35
35
|
import type {
|
|
36
36
|
PackagePublicSurfaceFact,
|
|
37
|
-
} from '../parsers/
|
|
37
|
+
} from '../parsers/package-public-surface.js';
|
|
38
38
|
import { normalizePath } from '../utils/path-utils.js';
|
|
39
39
|
import { errorMessage } from '../utils/diagnostics.js';
|
|
40
40
|
import { sha256Text } from '../utils/hashing.js';
|
|
@@ -44,7 +44,11 @@ import {
|
|
|
44
44
|
finalizePackageTargetInvalidations,
|
|
45
45
|
invalidatePackageTargetFacts,
|
|
46
46
|
type PackageInvalidationBatch,
|
|
47
|
-
} from '../db/
|
|
47
|
+
} from '../db/package-target-invalidation.js';
|
|
48
|
+
import {
|
|
49
|
+
isPreparedRepositorySnapshotError,
|
|
50
|
+
recordPreparedSnapshotFailure,
|
|
51
|
+
} from '../db/index-publication-failure.js';
|
|
48
52
|
import {
|
|
49
53
|
loadRepositorySourceContext,
|
|
50
54
|
type RepositorySourceContext,
|
|
@@ -82,12 +86,21 @@ export async function indexRepository(
|
|
|
82
86
|
): Promise<IndexRepoResult> {
|
|
83
87
|
try {
|
|
84
88
|
const prepared = await prepareRepositoryIndex(repo, force, instrumentation);
|
|
85
|
-
if (
|
|
89
|
+
if (prepared.skipped)
|
|
90
|
+
return { fileCount: 0, diagnosticCount: 0, skipped: true };
|
|
91
|
+
const outcome = db.transaction(() => {
|
|
86
92
|
const batch = createPackageInvalidationBatch([prepared.repo.id]);
|
|
87
|
-
|
|
88
|
-
finalizePackageTargetInvalidations(db, batch);
|
|
93
|
+
const published = publishOneRepository(db, prepared, batch);
|
|
94
|
+
if (published.ok) finalizePackageTargetInvalidations(db, batch);
|
|
95
|
+
return published;
|
|
89
96
|
});
|
|
90
|
-
return
|
|
97
|
+
return outcome.ok
|
|
98
|
+
? {
|
|
99
|
+
fileCount: prepared.fileCount,
|
|
100
|
+
diagnosticCount: prepared.diagnosticCount,
|
|
101
|
+
skipped: false,
|
|
102
|
+
}
|
|
103
|
+
: { fileCount: 0, diagnosticCount: 1, skipped: false };
|
|
91
104
|
} catch (error) {
|
|
92
105
|
recordIndexFailure(db, repo.id, error);
|
|
93
106
|
return { fileCount: 0, diagnosticCount: 1, skipped: false };
|
|
@@ -172,10 +185,58 @@ export function publishPreparedRepositoryIndex(
|
|
|
172
185
|
insertCalls(db, repoId, prepared.parsed.calls);
|
|
173
186
|
db.prepare("UPDATE repositories SET last_indexed_at=?, index_status='indexed', error_count=0, fingerprint=?, fact_generation=COALESCE(fact_generation,0)+1, graph_stale_reason='facts_changed', graph_stale_at=?, fact_analyzer_version=? WHERE id=?").run(now, prepared.fingerprint, now, ANALYZER_VERSION, repoId);
|
|
174
187
|
}
|
|
188
|
+
|
|
189
|
+
export type RepositoryPublicationOutcome =
|
|
190
|
+
| { ok: true }
|
|
191
|
+
| { ok: false; error: unknown };
|
|
192
|
+
|
|
193
|
+
export function publishOneRepository(
|
|
194
|
+
db: Db,
|
|
195
|
+
prepared: PreparedRepositoryIndex,
|
|
196
|
+
invalidations: PackageInvalidationBatch,
|
|
197
|
+
): RepositoryPublicationOutcome {
|
|
198
|
+
try {
|
|
199
|
+
db.transaction(() => withPublicationSavepoint(
|
|
200
|
+
db,
|
|
201
|
+
prepared.repo.id,
|
|
202
|
+
() => publishPreparedRepositoryIndex(db, prepared, invalidations),
|
|
203
|
+
));
|
|
204
|
+
return { ok: true };
|
|
205
|
+
} catch (error) {
|
|
206
|
+
recordIndexFailure(db, prepared.repo.id, error);
|
|
207
|
+
return { ok: false, error };
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function withPublicationSavepoint<T>(
|
|
212
|
+
db: Db,
|
|
213
|
+
repoId: number,
|
|
214
|
+
publish: () => T,
|
|
215
|
+
): T {
|
|
216
|
+
const name = `service_flow_repository_${repoId}`;
|
|
217
|
+
db.exec(`SAVEPOINT ${name}`);
|
|
218
|
+
try {
|
|
219
|
+
const result = publish();
|
|
220
|
+
db.exec(`RELEASE SAVEPOINT ${name}`);
|
|
221
|
+
return result;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
db.exec(`ROLLBACK TO SAVEPOINT ${name}`);
|
|
224
|
+
db.exec(`RELEASE SAVEPOINT ${name}`);
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
175
229
|
export function recordIndexFailure(db: Db, repoId: number, error: unknown): void {
|
|
230
|
+
if (isPreparedRepositorySnapshotError(error)) {
|
|
231
|
+
recordPreparedSnapshotFailure(db, repoId, error);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
176
234
|
const message = errorMessage(error);
|
|
177
235
|
db.prepare("UPDATE repositories SET index_status='failed', error_count=1 WHERE id=?").run(repoId);
|
|
178
|
-
db.prepare(
|
|
236
|
+
db.prepare(`DELETE FROM diagnostics WHERE repo_id=? AND (
|
|
237
|
+
code IN ('index_failed_snapshot_preserved','source_read_failed')
|
|
238
|
+
OR code GLOB 'invalid_prepared_repository_snapshot:*'
|
|
239
|
+
)`).run(repoId);
|
|
179
240
|
db.prepare('INSERT INTO diagnostics(repo_id,severity,code,message) VALUES(?,?,?,?)').run(repoId, 'error', 'source_read_failed', `Index failed before publication; previous facts and fingerprint were preserved. ${message}`);
|
|
180
241
|
}
|
|
181
242
|
async function parseAllSourceFacts(
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import type { Db } from '../db/connection.js';
|
|
2
2
|
import { listRepositories, reposByName } from '../db/repositories.js';
|
|
3
3
|
import { errorMessage } from '../utils/diagnostics.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
prepareRepositoryIndex,
|
|
6
|
+
publishOneRepository,
|
|
7
|
+
recordIndexFailure,
|
|
8
|
+
type PreparedRepositoryIndex,
|
|
9
|
+
} from './repository-indexer.js';
|
|
5
10
|
import { materializeCdsExtensionOperations } from './cds-extension-resolver.js';
|
|
6
11
|
import {
|
|
7
12
|
createPackageInvalidationBatch,
|
|
8
13
|
finalizePackageTargetInvalidations,
|
|
9
|
-
|
|
14
|
+
mergePackageInvalidationEffects,
|
|
15
|
+
type PackageInvalidationBatch,
|
|
16
|
+
} from '../db/package-target-invalidation.js';
|
|
17
|
+
import {
|
|
18
|
+
isPreparedRepositorySnapshotError,
|
|
19
|
+
} from '../db/index-publication-failure.js';
|
|
20
|
+
import { binaryCompare } from '../parsers/fact-identity.js';
|
|
10
21
|
// Ownerless rows predate PID coordination; this matches doctor's stale-run threshold without taking over a recent legacy writer.
|
|
11
22
|
const LEGACY_OWNER_RECOVERY_MS = 60 * 60 * 1_000;
|
|
12
23
|
type RunningIndexRow = Record<string, unknown>;
|
|
@@ -80,11 +91,21 @@ export function claimIndexRun(
|
|
|
80
91
|
throw error;
|
|
81
92
|
}
|
|
82
93
|
}
|
|
94
|
+
export interface IndexWorkspaceSummary {
|
|
95
|
+
repoCount: number;
|
|
96
|
+
indexedCount: number;
|
|
97
|
+
skippedCount: number;
|
|
98
|
+
failedCount: number;
|
|
99
|
+
failedRepos: Array<{ name: string; code: string }>;
|
|
100
|
+
fileCount: number;
|
|
101
|
+
diagnosticCount: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
83
104
|
export async function indexWorkspace(
|
|
84
105
|
db: Db,
|
|
85
106
|
workspaceId: number,
|
|
86
107
|
options: { repo?: string; force: boolean; injectDerivedMaterializationFailure?: boolean },
|
|
87
|
-
): Promise<
|
|
108
|
+
): Promise<IndexWorkspaceSummary> {
|
|
88
109
|
const repos = selectedRepositories(db, workspaceId, options.repo);
|
|
89
110
|
const runId = claimIndexRun(db, workspaceId, repos.length);
|
|
90
111
|
const state: PreparationState = {
|
|
@@ -92,8 +113,9 @@ export async function indexWorkspace(
|
|
|
92
113
|
};
|
|
93
114
|
try {
|
|
94
115
|
await prepareRepositories(repos, options.force, state);
|
|
95
|
-
|
|
96
|
-
|
|
116
|
+
return publishPreparedWorkspaceRows(
|
|
117
|
+
db, workspaceId, runId, state.rows, options,
|
|
118
|
+
);
|
|
97
119
|
} catch (error) {
|
|
98
120
|
finishFailedRun(db, runId, state, error);
|
|
99
121
|
if (state.activeRepoId && state.rows.length < repos.length)
|
|
@@ -111,6 +133,18 @@ interface PreparationState {
|
|
|
111
133
|
activeRepoId?: number;
|
|
112
134
|
}
|
|
113
135
|
|
|
136
|
+
interface PublicationState {
|
|
137
|
+
fileCount: number;
|
|
138
|
+
diagnosticCount: number;
|
|
139
|
+
skippedCount: number;
|
|
140
|
+
indexedCount: number;
|
|
141
|
+
publicationFailureCount: number;
|
|
142
|
+
failedRepoIds: Set<number>;
|
|
143
|
+
failedRepos: Array<{ name: string; code: string }>;
|
|
144
|
+
rows: readonly PreparedRepositoryIndex[];
|
|
145
|
+
activeRepoId?: number;
|
|
146
|
+
}
|
|
147
|
+
|
|
114
148
|
function selectedRepositories(
|
|
115
149
|
db: Db,
|
|
116
150
|
workspaceId: number,
|
|
@@ -145,38 +179,118 @@ async function prepareRepositories(
|
|
|
145
179
|
}
|
|
146
180
|
}
|
|
147
181
|
|
|
148
|
-
function
|
|
182
|
+
export function publishPreparedWorkspaceRows(
|
|
149
183
|
db: Db,
|
|
150
184
|
workspaceId: number,
|
|
151
|
-
options: { injectDerivedMaterializationFailure?: boolean },
|
|
152
185
|
runId: number,
|
|
153
|
-
|
|
154
|
-
|
|
186
|
+
rows: readonly PreparedRepositoryIndex[],
|
|
187
|
+
options: { injectDerivedMaterializationFailure?: boolean } = {},
|
|
188
|
+
): IndexWorkspaceSummary {
|
|
189
|
+
const state = publicationState(rows);
|
|
155
190
|
db.transaction(() => {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
);
|
|
191
|
+
const effects = createPackageInvalidationBatch([]);
|
|
192
|
+
const publishedRepoIds: number[] = [];
|
|
159
193
|
for (const row of state.rows) {
|
|
160
194
|
state.activeRepoId = row.repo.id;
|
|
161
|
-
|
|
195
|
+
if (row.skipped) continue;
|
|
196
|
+
const result = publishPreparedRow(db, row);
|
|
197
|
+
if (result.status === 'failed') {
|
|
198
|
+
recordPublicationFailure(db, state, row, result.error);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
state.indexedCount += 1;
|
|
202
|
+
publishedRepoIds.push(row.repo.id);
|
|
203
|
+
mergePackageInvalidationEffects(effects, result.effects);
|
|
162
204
|
}
|
|
163
205
|
if (options.injectDerivedMaterializationFailure)
|
|
164
206
|
throw new Error('Injected derived materialization failure');
|
|
165
|
-
materializeCdsExtensionOperations(
|
|
207
|
+
materializeCdsExtensionOperations(
|
|
208
|
+
db, workspaceId, state.failedRepoIds,
|
|
209
|
+
);
|
|
210
|
+
const invalidations = createPackageInvalidationBatch(publishedRepoIds);
|
|
211
|
+
mergePackageInvalidationEffects(invalidations, effects);
|
|
166
212
|
finalizePackageTargetInvalidations(db, invalidations);
|
|
167
|
-
|
|
213
|
+
finishCompletedRun(db, runId, state);
|
|
214
|
+
});
|
|
215
|
+
return indexSummary(rows.length, state);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function publicationState(
|
|
219
|
+
rows: readonly PreparedRepositoryIndex[],
|
|
220
|
+
): PublicationState {
|
|
221
|
+
return {
|
|
222
|
+
rows,
|
|
223
|
+
fileCount: rows.reduce((total, row) => total + row.fileCount, 0),
|
|
224
|
+
diagnosticCount: rows.reduce(
|
|
225
|
+
(total, row) => total + row.diagnosticCount, 0,
|
|
226
|
+
),
|
|
227
|
+
skippedCount: rows.filter((row) => row.skipped).length,
|
|
228
|
+
indexedCount: 0,
|
|
229
|
+
publicationFailureCount: 0,
|
|
230
|
+
failedRepoIds: new Set(),
|
|
231
|
+
failedRepos: [],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
type PublicationResult =
|
|
236
|
+
| { status: 'published'; effects: PackageInvalidationBatch }
|
|
237
|
+
| { status: 'failed'; error: unknown };
|
|
238
|
+
|
|
239
|
+
function publishPreparedRow(
|
|
240
|
+
db: Db,
|
|
241
|
+
row: PreparedRepositoryIndex,
|
|
242
|
+
): PublicationResult {
|
|
243
|
+
const effects = createPackageInvalidationBatch([row.repo.id]);
|
|
244
|
+
const outcome = publishOneRepository(db, row, effects);
|
|
245
|
+
if (!outcome.ok && !isPreparedRepositorySnapshotError(outcome.error))
|
|
246
|
+
throw outcome.error;
|
|
247
|
+
return outcome.ok
|
|
248
|
+
? { status: 'published', effects }
|
|
249
|
+
: { status: 'failed', error: outcome.error };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function recordPublicationFailure(
|
|
253
|
+
db: Db,
|
|
254
|
+
state: PublicationState,
|
|
255
|
+
row: PreparedRepositoryIndex,
|
|
256
|
+
error: unknown,
|
|
257
|
+
): void {
|
|
258
|
+
state.failedRepoIds.add(row.repo.id);
|
|
259
|
+
state.failedRepos.push({
|
|
260
|
+
name: row.repo.name,
|
|
261
|
+
code: isPreparedRepositorySnapshotError(error)
|
|
262
|
+
? error.message : 'source_read_failed',
|
|
168
263
|
});
|
|
264
|
+
state.publicationFailureCount += 1;
|
|
169
265
|
}
|
|
170
266
|
|
|
171
|
-
function
|
|
267
|
+
function finishCompletedRun(
|
|
172
268
|
db: Db,
|
|
173
269
|
runId: number,
|
|
174
|
-
state:
|
|
270
|
+
state: PublicationState,
|
|
175
271
|
): void {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
new Date().toISOString(), state.fileCount, state.diagnosticCount, runId,
|
|
272
|
+
const status = completedRunStatus(
|
|
273
|
+
state.rows.length, state.publicationFailureCount,
|
|
179
274
|
);
|
|
275
|
+
const error = status === 'success' ? null
|
|
276
|
+
: `${state.publicationFailureCount} repositories failed index publication.`;
|
|
277
|
+
db.prepare(`UPDATE index_runs SET finished_at=?,status=?,
|
|
278
|
+
file_count=?,diagnostic_count=?,error_message=? WHERE id=?`).run(
|
|
279
|
+
new Date().toISOString(), status, state.fileCount,
|
|
280
|
+
completedDiagnosticCount(state), error, runId,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function completedRunStatus(
|
|
285
|
+
repoCount: number,
|
|
286
|
+
failedCount: number,
|
|
287
|
+
): 'success' | 'partial_failure' | 'failed' {
|
|
288
|
+
if (failedCount === 0) return 'success';
|
|
289
|
+
return failedCount === repoCount ? 'failed' : 'partial_failure';
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function completedDiagnosticCount(state: PublicationState): number {
|
|
293
|
+
return state.diagnosticCount + state.publicationFailureCount;
|
|
180
294
|
}
|
|
181
295
|
|
|
182
296
|
function finishFailedRun(
|
|
@@ -194,19 +308,17 @@ function finishFailedRun(
|
|
|
194
308
|
|
|
195
309
|
function indexSummary(
|
|
196
310
|
repoCount: number,
|
|
197
|
-
state:
|
|
198
|
-
): {
|
|
199
|
-
repoCount: number;
|
|
200
|
-
indexedCount: number;
|
|
201
|
-
skippedCount: number;
|
|
202
|
-
fileCount: number;
|
|
203
|
-
diagnosticCount: number;
|
|
204
|
-
} {
|
|
311
|
+
state: PublicationState,
|
|
312
|
+
): IndexWorkspaceSummary {
|
|
205
313
|
return {
|
|
206
314
|
repoCount,
|
|
207
|
-
indexedCount:
|
|
315
|
+
indexedCount: state.indexedCount,
|
|
208
316
|
skippedCount: state.skippedCount,
|
|
317
|
+
failedCount: state.publicationFailureCount,
|
|
318
|
+
failedRepos: [...state.failedRepos].sort((left, right) =>
|
|
319
|
+
binaryCompare(left.name, right.name)
|
|
320
|
+
|| binaryCompare(left.code, right.code)),
|
|
209
321
|
fileCount: state.fileCount,
|
|
210
|
-
diagnosticCount: state
|
|
322
|
+
diagnosticCount: completedDiagnosticCount(state),
|
|
211
323
|
};
|
|
212
324
|
}
|