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

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions