@shipfox/api-workflows 11.0.0 → 12.1.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +107 -0
- package/README.md +75 -0
- package/dist/core/agent-defaults.d.ts +2 -1
- package/dist/core/agent-defaults.d.ts.map +1 -1
- package/dist/core/agent-defaults.js.map +1 -1
- package/dist/core/checkout.d.ts +7 -21
- package/dist/core/checkout.d.ts.map +1 -1
- package/dist/core/checkout.js +122 -41
- package/dist/core/checkout.js.map +1 -1
- package/dist/core/entities/job-execution.d.ts +8 -0
- package/dist/core/entities/job-execution.d.ts.map +1 -1
- package/dist/core/entities/job-execution.js +13 -1
- package/dist/core/entities/job-execution.js.map +1 -1
- package/dist/core/entities/job-listener-event.d.ts +2 -0
- package/dist/core/entities/job-listener-event.d.ts.map +1 -1
- package/dist/core/entities/job-listener-event.js.map +1 -1
- package/dist/core/entities/step.d.ts +13 -3
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/entities/step.js +6 -0
- package/dist/core/entities/step.js.map +1 -1
- package/dist/core/entities/workflow-run-attempt.d.ts +1 -0
- package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
- package/dist/core/entities/workflow-run-attempt.js.map +1 -1
- package/dist/core/entities/workflow-run.d.ts +17 -0
- package/dist/core/entities/workflow-run.d.ts.map +1 -1
- package/dist/core/entities/workflow-run.js.map +1 -1
- package/dist/core/errors.d.ts +9 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +10 -5
- package/dist/core/errors.js.map +1 -1
- package/dist/core/job-execution.d.ts.map +1 -1
- package/dist/core/job-execution.js +14 -8
- package/dist/core/job-execution.js.map +1 -1
- package/dist/core/job-transition/decide-job-activation.d.ts +1 -0
- package/dist/core/job-transition/decide-job-activation.d.ts.map +1 -1
- package/dist/core/job-transition/decide-job-activation.js +1 -0
- package/dist/core/job-transition/decide-job-activation.js.map +1 -1
- package/dist/core/job-transition/derive-job-success.d.ts +1 -0
- package/dist/core/job-transition/derive-job-success.d.ts.map +1 -1
- package/dist/core/job-transition/derive-job-success.js +5 -8
- package/dist/core/job-transition/derive-job-success.js.map +1 -1
- package/dist/core/listener-execution-materialization.d.ts +6 -3
- package/dist/core/listener-execution-materialization.d.ts.map +1 -1
- package/dist/core/listener-execution-materialization.js +44 -6
- package/dist/core/listener-execution-materialization.js.map +1 -1
- package/dist/core/resolve-trigger-reference.d.ts +11 -0
- package/dist/core/resolve-trigger-reference.d.ts.map +1 -0
- package/dist/core/resolve-trigger-reference.js +39 -0
- package/dist/core/resolve-trigger-reference.js.map +1 -0
- package/dist/core/run-workflow.d.ts +1 -0
- package/dist/core/run-workflow.d.ts.map +1 -1
- package/dist/core/run-workflow.js +1 -0
- package/dist/core/run-workflow.js.map +1 -1
- package/dist/core/step-config/agent.d.ts +1 -2
- package/dist/core/step-config/agent.d.ts.map +1 -1
- package/dist/core/step-config/agent.js +22 -7
- package/dist/core/step-config/agent.js.map +1 -1
- package/dist/core/step-config/assemble-run-context.d.ts +19 -8
- package/dist/core/step-config/assemble-run-context.d.ts.map +1 -1
- package/dist/core/step-config/assemble-run-context.js +51 -19
- package/dist/core/step-config/assemble-run-context.js.map +1 -1
- package/dist/core/step-config/complete-step-dispatch-config.d.ts.map +1 -1
- package/dist/core/step-config/complete-step-dispatch-config.js +72 -4
- package/dist/core/step-config/complete-step-dispatch-config.js.map +1 -1
- package/dist/core/step-config/index.d.ts +1 -0
- package/dist/core/step-config/index.d.ts.map +1 -1
- package/dist/core/step-config/index.js +1 -0
- package/dist/core/step-config/index.js.map +1 -1
- package/dist/core/step-config/materialize-job-execution-steps.d.ts +1 -1
- package/dist/core/step-config/materialize-job-execution-steps.d.ts.map +1 -1
- package/dist/core/step-config/materialize-job-execution-steps.js +49 -8
- package/dist/core/step-config/materialize-job-execution-steps.js.map +1 -1
- package/dist/core/step-config/materialize-workflow-model.d.ts +3 -3
- package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -1
- package/dist/core/step-config/materialize-workflow-model.js +9 -5
- package/dist/core/step-config/materialize-workflow-model.js.map +1 -1
- package/dist/core/step-config/resolve-job-execution-name.d.ts +3 -3
- package/dist/core/step-config/resolve-job-execution-name.d.ts.map +1 -1
- package/dist/core/step-config/resolve-job-execution-name.js +24 -13
- package/dist/core/step-config/resolve-job-execution-name.js.map +1 -1
- package/dist/core/step-config/resolve-step-config.d.ts.map +1 -1
- package/dist/core/step-config/resolve-step-config.js +174 -9
- package/dist/core/step-config/resolve-step-config.js.map +1 -1
- package/dist/core/step-config/resolve-workflow-run-name.d.ts +19 -0
- package/dist/core/step-config/resolve-workflow-run-name.d.ts.map +1 -0
- package/dist/core/step-config/resolve-workflow-run-name.js +73 -0
- package/dist/core/step-config/resolve-workflow-run-name.js.map +1 -0
- package/dist/core/step-transition/decide-step-transition.js.map +1 -1
- package/dist/core/step-transition/evaluate-gate.d.ts +2 -1
- package/dist/core/step-transition/evaluate-gate.d.ts.map +1 -1
- package/dist/core/step-transition/evaluate-gate.js +5 -3
- package/dist/core/step-transition/evaluate-gate.js.map +1 -1
- package/dist/core/workflow-run-creation.d.ts +3 -0
- package/dist/core/workflow-run-creation.d.ts.map +1 -1
- package/dist/core/workflow-run-creation.js +22 -7
- package/dist/core/workflow-run-creation.js.map +1 -1
- package/dist/db/db.d.ts +278 -10
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +2 -0
- package/dist/db/db.js.map +1 -1
- package/dist/db/index.d.ts +3 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +2 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/job-listener-events.d.ts +2 -0
- package/dist/db/job-listener-events.d.ts.map +1 -1
- package/dist/db/job-listener-events.js +1 -0
- package/dist/db/job-listener-events.js.map +1 -1
- package/dist/db/job-listeners.d.ts +2 -0
- package/dist/db/job-listeners.d.ts.map +1 -1
- package/dist/db/job-listeners.js +81 -21
- package/dist/db/job-listeners.js.map +1 -1
- package/dist/db/schema/job-executions.d.ts +3 -3
- package/dist/db/schema/job-executions.d.ts.map +1 -1
- package/dist/db/schema/job-executions.js +8 -4
- package/dist/db/schema/job-executions.js.map +1 -1
- package/dist/db/schema/job-listener-events.d.ts +20 -0
- package/dist/db/schema/job-listener-events.d.ts.map +1 -1
- package/dist/db/schema/job-listener-events.js +2 -0
- package/dist/db/schema/job-listener-events.js.map +1 -1
- package/dist/db/schema/step-attempts.js +2 -2
- package/dist/db/schema/step-attempts.js.map +1 -1
- package/dist/db/schema/steps.d.ts +4 -2
- package/dist/db/schema/steps.d.ts.map +1 -1
- package/dist/db/schema/steps.js +1 -1
- package/dist/db/schema/steps.js.map +1 -1
- package/dist/db/schema/workflow-run-attempts.d.ts +21 -2
- package/dist/db/schema/workflow-run-attempts.d.ts.map +1 -1
- package/dist/db/schema/workflow-run-attempts.js +2 -0
- package/dist/db/schema/workflow-run-attempts.js.map +1 -1
- package/dist/db/schema/workflow-run-counters.d.ts +43 -0
- package/dist/db/schema/workflow-run-counters.d.ts.map +1 -0
- package/dist/db/schema/workflow-run-counters.js +10 -0
- package/dist/db/schema/workflow-run-counters.js.map +1 -0
- package/dist/db/schema/workflow-runs.d.ts +54 -1
- package/dist/db/schema/workflow-runs.d.ts.map +1 -1
- package/dist/db/schema/workflow-runs.js +10 -2
- package/dist/db/schema/workflow-runs.js.map +1 -1
- package/dist/db/workflow-runs/job-executions.d.ts.map +1 -1
- package/dist/db/workflow-runs/job-executions.js +35 -14
- package/dist/db/workflow-runs/job-executions.js.map +1 -1
- package/dist/db/workflow-runs/jobs.d.ts +2 -0
- package/dist/db/workflow-runs/jobs.d.ts.map +1 -1
- package/dist/db/workflow-runs/jobs.js +9 -5
- package/dist/db/workflow-runs/jobs.js.map +1 -1
- package/dist/db/workflow-runs/queries.d.ts +51 -0
- package/dist/db/workflow-runs/queries.d.ts.map +1 -1
- package/dist/db/workflow-runs/queries.js +82 -2
- package/dist/db/workflow-runs/queries.js.map +1 -1
- package/dist/db/workflow-runs/run-create.d.ts +1 -0
- package/dist/db/workflow-runs/run-create.d.ts.map +1 -1
- package/dist/db/workflow-runs/run-create.js +159 -32
- package/dist/db/workflow-runs/run-create.js.map +1 -1
- package/dist/db/workflow-runs/run-rerun.d.ts.map +1 -1
- package/dist/db/workflow-runs/run-rerun.js +13 -5
- package/dist/db/workflow-runs/run-rerun.js.map +1 -1
- package/dist/db/workflow-runs/shared.d.ts +1 -0
- package/dist/db/workflow-runs/shared.d.ts.map +1 -1
- package/dist/db/workflow-runs/shared.js +2 -1
- package/dist/db/workflow-runs/shared.js.map +1 -1
- package/dist/db/workflow-runs/steps.js +3 -3
- package/dist/db/workflow-runs/steps.js.map +1 -1
- package/dist/db/workflow-runs.d.ts +4 -3
- package/dist/db/workflow-runs.d.ts.map +1 -1
- package/dist/db/workflow-runs.js +3 -2
- package/dist/db/workflow-runs.js.map +1 -1
- package/dist/metrics/instance.d.ts +1 -0
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +9 -0
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/dto/checkout-token.d.ts +1 -0
- package/dist/presentation/dto/checkout-token.d.ts.map +1 -1
- package/dist/presentation/dto/checkout-token.js +1 -0
- package/dist/presentation/dto/checkout-token.js.map +1 -1
- package/dist/presentation/dto/index.d.ts +1 -1
- package/dist/presentation/dto/index.d.ts.map +1 -1
- package/dist/presentation/dto/index.js +1 -1
- package/dist/presentation/dto/index.js.map +1 -1
- package/dist/presentation/dto/step.d.ts.map +1 -1
- package/dist/presentation/dto/step.js +2 -2
- package/dist/presentation/dto/step.js.map +1 -1
- package/dist/presentation/dto/workflow-run.d.ts +3 -1
- package/dist/presentation/dto/workflow-run.d.ts.map +1 -1
- package/dist/presentation/dto/workflow-run.js +34 -0
- package/dist/presentation/dto/workflow-run.js.map +1 -1
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +31 -3
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/checkout-token.d.ts +1 -1
- package/dist/presentation/routes/checkout-token.d.ts.map +1 -1
- package/dist/presentation/routes/checkout-token.js +32 -20
- package/dist/presentation/routes/checkout-token.js.map +1 -1
- package/dist/presentation/routes/leased-step.d.ts +2 -0
- package/dist/presentation/routes/leased-step.d.ts.map +1 -1
- package/dist/presentation/routes/leased-step.js +2 -1
- package/dist/presentation/routes/leased-step.js.map +1 -1
- package/dist/presentation/routes/list-runs.d.ts.map +1 -1
- package/dist/presentation/routes/list-runs.js +9 -3
- package/dist/presentation/routes/list-runs.js.map +1 -1
- package/dist/presentation/routes/project-access.d.ts +1 -0
- package/dist/presentation/routes/project-access.d.ts.map +1 -1
- package/dist/presentation/routes/report-step.d.ts.map +1 -1
- package/dist/presentation/routes/report-step.js +9 -2
- package/dist/presentation/routes/report-step.js.map +1 -1
- package/dist/presentation/subscribers/on-job-steps-settled.js +1 -1
- package/dist/presentation/subscribers/on-job-steps-settled.js.map +1 -1
- package/dist/presentation/subscribers/on-runner-job-claimed.d.ts.map +1 -1
- package/dist/presentation/subscribers/on-runner-job-claimed.js +21 -0
- package/dist/presentation/subscribers/on-runner-job-claimed.js.map +1 -1
- package/dist/temporal/activities/index.d.ts.map +1 -1
- package/dist/temporal/activities/index.js +2 -1
- package/dist/temporal/activities/index.js.map +1 -1
- package/dist/temporal/activities/orchestration-activities.d.ts +1 -0
- package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -1
- package/dist/temporal/activities/orchestration-activities.js.map +1 -1
- package/dist/temporal/constants.d.ts +1 -0
- package/dist/temporal/constants.d.ts.map +1 -1
- package/dist/temporal/constants.js +1 -0
- package/dist/temporal/constants.js.map +1 -1
- package/dist/temporal/index.d.ts +1 -1
- package/dist/temporal/index.d.ts.map +1 -1
- package/dist/temporal/index.js +1 -1
- package/dist/temporal/index.js.map +1 -1
- package/dist/temporal/workflows/index.bundle.js +82 -43
- package/dist/temporal/workflows/index.d.ts +1 -1
- package/dist/temporal/workflows/index.d.ts.map +1 -1
- package/dist/temporal/workflows/index.js +1 -1
- package/dist/temporal/workflows/index.js.map +1 -1
- package/dist/temporal/workflows/job-execution-orchestration.d.ts +5 -0
- package/dist/temporal/workflows/job-execution-orchestration.d.ts.map +1 -1
- package/dist/temporal/workflows/job-execution-orchestration.js +77 -43
- package/dist/temporal/workflows/job-execution-orchestration.js.map +1 -1
- package/dist/temporal/workflows/test-env.d.ts +5 -1
- package/dist/temporal/workflows/test-env.d.ts.map +1 -1
- package/dist/temporal/workflows/test-env.js +32 -11
- package/dist/temporal/workflows/test-env.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0000_initial.sql +14 -2
- package/drizzle/0001_windy_sunfire.sql +1 -0
- package/drizzle/meta/0000_snapshot.json +93 -1
- package/drizzle/meta/0001_snapshot.json +1711 -0
- package/drizzle/meta/_journal.json +2 -2
- package/package.json +19 -19
- package/src/core/agent-defaults.ts +2 -1
- package/src/core/checkout.test.ts +378 -67
- package/src/core/checkout.ts +142 -59
- package/src/core/entities/job-execution.test.ts +21 -0
- package/src/core/entities/job-execution.ts +24 -0
- package/src/core/entities/job-listener-event.ts +3 -0
- package/src/core/entities/step.ts +15 -3
- package/src/core/entities/workflow-run-attempt.ts +1 -0
- package/src/core/entities/workflow-run.ts +16 -0
- package/src/core/errors.ts +21 -7
- package/src/core/job-execution.ts +27 -4
- package/src/core/job-transition/decide-job-activation.test.ts +4 -0
- package/src/core/job-transition/decide-job-activation.ts +2 -0
- package/src/core/job-transition/derive-job-success.test.ts +12 -0
- package/src/core/job-transition/derive-job-success.ts +6 -9
- package/src/core/listener-execution-materialization.test.ts +2 -0
- package/src/core/listener-execution-materialization.ts +57 -11
- package/src/core/resolve-trigger-reference.test.ts +160 -0
- package/src/core/resolve-trigger-reference.ts +53 -0
- package/src/core/run-workflow.ts +2 -0
- package/src/core/step-config/agent.ts +29 -12
- package/src/core/step-config/assemble-run-context.test.ts +149 -6
- package/src/core/step-config/assemble-run-context.ts +87 -25
- package/src/core/step-config/complete-step-dispatch-config.test.ts +125 -2
- package/src/core/step-config/complete-step-dispatch-config.ts +83 -1
- package/src/core/step-config/index.ts +7 -0
- package/src/core/step-config/materialize-job-execution-steps.test.ts +250 -1
- package/src/core/step-config/materialize-job-execution-steps.ts +57 -10
- package/src/core/step-config/materialize-workflow-model.test.ts +212 -4
- package/src/core/step-config/materialize-workflow-model.ts +33 -28
- package/src/core/step-config/resolve-job-execution-name.test.ts +37 -15
- package/src/core/step-config/resolve-job-execution-name.ts +30 -15
- package/src/core/step-config/resolve-step-config.ts +175 -10
- package/src/core/step-config/resolve-workflow-run-name.test.ts +115 -0
- package/src/core/step-config/resolve-workflow-run-name.ts +108 -0
- package/src/core/step-transition/decide-step-transition.ts +2 -2
- package/src/core/step-transition/evaluate-gate.test.ts +8 -0
- package/src/core/step-transition/evaluate-gate.ts +8 -1
- package/src/core/workflow-run-creation.test.ts +7 -4
- package/src/core/workflow-run-creation.ts +13 -7
- package/src/db/db.ts +2 -0
- package/src/db/index.ts +6 -0
- package/src/db/job-listener-events.test.ts +19 -0
- package/src/db/job-listener-events.ts +3 -0
- package/src/db/job-listeners.test.ts +187 -5
- package/src/db/job-listeners.ts +122 -30
- package/src/db/schema/job-executions.ts +12 -5
- package/src/db/schema/job-listener-events.ts +3 -0
- package/src/db/schema/step-attempts.ts +2 -2
- package/src/db/schema/steps.ts +2 -1
- package/src/db/schema/workflow-run-attempts.ts +2 -0
- package/src/db/schema/workflow-run-counters.ts +13 -0
- package/src/db/schema/workflow-runs.ts +11 -2
- package/src/db/workflow-runs/job-executions.ts +37 -15
- package/src/db/workflow-runs/jobs.ts +17 -4
- package/src/db/workflow-runs/queries.test.ts +206 -0
- package/src/db/workflow-runs/queries.ts +146 -2
- package/src/db/workflow-runs/run-create.test.ts +606 -8
- package/src/db/workflow-runs/run-create.ts +185 -40
- package/src/db/workflow-runs/run-rerun.test.ts +61 -2
- package/src/db/workflow-runs/run-rerun.ts +15 -5
- package/src/db/workflow-runs/shared.ts +2 -0
- package/src/db/workflow-runs/steps.ts +3 -3
- package/src/db/workflow-runs.ts +7 -0
- package/src/metrics/instance.ts +14 -0
- package/src/presentation/dto/checkout-token.test.ts +19 -9
- package/src/presentation/dto/checkout-token.ts +2 -1
- package/src/presentation/dto/index.ts +1 -1
- package/src/presentation/dto/job.test.ts +9 -0
- package/src/presentation/dto/step.test.ts +12 -0
- package/src/presentation/dto/step.ts +5 -2
- package/src/presentation/dto/workflow-run.ts +44 -2
- package/src/presentation/inter-module.test.ts +165 -0
- package/src/presentation/inter-module.ts +38 -4
- package/src/presentation/routes/checkout-token.test.ts +357 -142
- package/src/presentation/routes/checkout-token.ts +56 -26
- package/src/presentation/routes/get-run.test.ts +2 -0
- package/src/presentation/routes/get-step-secrets.test.ts +7 -2
- package/src/presentation/routes/leased-step.ts +9 -1
- package/src/presentation/routes/list-runs.test.ts +57 -0
- package/src/presentation/routes/list-runs.ts +8 -3
- package/src/presentation/routes/report-step.test.ts +25 -0
- package/src/presentation/routes/report-step.ts +10 -2
- package/src/presentation/subscribers/on-job-steps-settled.ts +1 -1
- package/src/presentation/subscribers/on-runner-job-claimed.test.ts +49 -0
- package/src/presentation/subscribers/on-runner-job-claimed.ts +22 -0
- package/src/temporal/activities/index.ts +1 -0
- package/src/temporal/activities/orchestration-activities.ts +1 -0
- package/src/temporal/constants.ts +1 -0
- package/src/temporal/index.ts +1 -0
- package/src/temporal/workflows/index.ts +1 -0
- package/src/temporal/workflows/job-execution-orchestration.test.ts +142 -6
- package/src/temporal/workflows/job-execution-orchestration.ts +99 -50
- package/src/temporal/workflows/run-orchestration.test.ts +1 -1
- package/src/temporal/workflows/test-env.ts +50 -13
- package/test/factories/project.ts +2 -0
- package/test/factories/workflow-model.ts +80 -26
- package/test/factories/workflow-run.ts +4 -1
- package/test/fixtures/agent-inter-module.ts +2 -1
- package/test/fixtures/job-with-steps.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/drizzle/0001_agent_tool_materialization.sql +0 -1
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createWorkflowModelSnapshot,
|
|
3
|
+
WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS,
|
|
4
|
+
type WorkflowModel,
|
|
5
|
+
} from '@shipfox/api-definitions-dto';
|
|
2
6
|
import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';
|
|
3
7
|
import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';
|
|
4
8
|
import type {SecretsInterModuleClient} from '@shipfox/api-secrets-dto/inter-module';
|
|
5
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
analyzeContextKeyAccess,
|
|
11
|
+
type ResolvedFieldSegment,
|
|
12
|
+
type WorkflowExpression,
|
|
13
|
+
} from '@shipfox/expression';
|
|
6
14
|
import {logger} from '@shipfox/node-opentelemetry';
|
|
7
|
-
import {eq} from 'drizzle-orm';
|
|
15
|
+
import {eq, sql} from 'drizzle-orm';
|
|
8
16
|
import type {AgentDefaultsResolver} from '#core/agent-defaults.js';
|
|
9
17
|
import {
|
|
10
18
|
createAgentToolMaterializationSnapshot,
|
|
@@ -16,15 +24,22 @@ import type {
|
|
|
16
24
|
WorkflowSourceSnapshot,
|
|
17
25
|
} from '#core/entities/workflow-run.js';
|
|
18
26
|
import {InterpolationUnresolvableError} from '#core/errors.js';
|
|
27
|
+
import {resolveWorkflowRunTriggerReference} from '#core/resolve-trigger-reference.js';
|
|
28
|
+
import {assembleCreationContext} from '#core/step-config/assemble-run-context.js';
|
|
19
29
|
import type {MaterializedWorkflowJob} from '#core/step-config/materialize-workflow-model.js';
|
|
20
30
|
import type {WorkflowStepTemplateDiagnostic} from '#core/step-config/resolve-step-config.js';
|
|
31
|
+
import {resolveWorkflowRunName} from '#core/step-config/resolve-workflow-run-name.js';
|
|
21
32
|
import {
|
|
22
33
|
deriveInitialJobExecutionPlan,
|
|
23
34
|
materializeWorkflowRunJobs,
|
|
24
35
|
} from '#core/workflow-run-creation.js';
|
|
25
|
-
import {
|
|
26
|
-
|
|
36
|
+
import {
|
|
37
|
+
recordWorkflowDisplayNameResolutionDegraded,
|
|
38
|
+
recordWorkflowRunCreated,
|
|
39
|
+
} from '#metrics/instance.js';
|
|
40
|
+
import {db, type Tx} from '../db.js';
|
|
27
41
|
import {workflowRunAttempts} from '../schema/workflow-run-attempts.js';
|
|
42
|
+
import {workflowRunCounters} from '../schema/workflow-run-counters.js';
|
|
28
43
|
import {toWorkflowRun, workflowRuns} from '../schema/workflow-runs.js';
|
|
29
44
|
import {type MaterializedRunGraphJob, persistMaterializedRunGraph} from './run-graph.js';
|
|
30
45
|
|
|
@@ -44,6 +59,7 @@ export interface CreateWorkflowRunParams {
|
|
|
44
59
|
name?: string | undefined;
|
|
45
60
|
model: WorkflowModel;
|
|
46
61
|
triggerPayload: TriggerPayload;
|
|
62
|
+
triggerConnectionId?: string | undefined;
|
|
47
63
|
inputs?: Record<string, unknown> | undefined;
|
|
48
64
|
sourceSnapshot?: WorkflowSourceSnapshot | null | undefined;
|
|
49
65
|
triggerIdempotencyKey?: string | undefined;
|
|
@@ -54,6 +70,14 @@ export interface CreateWorkflowRunParams {
|
|
|
54
70
|
}
|
|
55
71
|
|
|
56
72
|
export async function createWorkflowRun(params: CreateWorkflowRunParams): Promise<WorkflowRun> {
|
|
73
|
+
const triggerReference = await resolveWorkflowRunTriggerReference({
|
|
74
|
+
workspaceId: params.workspaceId,
|
|
75
|
+
triggerConnectionId: params.triggerConnectionId,
|
|
76
|
+
triggerPayload: params.triggerPayload,
|
|
77
|
+
integrations: params.integrations,
|
|
78
|
+
projects: params.projects,
|
|
79
|
+
});
|
|
80
|
+
const staticName = params.name ?? params.model.name;
|
|
57
81
|
const agentToolContext =
|
|
58
82
|
params.integrations === undefined
|
|
59
83
|
? undefined
|
|
@@ -69,19 +93,42 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
|
|
|
69
93
|
context: agentToolContext,
|
|
70
94
|
});
|
|
71
95
|
const result = await db().transaction(async (tx) => {
|
|
96
|
+
// Serialize idempotent trigger resolution separately from per-definition number
|
|
97
|
+
// allocation so a replay never consumes a number, including when two deliveries
|
|
98
|
+
// race before either run is visible.
|
|
99
|
+
if (params.triggerIdempotencyKey) {
|
|
100
|
+
await tx.execute(
|
|
101
|
+
sql`select pg_advisory_xact_lock(hashtext(${params.triggerIdempotencyKey}))`,
|
|
102
|
+
);
|
|
103
|
+
const existing = await tx
|
|
104
|
+
.select()
|
|
105
|
+
.from(workflowRuns)
|
|
106
|
+
.where(eq(workflowRuns.triggerIdempotencyKey, params.triggerIdempotencyKey))
|
|
107
|
+
.limit(1);
|
|
108
|
+
const existingRow = existing[0];
|
|
109
|
+
if (existingRow) return {run: toWorkflowRun(existingRow), created: false};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Keep allocation on the existing transaction so a trigger burst cannot pin
|
|
113
|
+
// every pool connection and then wait for a second connection per run.
|
|
114
|
+
const number = await allocateWorkflowRunNumber(tx, params.definitionId);
|
|
115
|
+
|
|
72
116
|
const insertResult = await tx
|
|
73
117
|
.insert(workflowRuns)
|
|
74
118
|
.values({
|
|
75
119
|
workspaceId: params.workspaceId,
|
|
76
120
|
projectId: params.projectId,
|
|
77
121
|
definitionId: params.definitionId,
|
|
78
|
-
|
|
122
|
+
number,
|
|
123
|
+
name: null,
|
|
124
|
+
workflowName: staticName,
|
|
79
125
|
status: 'pending',
|
|
80
126
|
currentAttempt: 1,
|
|
81
127
|
triggerProvider: params.triggerPayload.provider ?? null,
|
|
82
128
|
triggerSource: params.triggerPayload.source,
|
|
83
129
|
triggerEvent: params.triggerPayload.event,
|
|
84
130
|
triggerPayload: params.triggerPayload,
|
|
131
|
+
triggerReference,
|
|
85
132
|
inputs: params.inputs ?? null,
|
|
86
133
|
sourceSnapshot: params.sourceSnapshot ?? null,
|
|
87
134
|
triggerIdempotencyKey: params.triggerIdempotencyKey ?? null,
|
|
@@ -109,7 +156,38 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
|
|
|
109
156
|
return {run: toWorkflowRun(existingRow), created: false};
|
|
110
157
|
}
|
|
111
158
|
|
|
112
|
-
|
|
159
|
+
// Resolving run-creation templates and predicates here gives them a stable variable snapshot
|
|
160
|
+
// and interpolation access to the inserted run id. Run-name resolution is display-only and
|
|
161
|
+
// persists only a resolved override. If resolution fails, the transaction rolls back the run,
|
|
162
|
+
// jobs, steps, and outbox event together. Listening steps are resolved later when a job
|
|
163
|
+
// execution is created.
|
|
164
|
+
const provisionalRun = toWorkflowRun(runRow);
|
|
165
|
+
const oneShotJobs = params.model.jobs.filter((job) => job.mode !== 'listening');
|
|
166
|
+
const vars = await loadReferencedVariables({
|
|
167
|
+
model: params.model,
|
|
168
|
+
jobs: oneShotJobs,
|
|
169
|
+
workspaceId: params.workspaceId,
|
|
170
|
+
projectId: params.projectId,
|
|
171
|
+
definitionId: params.definitionId,
|
|
172
|
+
secrets: params.secrets,
|
|
173
|
+
});
|
|
174
|
+
const runNameResolution = resolveWorkflowRunName({
|
|
175
|
+
runName: params.model.runName,
|
|
176
|
+
context: assembleCreationContext({
|
|
177
|
+
run: provisionalRun,
|
|
178
|
+
triggerPayload: params.triggerPayload,
|
|
179
|
+
inputs: params.inputs ?? null,
|
|
180
|
+
vars,
|
|
181
|
+
}).values,
|
|
182
|
+
});
|
|
183
|
+
const [resolvedRunRow] = await tx
|
|
184
|
+
.update(workflowRuns)
|
|
185
|
+
.set({name: runNameResolution.value, updatedAt: new Date()})
|
|
186
|
+
.where(eq(workflowRuns.id, provisionalRun.id))
|
|
187
|
+
.returning();
|
|
188
|
+
if (!resolvedRunRow)
|
|
189
|
+
throw new Error(`Workflow run missing after name resolution: ${runRow.id}`);
|
|
190
|
+
const run = toWorkflowRun(resolvedRunRow);
|
|
113
191
|
const [attemptRow] = await tx
|
|
114
192
|
.insert(workflowRunAttempts)
|
|
115
193
|
.values({
|
|
@@ -117,23 +195,12 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
|
|
|
117
195
|
attempt: 1,
|
|
118
196
|
status: 'pending',
|
|
119
197
|
model: createWorkflowModelSnapshot(params.model),
|
|
198
|
+
vars,
|
|
120
199
|
agentToolMaterialization,
|
|
121
200
|
})
|
|
122
201
|
.returning();
|
|
123
202
|
if (!attemptRow) throw new Error('Insert returned no rows');
|
|
124
203
|
|
|
125
|
-
// Resolving one-shot templates here gives interpolation access to the inserted run id.
|
|
126
|
-
// If resolution fails, the transaction rolls back the run, jobs, steps, and outbox event together.
|
|
127
|
-
// Listening steps are resolved later when a job execution is created.
|
|
128
|
-
const oneShotJobs = params.model.jobs.filter((job) => job.mode !== 'listening');
|
|
129
|
-
const vars = await loadReferencedVariables({
|
|
130
|
-
model: params.model,
|
|
131
|
-
jobs: oneShotJobs,
|
|
132
|
-
workspaceId: params.workspaceId,
|
|
133
|
-
projectId: params.projectId,
|
|
134
|
-
definitionId: params.definitionId,
|
|
135
|
-
secrets: params.secrets,
|
|
136
|
-
});
|
|
137
204
|
const materializedJobs = await materializeWorkflowRunJobs({
|
|
138
205
|
run,
|
|
139
206
|
model: params.model,
|
|
@@ -171,15 +238,49 @@ export async function createWorkflowRun(params: CreateWorkflowRunParams): Promis
|
|
|
171
238
|
),
|
|
172
239
|
});
|
|
173
240
|
|
|
174
|
-
return {
|
|
241
|
+
return {
|
|
242
|
+
run,
|
|
243
|
+
created: true,
|
|
244
|
+
nameDegradation: runNameResolution.degradation,
|
|
245
|
+
};
|
|
175
246
|
});
|
|
176
247
|
|
|
177
|
-
if (result.created)
|
|
248
|
+
if (result.created && result.nameDegradation !== undefined) {
|
|
249
|
+
recordWorkflowDisplayNameResolutionDegraded('workflow.run_name', result.nameDegradation.cause);
|
|
250
|
+
logger().warn(
|
|
251
|
+
{
|
|
252
|
+
workflowRunId: result.run.id,
|
|
253
|
+
definitionId: result.run.definitionId,
|
|
254
|
+
field: 'workflow.run_name',
|
|
255
|
+
cause: result.nameDegradation.cause,
|
|
256
|
+
...(result.nameDegradation.expression === undefined
|
|
257
|
+
? {}
|
|
258
|
+
: {expression: result.nameDegradation.expression.slice(0, 256)}),
|
|
259
|
+
},
|
|
260
|
+
'Workflow run name resolution degraded to the static workflow name',
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (result.created) {
|
|
178
265
|
recordWorkflowRunCreated(result.run.triggerPayload.provider ?? result.run.triggerSource);
|
|
266
|
+
}
|
|
179
267
|
|
|
180
268
|
return result.run;
|
|
181
269
|
}
|
|
182
270
|
|
|
271
|
+
async function allocateWorkflowRunNumber(tx: Tx, definitionId: string): Promise<number> {
|
|
272
|
+
const [counterRow] = await tx
|
|
273
|
+
.insert(workflowRunCounters)
|
|
274
|
+
.values({definitionId, nextNumber: 2})
|
|
275
|
+
.onConflictDoUpdate({
|
|
276
|
+
target: workflowRunCounters.definitionId,
|
|
277
|
+
set: {nextNumber: sql`${workflowRunCounters.nextNumber} + 1`},
|
|
278
|
+
})
|
|
279
|
+
.returning({number: sql<number>`${workflowRunCounters.nextNumber} - 1`});
|
|
280
|
+
if (!counterRow) throw new Error('Run counter allocation returned no rows');
|
|
281
|
+
return counterRow.number;
|
|
282
|
+
}
|
|
283
|
+
|
|
183
284
|
export async function loadReferencedVariables(params: {
|
|
184
285
|
readonly model: WorkflowModel;
|
|
185
286
|
readonly jobs?: readonly WorkflowModelJob[] | undefined;
|
|
@@ -192,15 +293,22 @@ export async function loadReferencedVariables(params: {
|
|
|
192
293
|
const keys = [...new Set(references.map((reference) => reference.key))].sort();
|
|
193
294
|
if (keys.length === 0) return undefined;
|
|
194
295
|
|
|
195
|
-
|
|
296
|
+
const requiresSecrets = (reference: ReferencedVariable) =>
|
|
297
|
+
reference.field !== 'job.execution_name' && reference.field !== 'workflow.run_name';
|
|
298
|
+
const requiredReferences = references.filter(requiresSecrets);
|
|
299
|
+
const requiredKeys = new Set(requiredReferences.map((reference) => reference.key));
|
|
300
|
+
if (!params.secrets) {
|
|
301
|
+
if (requiredKeys.size === 0) return undefined;
|
|
302
|
+
throw new Error('Secrets client is not configured.');
|
|
303
|
+
}
|
|
196
304
|
const {values: vars} = await params.secrets.getVariablesByNamespace({
|
|
197
305
|
workspaceId: params.workspaceId,
|
|
198
306
|
projectId: params.projectId,
|
|
199
307
|
namespace: '',
|
|
200
308
|
});
|
|
201
|
-
const missingKey =
|
|
309
|
+
const missingKey = [...requiredKeys].find((key) => !(key in vars));
|
|
202
310
|
if (missingKey !== undefined) {
|
|
203
|
-
const reference =
|
|
311
|
+
const reference = requiredReferences.find((candidate) => candidate.key === missingKey);
|
|
204
312
|
throw new InterpolationUnresolvableError(params.definitionId, {
|
|
205
313
|
field: reference?.field ?? 'env',
|
|
206
314
|
source: reference?.source ?? `vars.${missingKey}`,
|
|
@@ -208,7 +316,12 @@ export async function loadReferencedVariables(params: {
|
|
|
208
316
|
});
|
|
209
317
|
}
|
|
210
318
|
|
|
211
|
-
|
|
319
|
+
const referencedVars: Record<string, string> = {};
|
|
320
|
+
for (const key of keys) {
|
|
321
|
+
const value = vars[key];
|
|
322
|
+
if (value !== undefined) referencedVars[key] = value;
|
|
323
|
+
}
|
|
324
|
+
return referencedVars;
|
|
212
325
|
}
|
|
213
326
|
|
|
214
327
|
function materializeRunGraphJobs(params: {
|
|
@@ -221,7 +334,7 @@ function materializeRunGraphJobs(params: {
|
|
|
221
334
|
job: {
|
|
222
335
|
key: job.key,
|
|
223
336
|
mode: job.mode,
|
|
224
|
-
name:
|
|
337
|
+
name: job.name ?? null,
|
|
225
338
|
status: 'pending' as const,
|
|
226
339
|
checkoutPersistCredentials: job.checkout.persistCredentials,
|
|
227
340
|
checkoutPermissionsContents: job.checkout.permissions.contents,
|
|
@@ -242,7 +355,7 @@ function materializeRunGraphJobs(params: {
|
|
|
242
355
|
createExecution: (jobRow) => {
|
|
243
356
|
if (jobRow.mode === 'listening') return undefined;
|
|
244
357
|
|
|
245
|
-
const fallbackName =
|
|
358
|
+
const fallbackName = jobRow.name ?? jobRow.key;
|
|
246
359
|
const modelJob = params.params.model.jobs[jobIndex];
|
|
247
360
|
if (!modelJob) return undefined;
|
|
248
361
|
const executionPlan = deriveInitialJobExecutionPlan({
|
|
@@ -259,7 +372,9 @@ function materializeRunGraphJobs(params: {
|
|
|
259
372
|
|
|
260
373
|
return {
|
|
261
374
|
sequence: 1,
|
|
262
|
-
|
|
375
|
+
// Persist only the resolved override. The core entity supplies the
|
|
376
|
+
// static job name/key when this is null.
|
|
377
|
+
name: executionPlan.nameOverride,
|
|
263
378
|
runner: [...executionPlan.runner],
|
|
264
379
|
status: 'pending' as const,
|
|
265
380
|
evaluationTrace:
|
|
@@ -288,12 +403,28 @@ function referencedVariables(
|
|
|
288
403
|
): readonly ReferencedVariable[] {
|
|
289
404
|
const references: ReferencedVariable[] = [];
|
|
290
405
|
|
|
406
|
+
for (const job of model.jobs) {
|
|
407
|
+
collectPredicateVariableReferences(job.if, references);
|
|
408
|
+
collectPredicateVariableReferences(job.success, references);
|
|
409
|
+
|
|
410
|
+
for (const trigger of [...(job.listening?.on ?? []), ...(job.listening?.until ?? [])]) {
|
|
411
|
+
collectPredicateVariableReferences(trigger.filter, references);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
for (const step of job.steps) {
|
|
415
|
+
collectPredicateVariableReferences(step.if, references);
|
|
416
|
+
collectPredicateVariableReferences(step.gate?.success, references);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
collectFieldVariableReferences(model.runName, references, {field: 'workflow.run_name'});
|
|
421
|
+
|
|
291
422
|
if (jobs.length > 0) {
|
|
292
423
|
collectTemplateVariableReferences(model.templates?.env, references);
|
|
293
424
|
}
|
|
294
425
|
|
|
295
426
|
for (const job of jobs) {
|
|
296
|
-
collectFieldVariableReferences(job.
|
|
427
|
+
collectFieldVariableReferences(job.executionName, references, {field: 'job.execution_name'});
|
|
297
428
|
for (const template of job.runnerTemplates ?? []) {
|
|
298
429
|
collectFieldVariableReferences(template, references, {field: 'job.runner'});
|
|
299
430
|
}
|
|
@@ -302,15 +433,22 @@ function referencedVariables(
|
|
|
302
433
|
|
|
303
434
|
for (const step of job.steps) {
|
|
304
435
|
collectFieldVariableReferences(step.templates?.name, references, {field: 'step.name'});
|
|
436
|
+
collectFieldVariableReferences(step.templates?.workingDirectory, references, {
|
|
437
|
+
field: 'step.working_directory',
|
|
438
|
+
});
|
|
305
439
|
if (step.kind === 'run') {
|
|
306
440
|
collectFieldVariableReferences(step.templates?.command, references, {field: 'run'});
|
|
307
441
|
collectTemplateVariableReferences(step.templates?.env, references);
|
|
308
|
-
} else {
|
|
442
|
+
} else if (step.kind === 'agent') {
|
|
309
443
|
collectFieldVariableReferences(step.templates?.prompt, references, {field: 'agent.prompt'});
|
|
310
444
|
collectFieldVariableReferences(step.templates?.model, references, {field: 'agent.model'});
|
|
311
445
|
collectFieldVariableReferences(step.templates?.provider, references, {
|
|
312
446
|
field: 'agent.provider',
|
|
313
447
|
});
|
|
448
|
+
} else if (step.kind === 'checkout') {
|
|
449
|
+
for (const [key, field] of WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS) {
|
|
450
|
+
collectFieldVariableReferences(step.checkout.templates?.[key], references, {field});
|
|
451
|
+
}
|
|
314
452
|
}
|
|
315
453
|
}
|
|
316
454
|
}
|
|
@@ -318,6 +456,23 @@ function referencedVariables(
|
|
|
318
456
|
return references;
|
|
319
457
|
}
|
|
320
458
|
|
|
459
|
+
function collectPredicateVariableReferences(
|
|
460
|
+
expression: WorkflowExpression | string | undefined,
|
|
461
|
+
references: ReferencedVariable[],
|
|
462
|
+
): void {
|
|
463
|
+
if (expression === undefined) return;
|
|
464
|
+
|
|
465
|
+
const keyAccess = analyzeContextKeyAccess(expression);
|
|
466
|
+
for (const reference of keyAccess.references) {
|
|
467
|
+
if (reference.root !== 'vars') continue;
|
|
468
|
+
references.push({
|
|
469
|
+
key: reference.key,
|
|
470
|
+
field: 'env',
|
|
471
|
+
source: typeof expression === 'string' ? expression : expression.source,
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
321
476
|
function collectTemplateVariableReferences(
|
|
322
477
|
templates: Readonly<Record<string, readonly ResolvedFieldSegment[]>> | undefined,
|
|
323
478
|
references: ReferencedVariable[],
|
|
@@ -357,16 +512,6 @@ function collectFieldVariableReferences(
|
|
|
357
512
|
}
|
|
358
513
|
}
|
|
359
514
|
|
|
360
|
-
function workflowTemplateSource(template: MaterializedWorkflowJob['name']): string | null {
|
|
361
|
-
if (template === undefined) return null;
|
|
362
|
-
|
|
363
|
-
return template
|
|
364
|
-
.map((segment) =>
|
|
365
|
-
segment.kind === 'literal' ? segment.value : `$${'{{'} ${segment.expression.source} ${'}}'}`,
|
|
366
|
-
)
|
|
367
|
-
.join('');
|
|
368
|
-
}
|
|
369
|
-
|
|
370
515
|
function logTemplateDiagnostics(params: {
|
|
371
516
|
readonly workflowRunId: string;
|
|
372
517
|
readonly diagnostics: readonly (WorkflowStepTemplateDiagnostic & {
|
|
@@ -42,6 +42,7 @@ describe('workflow run queries', () => {
|
|
|
42
42
|
describe('createRerunWorkflowRun', () => {
|
|
43
43
|
function rerunModel() {
|
|
44
44
|
return buildModel({
|
|
45
|
+
runName: `Run ${template('inputs.env')}`,
|
|
45
46
|
jobs: {
|
|
46
47
|
build: {steps: [{run: 'echo build'}]},
|
|
47
48
|
test: {needs: 'build', steps: [{run: 'echo test'}]},
|
|
@@ -112,6 +113,10 @@ describe('workflow run queries', () => {
|
|
|
112
113
|
|
|
113
114
|
expect(rerun).toMatchObject({
|
|
114
115
|
id: source.id,
|
|
116
|
+
number: source.number,
|
|
117
|
+
name: 'Run staging',
|
|
118
|
+
workflowName: 'Test Workflow',
|
|
119
|
+
nameOverride: 'Run staging',
|
|
115
120
|
inputs: {env: 'staging'},
|
|
116
121
|
sourceSnapshot: {content: 'name: Original\njobs: {}\n', format: 'yaml'},
|
|
117
122
|
});
|
|
@@ -198,7 +203,7 @@ describe('workflow run queries', () => {
|
|
|
198
203
|
expect(rerunAttempt?.agentToolMaterialization).toEqual(snapshot);
|
|
199
204
|
});
|
|
200
205
|
|
|
201
|
-
test('reruns
|
|
206
|
+
test('reruns re-materialize each job checkout policy from the model', async () => {
|
|
202
207
|
const source = await createWorkflowRun({
|
|
203
208
|
workspaceId,
|
|
204
209
|
projectId,
|
|
@@ -222,6 +227,12 @@ describe('workflow run queries', () => {
|
|
|
222
227
|
},
|
|
223
228
|
});
|
|
224
229
|
const sourceJobs = await getJobsByWorkflowRunId(source.id);
|
|
230
|
+
const sourceJob = sourceJobs[0];
|
|
231
|
+
if (!sourceJob) throw new Error('Missing source job');
|
|
232
|
+
await db()
|
|
233
|
+
.update(jobs)
|
|
234
|
+
.set({checkoutPersistCredentials: true, checkoutPermissionsContents: 'read'})
|
|
235
|
+
.where(eq(jobs.id, sourceJob.id));
|
|
225
236
|
await markJob(sourceJobs, 'build', 'failed');
|
|
226
237
|
await updateWorkflowRunStatus({
|
|
227
238
|
workflowRunId: source.id,
|
|
@@ -411,7 +422,7 @@ describe('workflow run queries', () => {
|
|
|
411
422
|
model: buildModel({
|
|
412
423
|
jobs: {
|
|
413
424
|
deploy: {
|
|
414
|
-
|
|
425
|
+
executionName: `Deploy ${template('inputs.environment')}`,
|
|
415
426
|
steps: [{run: 'echo deploy'}],
|
|
416
427
|
},
|
|
417
428
|
},
|
|
@@ -451,6 +462,54 @@ describe('workflow run queries', () => {
|
|
|
451
462
|
expect(rerunExecution?.name).toBe('Deploy prod (attempt 1)');
|
|
452
463
|
});
|
|
453
464
|
|
|
465
|
+
test('reruns preserve a null name override instead of copying the fallback', async () => {
|
|
466
|
+
const source = await createWorkflowRun({
|
|
467
|
+
workspaceId,
|
|
468
|
+
projectId,
|
|
469
|
+
definitionId,
|
|
470
|
+
model: buildModel({
|
|
471
|
+
jobs: {
|
|
472
|
+
deploy: {name: 'Deploy', steps: [{run: 'echo deploy'}]},
|
|
473
|
+
},
|
|
474
|
+
}),
|
|
475
|
+
triggerPayload: {
|
|
476
|
+
source: 'manual',
|
|
477
|
+
event: 'fire',
|
|
478
|
+
subscriptionId: crypto.randomUUID(),
|
|
479
|
+
userId: crypto.randomUUID(),
|
|
480
|
+
},
|
|
481
|
+
});
|
|
482
|
+
const [sourceJob] = await getJobsByWorkflowRunId(source.id);
|
|
483
|
+
if (!sourceJob) throw new Error('Missing deploy job');
|
|
484
|
+
await markJob([sourceJob], 'deploy', 'failed');
|
|
485
|
+
const [sourceExecution] = await getJobExecutionsByJobId(sourceJob.id);
|
|
486
|
+
if (!sourceExecution) throw new Error('Missing deploy execution');
|
|
487
|
+
expect(sourceExecution.nameOverride).toBeNull();
|
|
488
|
+
expect(sourceExecution.name).toBe('Deploy');
|
|
489
|
+
await updateWorkflowRunStatus({
|
|
490
|
+
workflowRunId: source.id,
|
|
491
|
+
status: 'failed',
|
|
492
|
+
expectedVersion: 1,
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
const rerun = await createRerunWorkflowRun({
|
|
496
|
+
workflowRunId: source.id,
|
|
497
|
+
mode: 'all',
|
|
498
|
+
actorUserId: crypto.randomUUID(),
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
const [rerunJob] = await getJobsByWorkflowRunId(rerun.id);
|
|
502
|
+
if (!rerunJob) throw new Error('Missing rerun deploy job');
|
|
503
|
+
const [rerunExecution] = await getJobExecutionsByJobId(rerunJob.id);
|
|
504
|
+
expect(rerunExecution?.nameOverride).toBeNull();
|
|
505
|
+
expect(rerunExecution?.name).toBe('Deploy');
|
|
506
|
+
const [storedRerunExecution] = await db()
|
|
507
|
+
.select({name: jobExecutions.name})
|
|
508
|
+
.from(jobExecutions)
|
|
509
|
+
.where(eq(jobExecutions.jobId, rerunJob.id));
|
|
510
|
+
expect(storedRerunExecution?.name).toBeNull();
|
|
511
|
+
});
|
|
512
|
+
|
|
454
513
|
test('writes one run-attempt-created outbox event for the rerun', async () => {
|
|
455
514
|
const source = await createTerminalSourceRun();
|
|
456
515
|
|
|
@@ -77,6 +77,7 @@ export async function createRerunWorkflowRun(
|
|
|
77
77
|
rerunMode: params.mode,
|
|
78
78
|
rerunByUserId: params.actorUserId,
|
|
79
79
|
model: sourceAttemptRow.model,
|
|
80
|
+
vars: sourceAttemptRow.vars,
|
|
80
81
|
agentToolMaterialization: sourceAttemptRow.agentToolMaterialization,
|
|
81
82
|
})
|
|
82
83
|
.returning();
|
|
@@ -192,6 +193,9 @@ function materializeRerunGraphJobs(params: {
|
|
|
192
193
|
|
|
193
194
|
return params.sourceJobs.map((sourceJob) => {
|
|
194
195
|
const carriedOver = params.mode === 'failed' && sourceJob.status === 'succeeded';
|
|
196
|
+
const modelJob = sourceModelJobByKey.get(sourceJob.key);
|
|
197
|
+
const modelCheckout = modelJob?.checkout;
|
|
198
|
+
const resolvedModelCheckout = modelCheckout === false ? undefined : modelCheckout;
|
|
195
199
|
|
|
196
200
|
return {
|
|
197
201
|
job: {
|
|
@@ -201,8 +205,10 @@ function materializeRerunGraphJobs(params: {
|
|
|
201
205
|
status: carriedOver ? ('succeeded' as const) : ('pending' as const),
|
|
202
206
|
statusReason: null,
|
|
203
207
|
carriedOver,
|
|
204
|
-
checkoutPersistCredentials:
|
|
205
|
-
|
|
208
|
+
checkoutPersistCredentials:
|
|
209
|
+
resolvedModelCheckout?.persistCredentials ?? sourceJob.checkoutPersistCredentials,
|
|
210
|
+
checkoutPermissionsContents:
|
|
211
|
+
resolvedModelCheckout?.permissions?.contents ?? sourceJob.checkoutPermissionsContents,
|
|
206
212
|
success: sourceJob.success,
|
|
207
213
|
executionTimeoutMs: sourceJob.executionTimeoutMs,
|
|
208
214
|
listeningTimeoutMs: sourceJob.listeningTimeoutMs,
|
|
@@ -224,8 +230,8 @@ function materializeRerunGraphJobs(params: {
|
|
|
224
230
|
if (job.mode === 'listening') return undefined;
|
|
225
231
|
|
|
226
232
|
const sourceExecution = params.sourceJobExecutionByJobId.get(sourceJob.id);
|
|
227
|
-
const
|
|
228
|
-
const executionName =
|
|
233
|
+
const nameOverride = sourceExecution?.name ?? null;
|
|
234
|
+
const executionName = nameOverride ?? job.name ?? job.key;
|
|
229
235
|
const runner =
|
|
230
236
|
carriedOver || modelJob === undefined
|
|
231
237
|
? (sourceExecution?.runner ?? job.runner ?? null)
|
|
@@ -234,13 +240,17 @@ function materializeRerunGraphJobs(params: {
|
|
|
234
240
|
modelJob,
|
|
235
241
|
jobId: job.id,
|
|
236
242
|
sequence: 1,
|
|
243
|
+
nameOverride,
|
|
237
244
|
executionName,
|
|
245
|
+
jobName: job.name,
|
|
238
246
|
status: 'pending',
|
|
239
247
|
});
|
|
240
248
|
|
|
241
249
|
return {
|
|
242
250
|
sequence: 1,
|
|
243
|
-
|
|
251
|
+
// Reruns preserve the authored/resolved override, never the
|
|
252
|
+
// effective fallback exposed by the core entity.
|
|
253
|
+
name: nameOverride,
|
|
244
254
|
runner: runner ? [...runner] : null,
|
|
245
255
|
status: carriedOver ? ('succeeded' as const) : ('pending' as const),
|
|
246
256
|
statusReason: null,
|
|
@@ -64,6 +64,7 @@ export async function getWorkflowContextForJob(
|
|
|
64
64
|
workflowRunAttemptId: string;
|
|
65
65
|
workspaceId: string;
|
|
66
66
|
projectId: string;
|
|
67
|
+
vars: Record<string, string> | null;
|
|
67
68
|
}> {
|
|
68
69
|
const rows = await tx
|
|
69
70
|
.select({
|
|
@@ -72,6 +73,7 @@ export async function getWorkflowContextForJob(
|
|
|
72
73
|
workflowRunAttemptId: workflowRunAttempts.id,
|
|
73
74
|
workspaceId: workflowRuns.workspaceId,
|
|
74
75
|
projectId: workflowRuns.projectId,
|
|
76
|
+
vars: workflowRunAttempts.vars,
|
|
75
77
|
})
|
|
76
78
|
.from(jobs)
|
|
77
79
|
.innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))
|
|
@@ -379,8 +379,8 @@ export interface RewindStepsToPendingParams {
|
|
|
379
379
|
// Restart-only: rewind every step at or after `fromPosition` back to pending,
|
|
380
380
|
// clearing its result and bumping both `version` and `current_attempt` so the next
|
|
381
381
|
// dispatch opens a fresh attempt. This DELIBERATELY bypasses the never-downgrade
|
|
382
|
-
// guard used everywhere else
|
|
383
|
-
//
|
|
382
|
+
// guard used everywhere else. It is the one place that resurrects terminal steps,
|
|
383
|
+
// so it must only be called from the durable-restart path, never the ordinary
|
|
384
384
|
// report path. It must run in the same transaction as the failed-attempt write.
|
|
385
385
|
export async function rewindStepsToPending(
|
|
386
386
|
params: RewindStepsToPendingParams,
|
|
@@ -405,7 +405,7 @@ export async function rewindStepsToPending(
|
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
// Count a single step's own attempts. Used to bound the restart cap on the
|
|
408
|
-
// gating step's actual executions
|
|
408
|
+
// gating step's actual executions: `steps.current_attempt` can't be used for
|
|
409
409
|
// the cap because a rewind also bumps it for downstream steps swept into the
|
|
410
410
|
// rewind range (which would inflate a later gate's cap in a multi-gate job).
|
|
411
411
|
export async function countStepAttempts(stepId: string, tx: Tx): Promise<number> {
|
package/src/db/workflow-runs.ts
CHANGED
|
@@ -47,6 +47,10 @@ export type {
|
|
|
47
47
|
WorkflowRunAggregates,
|
|
48
48
|
WorkflowRunCursor,
|
|
49
49
|
WorkflowRunFilters,
|
|
50
|
+
WorkflowRunJobStatusCount,
|
|
51
|
+
WorkflowRunJobSummary,
|
|
52
|
+
WorkflowRunJobSummaryTarget,
|
|
53
|
+
WorkflowRunJobsSummary,
|
|
50
54
|
} from './workflow-runs/queries.js';
|
|
51
55
|
export {
|
|
52
56
|
buildWorkflowRunListConditions,
|
|
@@ -59,6 +63,7 @@ export {
|
|
|
59
63
|
getWorkflowRunById,
|
|
60
64
|
getWorkflowRunDetail,
|
|
61
65
|
listRunAttempts,
|
|
66
|
+
listWorkflowRunJobSummaries,
|
|
62
67
|
listWorkflowRuns,
|
|
63
68
|
listWorkflowRunsByProject,
|
|
64
69
|
} from './workflow-runs/queries.js';
|
|
@@ -74,8 +79,10 @@ export {
|
|
|
74
79
|
createRerunWorkflowRun,
|
|
75
80
|
createWorkflowRun,
|
|
76
81
|
failWorkflowRunAsTimedOut,
|
|
82
|
+
loadReferencedVariables,
|
|
77
83
|
updateWorkflowRunStatus,
|
|
78
84
|
} from './workflow-runs/runs.js';
|
|
85
|
+
export {getWorkflowContextForJob} from './workflow-runs/shared.js';
|
|
79
86
|
export type {
|
|
80
87
|
ApplyStepResultParams,
|
|
81
88
|
BulkUpdateStepStatusesParams,
|
package/src/metrics/instance.ts
CHANGED
|
@@ -10,6 +10,13 @@ const runCreatedCount = meter.createCounter<{provider: string}>('workflows_run_c
|
|
|
10
10
|
description: 'Workflow runs created by bounded trigger provider',
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
+
const displayNameResolutionDegradedCount = meter.createCounter<{
|
|
14
|
+
field: 'workflow.run_name' | 'job.execution_name';
|
|
15
|
+
cause: 'missing_value' | 'evaluation_error' | 'empty_value' | 'sanitization';
|
|
16
|
+
}>('workflows_display_name_resolution_degraded', {
|
|
17
|
+
description: 'Display-name resolution degradations by field and bounded cause',
|
|
18
|
+
});
|
|
19
|
+
|
|
13
20
|
const runStatusChangedCount = meter.createCounter<{status: WorkflowRunStatus}>(
|
|
14
21
|
'workflows_run_status_changed',
|
|
15
22
|
{description: 'Workflow run status transitions by resulting status'},
|
|
@@ -97,6 +104,13 @@ export function recordWorkflowRunCreated(provider: string): void {
|
|
|
97
104
|
runCreatedCount.add(1, {provider});
|
|
98
105
|
}
|
|
99
106
|
|
|
107
|
+
export function recordWorkflowDisplayNameResolutionDegraded(
|
|
108
|
+
field: 'workflow.run_name' | 'job.execution_name',
|
|
109
|
+
cause: 'missing_value' | 'evaluation_error' | 'empty_value' | 'sanitization',
|
|
110
|
+
): void {
|
|
111
|
+
displayNameResolutionDegradedCount.add(1, {field, cause});
|
|
112
|
+
}
|
|
113
|
+
|
|
100
114
|
export function recordWorkflowRunStatusChanged(status: WorkflowRunStatus): void {
|
|
101
115
|
runStatusChangedCount.add(1, {status});
|
|
102
116
|
}
|