Skip to content

nullstone apply --publish #589

@BSick7

Description

@BSick7

Summary

As a Nullstone user or CI/CD pipeline, I want a single CLI command that packages and publishes an embedded module and then runs a plan and apply against a target workspace — so I can test module changes locally and automate module deployments in pipelines without manual multi-step processes.


Background

The GitOps auto-publish flow (Story 2) covers the merge-to-branch path. But developers also need to test module changes before merging, and CI/CD pipelines may need to publish and apply on demand outside of the standard GitOps trigger. The nullstone apply --publish command provides this path.

The command is designed for two primary contexts:

  1. Local development: A developer iterates on a module in a sandbox environment, running plan and apply interactively.
  2. CI/CD pipelines: A pipeline step publishes and applies a module change as part of a deployment workflow, with non-interactive approval and optional async execution.

Command Signature

nullstone apply --publish [--auto-approve] [--async] [--module-path <path>] [--stack <stack>] [--env <env>] [--block <block>]

Flags

Flag Description
--publish Package and publish the module before running plan/apply. Without this flag, the command behaves like the existing apply.
--auto-approve Automatically approve the plan if it succeeds, without prompting. Required for non-interactive CI/CD use.
--async Trigger the run and exit immediately, printing a dashboard link instead of streaming logs.
--module-path <path> Path to the module directory to publish. Defaults to the current working directory.
--stack <stack> Target Nullstone stack.
--env <env> Target environment within the stack.
--block <block> Target block (workspace) within the stack/environment.

Acceptance Criteria

Publish Phase

  • When --publish is specified, Nullstone packages the module at the resolved path and publishes a new build version before triggering a plan.
  • The resolved module path is determined by: --module-path flag → current working directory → module declaration in .nullstone/config.yml matching the cwd (in that order of precedence).
  • If the cwd or --module-path matches multiple declared modules, Nullstone errors with a clear message asking the user to specify --block or --module-path.
  • The published version is a build version (0.0.0-<short-sha>), not a release version.
  • Publish output is streamed to stdout:
    Publishing module: custom-rds
      Packaging...    ✓  (234ms)
      Uploading...    ✓  (1.2s)
      Version:        0.0.0-abc1234
    
    Module published successfully.
    

Plan Phase

  • After a successful publish, Nullstone triggers a plan against the target workspace using the newly published module version.
  • Plan logs are streamed to stdout in real time (unless --async is specified).
  • The plan output clearly identifies the target workspace (stack / env / block).
  • If the plan fails, the command exits with code 1 and no apply is triggered.

Approval Phase (interactive, default)

  • If --auto-approve is not specified and the plan succeeds, the user is prompted:
    Do you want to apply these changes? [y/N]:
    
  • y or yes triggers the apply. Any other input (including Enter) cancels.
  • On cancel, the command prints a dashboard link to the plan and exits with code 130.

Apply Phase

  • If approved (interactively or via --auto-approve), Nullstone triggers the apply.
  • Apply logs are streamed to stdout in real time (unless --async is specified).
  • On apply success, the command exits with code 0.
  • On apply failure, the command exits with code 2.

Async Mode (--async)

  • When --async is specified, the command triggers the plan (and apply, if --auto-approve is also set) and exits immediately after the run is queued.
  • The command prints a dashboard link to track the run:
    Run triggered. Track progress:
      https://app.nullstone.io/orgs/acme/stacks/primary/envs/dev/blocks/api/runs/8471
    
  • --async without --auto-approve triggers only a plan (not an apply). The output explicitly states that apply requires manual approval in the dashboard.
  • --async is compatible with --publish. Publish completes synchronously before the async run is queued.

Log Streaming

  • Log streaming uses a persistent connection (WebSocket or SSE) that automatically reconnects on network interruption.
  • If the stream connection is lost and cannot be reestablished, the CLI prints a warning and falls back to polling.
  • The underlying Nullstone run continues regardless of whether the CLI is connected (runs are detach-safe).

Exit Codes

Code Meaning
0 Success (apply complete, or async run queued, or user declined and plan link printed).
1 Plan failed.
2 Apply failed.
3 Publish failed.
130 User declined apply at interactive prompt.

CI/CD Usage

  • The command is fully non-interactive when --auto-approve is specified (no prompts, no TTY required).
  • Exit codes are stable and documented for use in pipeline scripts.
  • Example pipeline invocation:
    nullstone iac apply --publish --auto-approve \
      --stack primary --env production --block api

Local Dev: --local-module Override

  • A separate --local-module <path> flag allows developers to inject a local module path in place of a registry reference, without publishing.
  • This is equivalent to Terraform's dev_overrides in .terraformrc — the module is used directly from disk.
  • --local-module and --publish are mutually exclusive; specifying both produces an error.
  • Local module overrides are never persisted to the Nullstone registry or reflected in GitOps state.

Output Design Summary

Publishing module: custom-rds
  Packaging...    ✓  (234ms)
  Uploading...    ✓  (1.2s)
  Version:        0.0.0-abc1234

Module published successfully.

Planning infrastructure changes...
  Stack: primary / Env: dev / Block: api
──────────────────────────────────────────
  ~ aws_rds_cluster.main
      engine_version: "13.4" → "15.3"

  + aws_rds_cluster_parameter_group.custom

Plan: 1 to add, 1 to change, 0 to destroy.
──────────────────────────────────────────

Do you want to apply these changes? [y/N]: y

Applying infrastructure changes...
  [streaming apply logs]

Apply complete. Resources: 1 added, 1 changed.

Out of Scope

  • nullstone modules publish as a standalone command without plan/apply (tracked separately).
  • Promoting build versions to release channels via this command.
  • Running plans against multiple workspaces in a single invocation.

Metadata

Metadata

Assignees

Labels

No labels
No labels
No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions