@fabricorg/databricks-testkit 0.3.0 → 0.4.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/index.d.cts CHANGED
@@ -548,14 +548,23 @@ interface JobTaskRunState {
548
548
  lifeCycleState: string;
549
549
  resultState: string;
550
550
  stateMessage?: string;
551
+ attemptNumber?: number;
551
552
  }
552
553
  interface JobOrchestrationRun {
553
554
  runId: number;
554
555
  lifeCycleState: string;
555
556
  resultState: string;
556
557
  tasks: JobTaskRunState[];
558
+ repairs: JobRepairRunState[];
557
559
  raw: Record<string, unknown>;
558
560
  }
561
+ interface JobRepairRunState {
562
+ repairId: number;
563
+ type: string;
564
+ lifeCycleState: string;
565
+ resultState: string;
566
+ taskRunIds: number[];
567
+ }
559
568
  interface JobWaitOptions {
560
569
  timeoutMs?: number;
561
570
  pollIntervalMs?: number;
@@ -563,12 +572,17 @@ interface JobWaitOptions {
563
572
  interface JobRepairOptions {
564
573
  rerunTasks?: string[];
565
574
  latestRepairId?: number;
575
+ rerunDependentTasks?: boolean;
566
576
  }
567
577
  interface JobOrchestrationLiveSpec {
568
578
  request: JobsSubmitRequest;
569
579
  expectedResult?: string;
570
580
  expectedTasks?: Record<string, string>;
571
581
  repairFailedTasks?: boolean;
582
+ cancellation?: {
583
+ request: JobsSubmitRequest;
584
+ expectedResult?: string;
585
+ };
572
586
  }
573
587
  declare class DatabricksJobsAdapter {
574
588
  private readonly client;
@@ -577,16 +591,20 @@ declare class DatabricksJobsAdapter {
577
591
  get(runId: number): Promise<JobOrchestrationRun>;
578
592
  wait(runId: number, options?: JobWaitOptions): Promise<JobOrchestrationRun>;
579
593
  cancel(runId: number): Promise<void>;
594
+ waitUntilActive(runId: number, options?: JobWaitOptions): Promise<JobOrchestrationRun>;
580
595
  repair(runId: number, options?: JobRepairOptions): Promise<number>;
596
+ waitForRepair(runId: number, repairId: number, options?: JobWaitOptions): Promise<JobOrchestrationRun>;
581
597
  }
582
598
  declare function validateJobGraph(tasks: readonly DatabricksJobTask[]): void;
583
599
  declare function jobsOrchestrationCheck(): LiveCheck;
584
600
  declare function parseJobOrchestrationLiveSpec(value: string): JobOrchestrationLiveSpec;
585
601
  declare function normalizeJobRun(fallbackRunId: number, raw: Record<string, unknown>): JobOrchestrationRun;
586
602
 
603
+ declare function jobsCertificationCheck(): LiveCheck;
604
+
587
605
  declare function createLakeflowJobsTargetPack(): TargetPack;
588
606
 
589
607
  declare function createBuiltinTargetPacks(): readonly TargetPack[];
590
608
  declare const builtinTargetPacks: readonly TargetPack[];
591
609
 
592
- export { type AppHealthCheckOptions, type AutoLoaderCheckOptions, type ConditionJobTask, type CreateContextOptions, type DatabricksJobTask, DatabricksJobsAdapter, type DbtJobTask, type DefinedLiveSuite, type DefinedTargetPackRun, type DeltaColumnContract, type DuckDbConnectionLike, type DuckDbContextOptions, type EphemeralLakebaseBranch, type ExecutionContext, type ForEachJobTask, type JobOrchestrationLiveSpec, type JobOrchestrationRun, type JobRepairOptions, type JobTaskBase, type JobTaskDependency, type JobTaskRunState, type JobWaitOptions, type JobsSubmitRequest, type LakebaseBranchOptions, type LakebaseCheckOptions, type LakebaseControlClient, type LiveCheck, type LiveCheckContext, type LiveCheckResult, type LiveCheckStatus, type LiveEvidence, type LiveSuiteRuntime, type LiveSuiteSpec, type MockDatabricksClient, type NotebookJobTask, type PipelineJobTask, type PollOptions, type PythonWheelJobTask, type RecordedCall, type RunJobTask, type RunTargetPackOptions, type SecretRotationCheckOptions, type SparkJarJobTask, type SparkPythonJobTask, type SparkSubmitJobTask, type SqlJobTask, TableFixture, type TargetPack, type TargetPackDoctorCheck, type TargetPackDoctorRequirement, type TargetPackDoctorResult, type TargetPackEvidenceMetadata, type TargetPackMaturity, type TargetPackRequirement, type TargetPackSpec, type TestProfile, type VolumeIOCheckOptions, type WorkspaceClientLike, type WorkspaceContextOptions, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, compareToGolden, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createClientFromEnv, createDuckDbContext, createEphemeralLakebaseBranch, createExecutionContext, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMockDatabricksClient, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, createWorkspaceContext, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, foundationTargetPacks, jobRunCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, normalizeJobRun, normalizeRow, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, parseStatementRows, performanceBudgetCheck, pipelineRefreshCheck, renderJUnit, resolveLakebaseProject, resolveProfile, resolveTokenProvider, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, toNamedParameters, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, volumeIOCheck, waitForPipelineUpdate };
610
+ export { type AppHealthCheckOptions, type AutoLoaderCheckOptions, type ConditionJobTask, type CreateContextOptions, type DatabricksJobTask, DatabricksJobsAdapter, type DbtJobTask, type DefinedLiveSuite, type DefinedTargetPackRun, type DeltaColumnContract, type DuckDbConnectionLike, type DuckDbContextOptions, type EphemeralLakebaseBranch, type ExecutionContext, type ForEachJobTask, type JobOrchestrationLiveSpec, type JobOrchestrationRun, type JobRepairOptions, type JobRepairRunState, type JobTaskBase, type JobTaskDependency, type JobTaskRunState, type JobWaitOptions, type JobsSubmitRequest, type LakebaseBranchOptions, type LakebaseCheckOptions, type LakebaseControlClient, type LiveCheck, type LiveCheckContext, type LiveCheckResult, type LiveCheckStatus, type LiveEvidence, type LiveSuiteRuntime, type LiveSuiteSpec, type MockDatabricksClient, type NotebookJobTask, type PipelineJobTask, type PollOptions, type PythonWheelJobTask, type RecordedCall, type RunJobTask, type RunTargetPackOptions, type SecretRotationCheckOptions, type SparkJarJobTask, type SparkPythonJobTask, type SparkSubmitJobTask, type SqlJobTask, TableFixture, type TargetPack, type TargetPackDoctorCheck, type TargetPackDoctorRequirement, type TargetPackDoctorResult, type TargetPackEvidenceMetadata, type TargetPackMaturity, type TargetPackRequirement, type TargetPackSpec, type TestProfile, type VolumeIOCheckOptions, type WorkspaceClientLike, type WorkspaceContextOptions, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, compareToGolden, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createClientFromEnv, createDuckDbContext, createEphemeralLakebaseBranch, createExecutionContext, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMockDatabricksClient, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, createWorkspaceContext, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, foundationTargetPacks, jobRunCheck, jobsCertificationCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, normalizeJobRun, normalizeRow, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, parseStatementRows, performanceBudgetCheck, pipelineRefreshCheck, renderJUnit, resolveLakebaseProject, resolveProfile, resolveTokenProvider, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, toNamedParameters, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, volumeIOCheck, waitForPipelineUpdate };
package/dist/index.d.ts CHANGED
@@ -548,14 +548,23 @@ interface JobTaskRunState {
548
548
  lifeCycleState: string;
549
549
  resultState: string;
550
550
  stateMessage?: string;
551
+ attemptNumber?: number;
551
552
  }
552
553
  interface JobOrchestrationRun {
553
554
  runId: number;
554
555
  lifeCycleState: string;
555
556
  resultState: string;
556
557
  tasks: JobTaskRunState[];
558
+ repairs: JobRepairRunState[];
557
559
  raw: Record<string, unknown>;
558
560
  }
561
+ interface JobRepairRunState {
562
+ repairId: number;
563
+ type: string;
564
+ lifeCycleState: string;
565
+ resultState: string;
566
+ taskRunIds: number[];
567
+ }
559
568
  interface JobWaitOptions {
560
569
  timeoutMs?: number;
561
570
  pollIntervalMs?: number;
@@ -563,12 +572,17 @@ interface JobWaitOptions {
563
572
  interface JobRepairOptions {
564
573
  rerunTasks?: string[];
565
574
  latestRepairId?: number;
575
+ rerunDependentTasks?: boolean;
566
576
  }
567
577
  interface JobOrchestrationLiveSpec {
568
578
  request: JobsSubmitRequest;
569
579
  expectedResult?: string;
570
580
  expectedTasks?: Record<string, string>;
571
581
  repairFailedTasks?: boolean;
582
+ cancellation?: {
583
+ request: JobsSubmitRequest;
584
+ expectedResult?: string;
585
+ };
572
586
  }
573
587
  declare class DatabricksJobsAdapter {
574
588
  private readonly client;
@@ -577,16 +591,20 @@ declare class DatabricksJobsAdapter {
577
591
  get(runId: number): Promise<JobOrchestrationRun>;
578
592
  wait(runId: number, options?: JobWaitOptions): Promise<JobOrchestrationRun>;
579
593
  cancel(runId: number): Promise<void>;
594
+ waitUntilActive(runId: number, options?: JobWaitOptions): Promise<JobOrchestrationRun>;
580
595
  repair(runId: number, options?: JobRepairOptions): Promise<number>;
596
+ waitForRepair(runId: number, repairId: number, options?: JobWaitOptions): Promise<JobOrchestrationRun>;
581
597
  }
582
598
  declare function validateJobGraph(tasks: readonly DatabricksJobTask[]): void;
583
599
  declare function jobsOrchestrationCheck(): LiveCheck;
584
600
  declare function parseJobOrchestrationLiveSpec(value: string): JobOrchestrationLiveSpec;
585
601
  declare function normalizeJobRun(fallbackRunId: number, raw: Record<string, unknown>): JobOrchestrationRun;
586
602
 
603
+ declare function jobsCertificationCheck(): LiveCheck;
604
+
587
605
  declare function createLakeflowJobsTargetPack(): TargetPack;
588
606
 
589
607
  declare function createBuiltinTargetPacks(): readonly TargetPack[];
590
608
  declare const builtinTargetPacks: readonly TargetPack[];
591
609
 
592
- export { type AppHealthCheckOptions, type AutoLoaderCheckOptions, type ConditionJobTask, type CreateContextOptions, type DatabricksJobTask, DatabricksJobsAdapter, type DbtJobTask, type DefinedLiveSuite, type DefinedTargetPackRun, type DeltaColumnContract, type DuckDbConnectionLike, type DuckDbContextOptions, type EphemeralLakebaseBranch, type ExecutionContext, type ForEachJobTask, type JobOrchestrationLiveSpec, type JobOrchestrationRun, type JobRepairOptions, type JobTaskBase, type JobTaskDependency, type JobTaskRunState, type JobWaitOptions, type JobsSubmitRequest, type LakebaseBranchOptions, type LakebaseCheckOptions, type LakebaseControlClient, type LiveCheck, type LiveCheckContext, type LiveCheckResult, type LiveCheckStatus, type LiveEvidence, type LiveSuiteRuntime, type LiveSuiteSpec, type MockDatabricksClient, type NotebookJobTask, type PipelineJobTask, type PollOptions, type PythonWheelJobTask, type RecordedCall, type RunJobTask, type RunTargetPackOptions, type SecretRotationCheckOptions, type SparkJarJobTask, type SparkPythonJobTask, type SparkSubmitJobTask, type SqlJobTask, TableFixture, type TargetPack, type TargetPackDoctorCheck, type TargetPackDoctorRequirement, type TargetPackDoctorResult, type TargetPackEvidenceMetadata, type TargetPackMaturity, type TargetPackRequirement, type TargetPackSpec, type TestProfile, type VolumeIOCheckOptions, type WorkspaceClientLike, type WorkspaceContextOptions, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, compareToGolden, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createClientFromEnv, createDuckDbContext, createEphemeralLakebaseBranch, createExecutionContext, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMockDatabricksClient, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, createWorkspaceContext, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, foundationTargetPacks, jobRunCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, normalizeJobRun, normalizeRow, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, parseStatementRows, performanceBudgetCheck, pipelineRefreshCheck, renderJUnit, resolveLakebaseProject, resolveProfile, resolveTokenProvider, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, toNamedParameters, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, volumeIOCheck, waitForPipelineUpdate };
610
+ export { type AppHealthCheckOptions, type AutoLoaderCheckOptions, type ConditionJobTask, type CreateContextOptions, type DatabricksJobTask, DatabricksJobsAdapter, type DbtJobTask, type DefinedLiveSuite, type DefinedTargetPackRun, type DeltaColumnContract, type DuckDbConnectionLike, type DuckDbContextOptions, type EphemeralLakebaseBranch, type ExecutionContext, type ForEachJobTask, type JobOrchestrationLiveSpec, type JobOrchestrationRun, type JobRepairOptions, type JobRepairRunState, type JobTaskBase, type JobTaskDependency, type JobTaskRunState, type JobWaitOptions, type JobsSubmitRequest, type LakebaseBranchOptions, type LakebaseCheckOptions, type LakebaseControlClient, type LiveCheck, type LiveCheckContext, type LiveCheckResult, type LiveCheckStatus, type LiveEvidence, type LiveSuiteRuntime, type LiveSuiteSpec, type MockDatabricksClient, type NotebookJobTask, type PipelineJobTask, type PollOptions, type PythonWheelJobTask, type RecordedCall, type RunJobTask, type RunTargetPackOptions, type SecretRotationCheckOptions, type SparkJarJobTask, type SparkPythonJobTask, type SparkSubmitJobTask, type SqlJobTask, TableFixture, type TargetPack, type TargetPackDoctorCheck, type TargetPackDoctorRequirement, type TargetPackDoctorResult, type TargetPackEvidenceMetadata, type TargetPackMaturity, type TargetPackRequirement, type TargetPackSpec, type TestProfile, type VolumeIOCheckOptions, type WorkspaceClientLike, type WorkspaceContextOptions, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, compareToGolden, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createClientFromEnv, createDuckDbContext, createEphemeralLakebaseBranch, createExecutionContext, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMockDatabricksClient, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, createWorkspaceContext, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, foundationTargetPacks, jobRunCheck, jobsCertificationCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, normalizeJobRun, normalizeRow, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, parseStatementRows, performanceBudgetCheck, pipelineRefreshCheck, renderJUnit, resolveLakebaseProject, resolveProfile, resolveTokenProvider, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, toNamedParameters, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, volumeIOCheck, waitForPipelineUpdate };
package/dist/index.js CHANGED
@@ -1259,7 +1259,7 @@ function createSqlDeltaFoundationPack() {
1259
1259
  ],
1260
1260
  requiredChecks: ["sql"],
1261
1261
  requirements: [workspaceRequirement, authRequirement, warehouseRequirement],
1262
- docsUrl: `${DOCS}#existing-foundation-to-migrate-into-packs`,
1262
+ docsUrl: `${DOCS}#sql-and-delta-foundation`,
1263
1263
  certificationScopes: [AZURE_SCOPE]
1264
1264
  });
1265
1265
  }
@@ -1284,7 +1284,7 @@ function createLakeflowFoundationPack() {
1284
1284
  ],
1285
1285
  requiredChecks: ["pipeline"],
1286
1286
  requirements: [workspaceRequirement, authRequirement],
1287
- docsUrl: `${DOCS}#existing-foundation-to-migrate-into-packs`,
1287
+ docsUrl: `${DOCS}#lakeflow-ingestion-foundation`,
1288
1288
  certificationScopes: [AZURE_SCOPE]
1289
1289
  });
1290
1290
  }
