let layer_trigger = [| 'OnCommit, # pre-commit (git) / jjw pre-op check (jj) 'OnPush, # pre-push (git) / rad patch submit (radicle) 'OnPR, # pull_request on remote CI 'OnMainMerge, # push to trunk/main branch 'OnTag, # semver tag event 'OnManual, # explicit user/agent trigger |] in let validation_kind = [| 'Lint, 'Test, 'Security, 'Compliance, 'Docs |] in let build_kind = [| 'Binary, 'Library, 'Container, 'Docs, 'SBOM |] in let distribution_kind = [| 'CargoRegistry, 'ContainerRegistry, 'Package, 'Artifact |] in # Validation spec — tool invocation, VCS/provider agnostic. # The generator translates this into provider-specific syntax. let validation_spec = { id | String | default = "", kind | validation_kind | default = 'Lint, tool | String | default = "", args | Array String | default = [], when | Array String | default = [], # glob patterns; empty = always run fail_fast | Bool | default = true, cargo_profile | String | default = "", # "" if not applicable } in # Build spec — artifact production, VCS/provider agnostic. let build_spec = { id | String | default = "", kind | build_kind | default = 'Binary, tool | String | default = "", args | Array String | default = [], cargo_profile | String | default = "", target | String | default = "", # cargo target triple; "" = native artifacts | Array String | default = [], # expected output paths } in # Distribution spec — where to send artifacts after build. let distribution_spec = { id | String | default = "", kind | distribution_kind | default = 'Artifact, tool | String | default = "", args | Array String | default = [], destination | String | default = "", } in # A workflow layer is an independent, self-contained set of operations. # Layers do NOT depend on each other — they form a set, not a chain. # A workspace may activate any combination of layers independently. let workflow_layer = { id | String | default = "", trigger | layer_trigger | default = 'OnManual, validations | Array String | default = [], # IDs from the active validations catalog builds | Array String | default = [], # IDs from the active builds catalog distributions | Array String | default = [], # IDs from the active distributions catalog # Provider implementations enabled for this layer. # Each provider generates a different artifact from the same layer declaration. # Use the ProviderImpl helpers below to construct typed provider records. providers | Array { tag | String, .. } | default = [], } in # Complete workflow declaration for a workspace. # Workspaces import defaults/workflow.ncl and extend/override as needed. let workflow_declaration = { layers | Array workflow_layer | default = [], validations | { _ | validation_spec } | default = {}, builds | { _ | build_spec } | default = {}, distributions | { _ | distribution_spec } | default = {}, } in # ── Provider constructor helpers ────────────────────────────────────────────── # Use these to build the providers array in WorkflowLayer. let mk_pre_commit = fun s => { tag = "PreCommit", stage = s } in let mk_woodpecker = fun f => { tag = "Woodpecker", file = f } in let mk_github_actions = fun f => { tag = "GithubActions", file = f } in let mk_justfile = fun r => { tag = "Justfile", recipe = r } in let mk_jjw_wrapper = { tag = "JjwWrapper" } in { # Types / contracts — use as field contracts: `field | W.WorkflowLayer` LayerTrigger = layer_trigger, ValidationKind = validation_kind, BuildKind = build_kind, DistributionKind = distribution_kind, ValidationSpec = validation_spec, BuildSpec = build_spec, DistributionSpec = distribution_spec, WorkflowLayer = workflow_layer, WorkflowDeclaration = workflow_declaration, # Provider constructors — use in `providers = [W.pre_commit "pre-commit", ...]` pre_commit = mk_pre_commit, woodpecker = mk_woodpecker, github_actions = mk_github_actions, justfile = mk_justfile, jjw_wrapper = mk_jjw_wrapper, }