@fabrika/provider-zerops 0.3.1 → 0.3.3

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.
@@ -8,6 +8,7 @@
8
8
  // The pin is checked BEFORE anything leaves this machine: `assertPinnedTag` refuses a branch or a SHA
9
9
  // (ADR-0025) without a network call, so `--to=main` fails on the spot rather than after a clone.
10
10
 
11
+ import { describeArgument, readFlag } from '@fabrika/installation-init'
11
12
  import { assertPinnedTag, defaultCheckoutDir } from './sidecar'
12
13
 
13
14
  /** Where the sidecar repository this command edits is found. */
@@ -43,16 +44,6 @@ export const UPGRADE_DRY_RUN_FLAG = '--dry-run'
43
44
  */
44
45
  const REPO_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/
45
46
 
46
- const readFlag = (argv: readonly string[], name: string): string | undefined => {
47
- const prefix = `${name}=`
48
- const matches = argv.filter((arg) => arg.startsWith(prefix))
49
- if (matches.length > 1) {
50
- throw new Error(`${name} was given more than once`)
51
- }
52
- const value = matches[0]?.slice(prefix.length)
53
- return value === undefined || value.trim() === '' ? undefined : value.trim()
54
- }
55
-
56
47
  const assertKnownArguments = (argv: readonly string[]): void => {
57
48
  for (const arg of argv) {
58
49
  if (arg === UPGRADE_DRY_RUN_FLAG || !arg.startsWith('-')) {
@@ -61,7 +52,7 @@ const assertKnownArguments = (argv: readonly string[]): void => {
61
52
  const name = arg.split('=')[0] ?? arg
62
53
  if (!FLAGS.some((flag) => flag === name) || !arg.includes('=')) {
63
54
  throw new Error(
64
- `unexpected argument \`${arg}\`. Run \`fabrika platform upgrade --provider=zerops --help\` for the surface`,
55
+ `unexpected argument ${describeArgument(arg)}. Run \`fabrika platform upgrade --provider=zerops --help\` for the surface`,
65
56
  )
66
57
  }
67
58
  }
@@ -71,7 +62,7 @@ const assertKnownArguments = (argv: readonly string[]): void => {
71
62
  const readInstallation = (argv: readonly string[]): string | undefined => {
72
63
  const positional = argv.filter((arg) => !arg.startsWith('-'))
73
64
  if (positional.length > 1) {
74
- throw new Error(`unexpected argument \`${positional[1]}\`: name ONE installation`)
65
+ throw new Error('unexpected second positional argument: name ONE installation')
75
66
  }
76
67
  const installation = positional[0]?.trim()
77
68
  return installation === undefined || installation === '' ? undefined : installation
@@ -1,7 +1,13 @@
1
1
  import type { JsonValue } from '@fabrika/provider-contract'
2
2
  import { z } from 'zod'
3
3
  import { renderYaml } from './compile'
4
- import { parseZeropsDescriptor, type PreparedZeropsDescriptor, selectZeropsDescriptorSetup } from './descriptor'
4
+ import {
5
+ assertOwnRunWhenExtending,
6
+ executionZeropsDocument,
7
+ parseZeropsDescriptor,
8
+ type PreparedZeropsDescriptor,
9
+ selectZeropsDescriptorSetup,
10
+ } from './descriptor'
5
11
 
6
12
  export type ManagedKey =
7
13
  | 'FABRIKA_RELEASE'
@@ -93,7 +99,9 @@ export function overlayRelease(contents: string, setup: string | undefined, rele
93
99
  const parsed = parseZeropsDescriptor(contents)
94
100
  assertAuthoredManagedDocument(parsed.document)
95
101
  const selected = selectZeropsDescriptorSetup(parsed, setup)
96
- const entries = parsed.document['zerops']
102
+ assertOwnRunWhenExtending(parsed, selected)
103
+ const execution = executionZeropsDocument(parsed, selected)
104
+ const entries = execution['zerops']
97
105
  if (!Array.isArray(entries)) throw new Error('zerops: descriptor requires setup entries')
98
106
  const overlaid = release === null ? entries : entries.map((entry) => {
99
107
  if (!isMapping(entry) || entry['setup'] !== selected) return entry
@@ -101,5 +109,5 @@ export function overlayRelease(contents: string, setup: string | undefined, rele
101
109
  const env = isMapping(run['envVariables']) ? run['envVariables'] : {}
102
110
  return { ...entry, run: { ...run, envVariables: { ...env, FABRIKA_RELEASE: release } } }
103
111
  })
104
- return { contents: renderYaml({ ...parsed.document, zerops: overlaid }), setup: selected }
112
+ return { contents: renderYaml({ ...execution, zerops: overlaid }), setup: selected }
105
113
  }
package/src/manifest.ts CHANGED
@@ -4,7 +4,7 @@ import type { JsonValue, ProviderCodec } from '@fabrika/provider-contract'
4
4
  import { normalizeGateRule, proxyGateRuleFieldsSchema } from '@fabrika/proxy-core/manifest'
5
5
  import { z } from 'zod'
6
6
  import { compileImport, ENV_ISOLATION, OVERRIDE, renderYaml } from './compile'
7
- import { parseZeropsDescriptor, selectZeropsDescriptorSetup } from './descriptor'
7
+ import { assertOwnRunWhenExtending, executionZeropsDocument, parseZeropsDescriptor, selectZeropsDescriptorSetup } from './descriptor'
8
8
  import { assertAuthoredManagedDocument, assertAuthoredManagedInputs } from './managed-env'
9
9
  import { allowedReferenceHosts, foreignReferenceHost } from './service-references'
10
10
  import type { ZeropsAppConfig, ZeropsNamespaceResourceRequirement, ZeropsProxySpec, ZeropsSharedPostgresBinding } from './types'
@@ -288,14 +288,17 @@ export function parseFabrikaManifest(value: unknown, expected: ManifestExpectati
288
288
  if (!serviceHostnames.includes(deployService)) {
289
289
  throw new Error('invalid fabrika manifest Zerops deploy service')
290
290
  }
291
+ // Only the selected setup and what it extends reach this app's service, so a sibling setup for another
292
+ // placement may reference services this app does not own.
293
+ const selectedSetup = selectZeropsDescriptorSetup(parsedDescriptor, zeropsSetup)
294
+ assertOwnRunWhenExtending(parsedDescriptor, selectedSetup)
291
295
  const foreignInDescriptor = foreignReferenceInValue(
292
- parsedDescriptor.document,
296
+ executionZeropsDocument(parsedDescriptor, selectedSetup),
293
297
  allowedReferenceHosts(serviceHostnames),
294
298
  )
295
299
  if (foreignInDescriptor !== null) {
296
300
  throw new Error(`invalid fabrika manifest: zerops.yaml references service \`${foreignInDescriptor}\`, which this app does not own`)
297
301
  }
298
- selectZeropsDescriptorSetup(parsedDescriptor, zeropsSetup)
299
302
  if (proxy !== undefined) {
300
303
  const separator = proxy.upstream.indexOf(':')
301
304
  const upstreamHostname = separator === -1 ? proxy.upstream : proxy.upstream.slice(0, separator)
package/src/provider.ts CHANGED
@@ -77,8 +77,6 @@ const POLL_INTERVAL_MS = 3000
77
77
  /** A run stops waiting for its version this long after it started. Zerops' own pipeline limit is 1 hour. */
78
78
  export const ZEROPS_VERSION_DEADLINE_MS = 75 * 60 * 1000
79
79
 
80
- const RELEASE_KEY = 'FABRIKA_RELEASE'
81
-
82
80
  /** Abandon the step if the run was cancelled. Checked before every real mutation and each poll iteration. */
83
81
  const assertRunning = (signal: AbortSignal): void => {
84
82
  if (signal.aborted) {
@@ -419,7 +417,7 @@ const writeServiceEnv = async (env: StepEnv): Promise<void> => {
419
417
  const written = SERVICE_MANAGED_KEYS.filter((key) => managedValues[key] !== null)
420
418
  const removed = SERVICE_MANAGED_KEYS.filter((key) => managedValues[key] === null)
421
419
  log(` [dry-run] would write service variables on ${serviceId}: ${written.join(', ') || '(none)'}`)
422
- log(` [dry-run] would remove service variables on ${serviceId} if present: ${[...removed, RELEASE_KEY].join(', ')}`)
420
+ log(` [dry-run] would remove service variables on ${serviceId} if present: ${removed.join(', ') || '(none)'}`)
423
421
  return
424
422
  }
425
423
  assertRunning(signal)
@@ -439,12 +437,6 @@ const writeServiceEnv = async (env: StepEnv): Promise<void> => {
439
437
  log(` ${key}: unchanged`)
440
438
  }
441
439
  }
442
- const strayRelease = records.find((record) => record.key === RELEASE_KEY)
443
- if (strayRelease !== undefined) {
444
- assertRunning(signal)
445
- await zerops.api.deleteServiceEnv({ envId: strayRelease.id, signal })
446
- log(` ${RELEASE_KEY}: removed`)
447
- }
448
440
  }
449
441
 
450
442
  /** Run one step's effect. Resolves on success, throws on failure (caught + recorded by `runSteps`). */