@@ -1312,7 +1312,7 @@ function createJobsCodeFoundationPack() {
1312
1312
  ],
1313
1313
  requiredChecks: ["jobs"],
1314
1314
  requirements: [workspaceRequirement, authRequirement],
1315
- docsUrl: `${DOCS}#existing-foundation-to-migrate-into-packs`,
1315
+ docsUrl: `${DOCS}#jobs-and-code-foundation`,
1316
1316
  certificationScopes: [AZURE_SCOPE]
1317
1317
  });
1318
1318
  }
@@ -1338,7 +1338,7 @@ function createUnityStorageFoundationPack() {
1338
1338
  ],
1339
1339
  requiredChecks: ["uc-grants"],
1340
1340
  requirements: [workspaceRequirement, authRequirement, warehouseRequirement],
1341
- docsUrl: `${DOCS}#existing-foundation-to-migrate-into-packs`,
1341
+ docsUrl: `${DOCS}#unity-catalog-and-storage-foundation`,
1342
1342
  certificationScopes: [AZURE_SCOPE]
1343
1343
  });
1344
1344
  }
@@ -1364,7 +1364,7 @@ function createAppsOperationalFoundationPack() {
1364
1364
  ],
1365
1365
  requiredChecks: ["app"],
1366
1366
  requirements: [workspaceRequirement, authRequirement],
1367
- docsUrl: `${DOCS}#existing-foundation-to-migrate-into-packs`,
1367
+ docsUrl: `${DOCS}#apps-and-operational-data-foundation`,
1368
1368
  certificationScopes: [AZURE_SCOPE]
1369
1369
  });
1370
1370
  }
@@ -1395,7 +1395,8 @@ var DatabricksJobsAdapter = class {
1395
1395
  async get(runId) {
1396
1396
  const raw = await this.client.get("/api/2.1/jobs/runs/get", {
1397
1397
  run_id: runId,
1398
- include_history: true
1398
+ include_history: true,
1399
+ include_resolved_values: true
1399
1400
  });
1400
1401
  return normalizeJobRun(runId, raw);
1401
1402
  }
@@ -1409,15 +1410,46 @@ var DatabricksJobsAdapter = class {
1409
1410
  async cancel(runId) {
1410
1411
  await this.client.post("/api/2.1/jobs/runs/cancel", { run_id: runId });
1411
1412
  }
1413
+ async waitUntilActive(runId, options = {}) {
1414
+ const timeoutMs = options.timeoutMs ?? 3e5;
1415
+ const pollIntervalMs = options.pollIntervalMs ?? 2e3;
1416
+ const deadline = Date.now() + timeoutMs;
1417
+ while (Date.now() < deadline) {
1418
+ const run = await this.get(runId);
1419
+ if (run.lifeCycleState === "RUNNING") return run;
1420
+ if (isTerminal(run.lifeCycleState)) {
1421
+ throw new Error(
1422
+ `Databricks run ${runId} reached ${run.lifeCycleState}/${run.resultState} before it could be canceled`
1423
+ );
1424
+ }
1425
+ await delay2(pollIntervalMs);
1426
+ }
1427
+ throw new Error(`Databricks run ${runId} did not become active within ${timeoutMs}ms`);
1428
+ }
1412
1429
  async repair(runId, options = {}) {
1413
1430
  const response = await this.client.post("/api/2.1/jobs/runs/repair", {
1414
1431
  run_id: runId,
1415
1432
  ...options.latestRepairId ? { latest_repair_id: options.latestRepairId } : {},
1433
+ ...options.rerunDependentTasks ? { rerun_dependent_tasks: true } : {},
1416
1434
  ...options.rerunTasks?.length ? { rerun_tasks: options.rerunTasks } : { rerun_all_failed_tasks: true }
1417
1435
  });
1418
1436
  if (!response.repair_id) throw new Error("Databricks Jobs repair returned no repair_id");
1419
1437
  return response.repair_id;
1420
1438
  }
1439
+ async waitForRepair(runId, repairId, options = {}) {
1440
+ const timeoutMs = options.timeoutMs ?? 9e5;
1441
+ const pollIntervalMs = options.pollIntervalMs ?? 5e3;
1442
+ const deadline = Date.now() + timeoutMs;
1443
+ while (Date.now() < deadline) {
1444
+ const run = await this.get(runId);
1445
+ const repair = run.repairs.find((candidate) => candidate.repairId === repairId);
1446
+ if (repair && isTerminal(repair.lifeCycleState)) return run;
1447
+ await delay2(pollIntervalMs);
1448
+ }
1449
+ throw new Error(
1450
+ `Databricks repair ${repairId} for run ${runId} timed out after ${timeoutMs}ms`
1451
+ );
1452
+ }
1421
1453
  };
1422
1454
  function validateJobGraph(tasks) {
1423
1455
  if (tasks.length === 0) throw new Error("Jobs orchestration requires at least one task");
@@ -1469,10 +1501,14 @@ function jobsOrchestrationCheck() {
1469
1501
  timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
1470
1502
  pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
1471
1503
  });
1504
+ let repairId;
1472
1505
  if (spec.repairFailedTasks && run.resultState !== "SUCCESS") {
1473
1506
  const failed = run.tasks.filter((task) => task.resultState === "FAILED").map((task) => task.taskKey);
1474
- await adapter.repair(runId, { rerunTasks: failed.length > 0 ? failed : void 0 });
1475
- run = await adapter.wait(runId, {
1507
+ repairId = await adapter.repair(runId, {
1508
+ rerunTasks: failed.length > 0 ? failed : void 0,
1509
+ rerunDependentTasks: true
1510
+ });
1511
+ run = await adapter.waitForRepair(runId, repairId, {
1476
1512
  timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
1477
1513
  pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
1478
1514
  });
@@ -1490,10 +1526,32 @@ function jobsOrchestrationCheck() {
1490
1526
  throw new Error(`Task '${taskKey}' ended in ${task.resultState}, expected ${expected}`);
1491
1527
  }
1492
1528
  }
1529
+ let cancellation;
1530
+ if (spec.cancellation) {
1531
+ const cancellationRunId = await adapter.submit(spec.cancellation.request);
1532
+ await adapter.waitUntilActive(cancellationRunId, {
1533
+ timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
1534
+ pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
1535
+ });
1536
+ await adapter.cancel(cancellationRunId);
1537
+ const canceled = await adapter.wait(cancellationRunId, {
1538
+ timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
1539
+ pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 1e4)
1540
+ });
1541
+ const expectedCancellation = spec.cancellation.expectedResult ?? "CANCELED";
1542
+ if (canceled.resultState !== expectedCancellation) {
1543
+ throw new Error(
1544
+ `Cancellation run ${cancellationRunId} ended in ${canceled.resultState}, expected ${expectedCancellation}`
1545
+ );
1546
+ }
1547
+ cancellation = { runId: cancellationRunId, resultState: canceled.resultState };
1548
+ }
1493
1549
  return {
1494
1550
  runId,
1551
+ ...repairId ? { repairId } : {},
1495
1552
  resultState: run.resultState,
1496
- tasks: run.tasks
1553
+ tasks: run.tasks,
1554
+ ...cancellation ? { cancellation } : {}
1497
1555
  };
1498
1556
  }
1499
1557
  };
@@ -1513,11 +1571,24 @@ function parseJobOrchestrationLiveSpec(value) {
1513
1571
  throw new Error("Jobs orchestration spec requires request.tasks");
1514
1572
  }
1515
1573
  validateJobGraph(spec.request.tasks);
1574
+ if (spec.cancellation) {
1575
+ if (typeof spec.cancellation !== "object" || !spec.cancellation.request || !Array.isArray(spec.cancellation.request.tasks)) {
1576
+ throw new Error("Jobs orchestration cancellation requires request.tasks");
1577
+ }
1578
+ validateJobGraph(spec.cancellation.request.tasks);
1579
+ }
1516
1580
  return spec;
1517
1581
  }
1518
1582
  function normalizeJobRun(fallbackRunId, raw) {
1519
1583
  const state = objectOf(raw.state);
1520
- const tasks = Array.isArray(raw.tasks) ? raw.tasks.filter(
1584
+ const repairEntries = Array.isArray(raw.repair_history) ? raw.repair_history.filter(
1585
+ (repair) => Boolean(repair && typeof repair === "object")
1586
+ ) : [];
1587
+ const taskRunRanks = /* @__PURE__ */ new Map();
1588
+ for (const [rank, repair] of repairEntries.entries()) {
1589
+ for (const runId of numberArray(repair.task_run_ids)) taskRunRanks.set(runId, rank);
1590
+ }
1591
+ const taskAttempts = Array.isArray(raw.tasks) ? raw.tasks.filter(
1521
1592
  (task) => Boolean(task && typeof task === "object")
1522
1593
  ).map((task) => {
1523
1594
  const taskState = objectOf(task.state);
@@ -1526,20 +1597,236 @@ function normalizeJobRun(fallbackRunId, raw) {
1526
1597
  ...Number.isFinite(Number(task.run_id)) ? { runId: Number(task.run_id) } : {},
1527
1598
  lifeCycleState: String(taskState.life_cycle_state ?? "UNKNOWN"),
1528
1599
  resultState: String(taskState.result_state ?? "UNKNOWN"),
1529
- ...typeof taskState.state_message === "string" ? { stateMessage: taskState.state_message } : {}
1600
+ ...typeof taskState.state_message === "string" ? { stateMessage: taskState.state_message } : {},
1601
+ ...Number.isFinite(Number(task.attempt_number)) ? { attemptNumber: Number(task.attempt_number) } : {}
1530
1602
  };
1531
1603
  }) : [];
1604
+ const latestTasks = /* @__PURE__ */ new Map();
1605
+ for (const task of taskAttempts) {
1606
+ const current = latestTasks.get(task.taskKey);
1607
+ const currentAttempt = current?.attemptNumber ?? -1;
1608
+ const candidateAttempt = task.attemptNumber ?? -1;
1609
+ const currentRank = current?.runId ? taskRunRanks.get(current.runId) ?? -1 : -1;
1610
+ const candidateRank = task.runId ? taskRunRanks.get(task.runId) ?? -1 : -1;
1611
+ if (!current || candidateAttempt > currentAttempt || candidateAttempt === currentAttempt && candidateRank >= currentRank) {
1612
+ latestTasks.set(task.taskKey, task);
1613
+ }
1614
+ }
1615
+ const tasks = [...latestTasks.values()];
1616
+ const repairs = repairEntries.map((repair) => {
1617
+ const repairState = objectOf(repair.state);
1618
+ return {
1619
+ repairId: Number(repair.id ?? repair.repair_id ?? 0),
1620
+ type: String(repair.type ?? "UNKNOWN"),
1621
+ lifeCycleState: String(repairState.life_cycle_state ?? "UNKNOWN"),
1622
+ resultState: String(repairState.result_state ?? "UNKNOWN"),
1623
+ taskRunIds: numberArray(repair.task_run_ids)
1624
+ };
1625
+ });
1532
1626
  return {
1533
1627
  runId: Number(raw.run_id ?? fallbackRunId),
1534
1628
  lifeCycleState: String(state.life_cycle_state ?? "UNKNOWN"),
1535
1629
  resultState: String(state.result_state ?? "UNKNOWN"),
1536
1630
  tasks,
1631
+ repairs,
1537
1632
  raw
1538
1633
  };
1539
1634
  }
1635
+ function isTerminal(state) {
1636
+ return ["TERMINATED", "SKIPPED", "INTERNAL_ERROR", "BLOCKED"].includes(state);
1637
+ }
1638
+ function delay2(ms) {
1639
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
1640
+ }
1540
1641
  function objectOf(value) {
1541
1642
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1542
1643
  }
1644
+ function numberArray(value) {
1645
+ return Array.isArray(value) ? value.map(Number).filter((candidate) => Number.isFinite(candidate)) : [];
1646
+ }
1647
+
1648
+ // src/jobs-certification-check.ts
1649
+ var NOTEBOOKS = {
1650
+ seed: `# Databricks notebook source
1651
+ dbutils.jobs.taskValues.set(key="branch", value="run")
1652
+ dbutils.jobs.taskValues.set(key="items", value=["alpha", "beta"])
1653
+ dbutils.notebook.exit("seeded")
1654
+ `,
1655
+ process: `# Databricks notebook source
1656
+ dbutils.widgets.text("item", "")
1657
+ item = dbutils.widgets.get("item")
1658
+ assert item, "item parameter is required"
1659
+ dbutils.notebook.exit(item)
1660
+ `,
1661
+ retry: `# Databricks notebook source
1662
+ dbutils.widgets.text("execution_count", "0")
1663
+ execution_count = int(dbutils.widgets.get("execution_count"))
1664
+ if execution_count <= 1:
1665
+ raise RuntimeError("intentional retryable failure")
1666
+ dbutils.notebook.exit("retried")
1667
+ `,
1668
+ repair: `# Databricks notebook source
1669
+ dbutils.widgets.text("repair_count", "0")
1670
+ repair_count = int(dbutils.widgets.get("repair_count"))
1671
+ if repair_count == 0:
1672
+ raise RuntimeError("intentional first-run failure")
1673
+ dbutils.notebook.exit("repaired")
1674
+ `,
1675
+ sleep: `# Databricks notebook source
1676
+ import time
1677
+ time.sleep(300)
1678
+ `
1679
+ };
1680
+ function jobsCertificationCheck() {
1681
+ return {
1682
+ id: "jobs-certification",
1683
+ description: "Disposable Lakeflow Jobs branch, loop, failure, repair, cancellation, and cleanup certification",
1684
+ configured: (env) => env.DBX_TEST_JOBS_CERTIFY === "1",
1685
+ async run({ env, client }) {
1686
+ const root = `${env.DBX_TEST_JOBS_FIXTURE_ROOT ?? "/Workspace/Shared/fabric-experiments-target-pack"}/${randomUUID()}`;
1687
+ const paths = Object.fromEntries(
1688
+ Object.keys(NOTEBOOKS).map((name) => [name, `${root}/${name}`])
1689
+ );
1690
+ try {
1691
+ await importNotebooks(client, paths);
1692
+ const adapter = new DatabricksJobsAdapter(client);
1693
+ const runId = await adapter.submit(certificationRequest(paths));
1694
+ const initial = await adapter.wait(runId, waitOptions(env));
1695
+ if (initial.resultState !== "FAILED") {
1696
+ throw new Error(
1697
+ `Certification run ${runId} expected FAILED before repair, got ${initial.resultState}`
1698
+ );
1699
+ }
1700
+ const retried = assertTask(initial.tasks, "retry", "SUCCESS");
1701
+ if ((retried.attemptNumber ?? 0) < 1) {
1702
+ throw new Error("Certification retry task did not record a second attempt");
1703
+ }
1704
+ assertTask(initial.tasks, "seed", "SUCCESS");
1705
+ assertTask(initial.tasks, "branch", "SUCCESS");
1706
+ assertTask(initial.tasks, "foreach", "SUCCESS");
1707
+ assertTask(initial.tasks, "repair", "FAILED");
1708
+ const repairId = await adapter.repair(runId, {
1709
+ rerunTasks: ["repair"],
1710
+ rerunDependentTasks: true
1711
+ });
1712
+ const repaired = await adapter.waitForRepair(runId, repairId, waitOptions(env));
1713
+ if (repaired.resultState !== "SUCCESS") {
1714
+ throw new Error(`Certification repair ${repairId} ended in ${repaired.resultState}`);
1715
+ }
1716
+ assertTask(repaired.tasks, "repair", "SUCCESS");
1717
+ const cancellationRunId = await adapter.submit(cancellationRequest(paths));
1718
+ await adapter.waitUntilActive(cancellationRunId, waitOptions(env));
1719
+ await adapter.cancel(cancellationRunId);
1720
+ const canceled = await adapter.wait(cancellationRunId, waitOptions(env));
1721
+ if (canceled.resultState !== "CANCELED") {
1722
+ throw new Error(`Certification cancellation ended in ${canceled.resultState}`);
1723
+ }
1724
+ return {
1725
+ runId,
1726
+ repairId,
1727
+ cancellationRunId,
1728
+ taskValues: true,
1729
+ retry: true,
1730
+ condition: true,
1731
+ forEach: true,
1732
+ repair: true,
1733
+ cancellation: true,
1734
+ fixtureRoot: root
1735
+ };
1736
+ } finally {
1737
+ await client.post("/api/2.0/workspace/delete", { path: root, recursive: true });
1738
+ }
1739
+ }
1740
+ };
1741
+ }
1742
+ async function importNotebooks(client, paths) {
1743
+ await client.post("/api/2.0/workspace/mkdirs", {
1744
+ path: paths.seed.slice(0, paths.seed.lastIndexOf("/"))
1745
+ });
1746
+ for (const [name, source] of Object.entries(NOTEBOOKS)) {
1747
+ await client.post("/api/2.0/workspace/import", {
1748
+ path: paths[name],
1749
+ format: "SOURCE",
1750
+ language: "PYTHON",
1751
+ overwrite: true,
1752
+ content: Buffer.from(source).toString("base64")
1753
+ });
1754
+ }
1755
+ }
1756
+ function certificationRequest(paths) {
1757
+ return {
1758
+ run_name: "fabric-experiments-jobs-certification",
1759
+ tasks: [
1760
+ {
1761
+ task_key: "retry",
1762
+ notebook_task: {
1763
+ notebook_path: paths.retry,
1764
+ base_parameters: { execution_count: "{{task.execution_count}}" }
1765
+ },
1766
+ max_retries: 1
1767
+ },
1768
+ {
1769
+ task_key: "seed",
1770
+ depends_on: [{ task_key: "retry" }],
1771
+ notebook_task: { notebook_path: paths.seed }
1772
+ },
1773
+ {
1774
+ task_key: "branch",
1775
+ depends_on: [{ task_key: "seed" }],
1776
+ condition_task: {
1777
+ left: "{{tasks.seed.values.branch}}",
1778
+ op: "EQUAL_TO",
1779
+ right: "run"
1780
+ }
1781
+ },
1782
+ {
1783
+ task_key: "foreach",
1784
+ depends_on: [{ task_key: "branch", outcome: "true" }],
1785
+ for_each_task: {
1786
+ inputs: "{{tasks.seed.values.items}}",
1787
+ concurrency: 2,
1788
+ task: {
1789
+ task_key: "process_item",
1790
+ notebook_task: {
1791
+ notebook_path: paths.process,
1792
+ base_parameters: { item: "{{input}}" }
1793
+ }
1794
+ }
1795
+ }
1796
+ },
1797
+ {
1798
+ task_key: "repair",
1799
+ depends_on: [{ task_key: "foreach" }],
1800
+ notebook_task: {
1801
+ notebook_path: paths.repair,
1802
+ base_parameters: { repair_count: "{{job.repair_count}}" }
1803
+ }
1804
+ }
1805
+ ]
1806
+ };
1807
+ }
1808
+ function cancellationRequest(paths) {
1809
+ return {
1810
+ run_name: "fabric-experiments-jobs-cancellation-certification",
1811
+ tasks: [{ task_key: "sleep", notebook_task: { notebook_path: paths.sleep } }]
1812
+ };
1813
+ }
1814
+ function waitOptions(env) {
1815
+ return {
1816
+ timeoutMs: Number(env.DBX_TEST_TIMEOUT_MS ?? 9e5),
1817
+ pollIntervalMs: Number(env.DBX_TEST_POLL_INTERVAL_MS ?? 5e3)
1818
+ };
1819
+ }
1820
+ function assertTask(tasks, taskKey, resultState) {
1821
+ const task = tasks.find((candidate) => candidate.taskKey === taskKey);
1822
+ if (!task) throw new Error(`Certification result did not contain task '${taskKey}'`);
1823
+ if (task.resultState !== resultState) {
1824
+ throw new Error(
1825
+ `Certification task '${taskKey}' ended in ${task.resultState}, expected ${resultState}`
1826
+ );
1827
+ }
1828
+ return task;
1829
+ }
1543
1830
 
1544
1831
  // src/jobs-target-pack.ts
1545
1832
  function createLakeflowJobsTargetPack() {
@@ -1547,8 +1834,8 @@ function createLakeflowJobsTargetPack() {
1547
1834
  id: "lakeflow-jobs",
1548
1835
  name: "Lakeflow Jobs orchestration",
1549
1836
  description: "Typed multi-task DAG, branch/loop, retry, cancellation, repair and task-outcome validation.",
1550
- version: "0.1.0",
1551
- maturity: "shipped",
1837
+ version: "0.2.0",
1838
+ maturity: "live-gated",
1552
1839
  capabilities: [
1553
1840
  "jobs.multi-task-dag",
1554
1841
  "jobs.dependencies",
@@ -1559,7 +1846,12 @@ function createLakeflowJobsTargetPack() {
1559
1846
  "jobs.repair",
1560
1847
  "jobs.task-outcomes"
1561
1848
  ],
1562
- checks: () => [restrictedPrincipalCheck(), jobRunCheck(), jobsOrchestrationCheck()],
1849
+ checks: () => [
1850
+ restrictedPrincipalCheck(),
1851
+ jobRunCheck(),
1852
+ jobsOrchestrationCheck(),
1853
+ jobsCertificationCheck()
1854
+ ],
1563
1855
  requiredChecks: ["jobs-orchestration"],
1564
1856
  requirements: [
1565
1857
  {
@@ -1582,11 +1874,14 @@ function createLakeflowJobsTargetPack() {
1582
1874
  {
1583
1875
  id: "orchestration-spec",
1584
1876
  description: "JSON multi-task orchestration scenario",
1585
- anyOf: ["DBX_TEST_JOBS_ORCHESTRATION_JSON"]
1877
+ anyOf: ["DBX_TEST_JOBS_ORCHESTRATION_JSON"],
1878
+ required: false
1586
1879
  }
1587
1880
  ],
1588
- docsUrl: "https://experiments.fabric.pro/docs/testing/target-packs/#pack-1--lakeflow-jobs-orchestration",
1589
- certificationScopes: []
1881
+ docsUrl: "https://experiments.fabric.pro/docs/testing/target-packs/#lakeflow-jobs-orchestration",
1882
+ certificationScopes: [
1883
+ "Azure Databricks serverless Jobs, West US, workspace OAuth, public network path"
1884
+ ]
1590
1885
  });
1591
1886
  }
1592
1887
 
@@ -1596,6 +1891,6 @@ function createBuiltinTargetPacks() {
1596
1891
  }
1597
1892
  var builtinTargetPacks = createBuiltinTargetPacks();
1598
1893
 
1599
- export { DatabricksJobsAdapter, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createEphemeralLakebaseBranch, createExecutionContext, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMockDatabricksClient, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, foundationTargetPacks, jobRunCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, normalizeJobRun, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, performanceBudgetCheck, pipelineRefreshCheck, renderJUnit, resolveLakebaseProject, resolveProfile, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, volumeIOCheck, waitForPipelineUpdate };
1894
+ export { DatabricksJobsAdapter, appHealthCheck, assertDeltaContract, autoLoaderIngestionCheck, backupRestoreCheck, builtinTargetPacks, classicComputeCheck, createAppsOperationalFoundationPack, createBuiltinTargetPacks, createEphemeralLakebaseBranch, createExecutionContext, createFoundationTargetPacks, createJobsCodeFoundationPack, createLakebaseTestProvider, createLakeflowFoundationPack, createLakeflowJobsTargetPack, createMockDatabricksClient, createSqlDeltaFoundationPack, createTargetPackRegistry, createUnityStorageFoundationPack, customLiveCheck, dbtBuildCheck, defineLiveSuite, defineTargetPack, defineTargetPackRun, deleteEphemeralLakebaseBranch, deleteVolumeFile, deltaContractCheck, doctorTargetPack, ensureVolumeDirectory, expectQueryToMatchGolden, expectTable, failureRecoveryCheck, foundationTargetPacks, jobRunCheck, jobsCertificationCheck, jobsOrchestrationCheck, lakebaseCredentialCheck, lakebaseRoundTripCheck, normalizeJobRun, normalizeVolumeRoot, notebookSubmitCheck, parseJobOrchestrationLiveSpec, performanceBudgetCheck, pipelineRefreshCheck, renderJUnit, resolveLakebaseProject, resolveProfile, restrictedPrincipalCheck, rollbackCheck, runLiveSuite, runTargetPack, secretRotationCheck, secretScopeCheck, serverlessComputeCheck, sqlRoundTripCheck, toLakebaseBranchId, unityCatalogAccessCheck, uploadVolumeFile, validateJobGraph, volumeIOCheck, waitForPipelineUpdate };
1600
1895
  //# sourceMappingURL=index.js.map
1601
1896
  //# sourceMappingURL=index.js.map