Skip to content

feat: integrate embedded-cluster CLI lint into release lint pipeline#696

Merged
emosbaugh merged 13 commits intomainfrom
emosbaugh/20260417/ec-lint-integration
Apr 21, 2026
Merged

feat: integrate embedded-cluster CLI lint into release lint pipeline#696
emosbaugh merged 13 commits intomainfrom
emosbaugh/20260417/ec-lint-integration

Conversation

@emosbaugh
Copy link
Copy Markdown
Member

@emosbaugh emosbaugh commented Apr 17, 2026

Summary

  • Adds EC lint as an opt-in linter (disabled by default) that runs the embedded-cluster CLI against manifest files alongside existing Helm, Preflight, and Support Bundle linters
  • Automatically discovers the EC version from the embeddedcluster.replicated.com/v1beta1 Config manifest (spec.version) — no separate config needed; supports multi-document YAML files
  • Downloads the EC binary from S3 (https://tf-embedded-cluster-binaries.s3.us-east-1.amazonaws.com/releases/{version}-{os}-{arch}.tgz) and caches it alongside other tools; version resolution via replicated.app/ping is not supported for EC so the fallback path is skipped
  • Supports binary-path config field and REPLICATED_EMBEDDED_CLUSTER_BINARY_PATH env var to bypass the resolver — version discovery is skipped when a binary path is provided
  • Configurable disable-checks list with defaults (helmchart-archive, ecconfig-helmchart-archive)
  • Linter config unified: all linters use LinterConfig (or ECLinterConfig which embeds it); ApplyDefaults is the single source of truth for which linters are on/off by default — nil is a transient parse state, never reaches IsEnabled() at runtime
  • In auto-discovery mode, the "no lintable resources" early return is skipped when EC linting is enabled, since EC lints a distinct set of files not found by traditional discovery

Example config

repl-lint:
  linters:
    embedded-cluster:
      disabled: false
      # optional overrides:
      # binary-path: /path/to/cli
      # disable-checks:
      #   - preflight-v1beta2

Test plan

  • Run replicated release lint without EC config — EC section shows as disabled
  • Enable EC linting in .replicated, point at a manifests dir with an EmbeddedCluster/Config manifest — version is auto-discovered, binary is downloaded and linting runs
  • Set REPLICATED_EMBEDDED_CLUSTER_BINARY_PATH to a local binary — resolver is bypassed, version discovery is skipped
  • JSON output includes embedded_cluster_results field
  • EC lint errors cause overall linting failed exit code
  • Auto-discovery mode with only EC manifests (no charts/preflights) — EC linting still runs

🤖 Generated with Claude Code

Adds EC lint as an opt-in linter (disabled by default) that runs the
embedded-cluster CLI against manifest directories and surfaces results
alongside Helm, Preflight, and Support Bundle lint output.

- New ECLinterConfig type with disabled-by-default IsEnabled() semantics
- Discovers EC version automatically from the EmbeddedCluster Config manifest
- Downloads the EC CLI binary from S3 by version, caches it alongside other tools
- Supports binary-path config field and REPLICATED_EMBEDDED_CLUSTER_BINARY_PATH
  env var to bypass the resolver
- Configurable --disable checks with sensible defaults

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread pkg/tools/downloader.go Outdated
Comment thread pkg/tools/config.go
Comment thread pkg/tools/downloader.go Outdated
emosbaugh and others added 4 commits April 17, 2026 12:32
…ries

Replaces manifestBaseDirs with ExpandManifestGlobs which expands the
manifest glob patterns from .replicated config to actual YAML file paths,
applying the same gitignore and hidden-path filtering as other linters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Kots uses LinterConfig where nil Disabled means enabled, so it requires
an explicit boolPtr(true). Also adds a nil-check in ApplyDefaults to
default Kots to disabled when a repl-lint section exists but omits Kots.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread pkg/lint2/embedded_cluster.go
Comment thread cli/cmd/lint.go Outdated
emosbaugh and others added 2 commits April 17, 2026 12:45
…lyDefaults

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…on path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread pkg/lint2/embedded_cluster.go
Comment thread pkg/tools/downloader.go
Comment thread pkg/tools/downloader.go Outdated
- Use json.NewDecoder loop in LintEmbeddedCluster to handle trailing content
  after JSON output (matches parseTroubleshootJSON approach)
- Iterate YAML documents in parseECVersionFromFile to find EC Config in
  non-first documents of multi-document YAML files
- Move DiscoverECVersion after binary path resolution so it is skipped when
  a binary path is explicitly provided (no version needed)
- Skip DownloadWithFallback for EC since version is always explicit; fallback
  to latest is unsupported and produced a misleading error message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread cli/cmd/lint.go
emosbaugh and others added 2 commits April 17, 2026 16:19
…o-discovery mode

The early return for "No lintable resources found" ran before the EC linting
block, silently skipping EC lint even when explicitly enabled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread pkg/lint2/embedded_cluster.go Outdated
…ills

- Remove KotsLinterConfig; all linters use LinterConfig (or ECLinterConfig)
- ECLinterConfig embeds LinterConfig and inherits IsEnabled()
- mergeECLinterConfig delegates the Disabled field to mergeLinterConfig
- nil Disabled is a transient parse state; ApplyDefaults always fills every
  linter's Disabled field before IsEnabled() is called
- Defaults (on/off) live in one place: the nil-fill block in ApplyDefaults
- Add tests for linter defaults, ApplyDefaults idempotency, and mergeECLinterConfig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread cli/cmd/lint.go Outdated
emosbaugh and others added 2 commits April 21, 2026 09:03
… file paths

Joining all expanded manifest paths produced an unreadably long string in
both table and JSON output. Individual messages already carry their own file
path from the EC lint output, so a short summary label is sufficient here.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add lint_types.go with generic LintIssue interface, FileLintResult[T],
  and LintOutput[T] — shared across all linting tools
- Rename Troubleshoot-prefixed types/functions to generic names:
  TroubleshootIssue→LintIssue, TroubleshootFileResult→FileLintResult,
  TroubleshootLintResult→LintOutput, parseTroubleshootJSON→parseLintJSON,
  convertTroubleshootResultToMessages→convertLintOutputToMessages,
  formatTroubleshootMessage→formatLintMessage
- Standardize on json:"info" (dropping unused json:"infos" — troubleshoot
  lint output only contains errors and warnings)
- Remove dead PreflightLintResult/PreflightFileResult and
  SupportBundleLintResult/SupportBundleFileResult types
- Remove ecFileResult/ecLintOutput; EC lint now parses directly into
  LintOutput[ecLintIssue], eliminating convertECResultToMessages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 788fa97. Configure here.

Comment thread pkg/lint2/lint_types.go
@emosbaugh emosbaugh merged commit f3f51c0 into main Apr 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants