2c45b343c2
New internal/lsp package implements a minimal JSON-RPC 2.0 LSP server over stdin/stdout with Content-Length framing. Supported lifecycle: initialize → initialized → shutdown → exit. Document sync: Full (sends complete text on every change). Handles textDocument/didOpen, didChange, didSave, didClose; publishes textDocument/publishDiagnostics after every change. Rule IDs surface as the diagnostic `code` field with `"glint"` as source. Parse errors produce an Error diagnostic at the top of the document. Include resolution is best-effort (GITLAB_TOKEN env var; ~/.cache/glint default cache). CLI: glint lsp [--token] [--gitlab-url] [--cache-dir] [--offline]. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 KiB
12 KiB
Roadmap
This document tracks planned improvements to glint. Items are grouped by theme, roughly in priority order within each group. Nothing here is a commitment — the tool is experimental and the list will shift as real usage surfaces better priorities.
Context simulation
Pass --branch, --tag, --source, or --var to glint check or glint graph to evaluate rules:if: expressions and only/except filters against a specific pipeline event.
- Single-context simulation — shipped v0.2.0;
--branch,--tag,--source,--varflags on both subcommands; jobs classified as active / manual / skipped workflow:rules:variables:propagation — shipped post-v0.2.0; variables from the matching workflow rule entry injected into the evaluation context before jobrules:if:expressions are evaluated- Expression evaluator: multi-line
if:values — shipped post-v0.2.0; newlines in block-scalar and folded YAMLif:values treated as whitespace - Expression evaluator:
${VAR}syntax — shipped post-v0.2.0;${CI_COMMIT_BRANCH}equivalent to$CI_COMMIT_BRANCHeverywhere - Expression evaluator: regex flags — shipped post-v0.2.0;
/pattern/i,/pattern/m,/pattern/ssupported - Expression evaluator: variable as regex RHS — shipped post-v0.2.0;
$BRANCH =~ $PATTERNwhere$PATTERNholds a/regex/string evaluates correctly - Expression evaluator: bare
true/falseand integer literals — shipped post-v0.2.0;$FLAG == true,$COUNT == 4compare as decimal strings matching GitLab CI behaviour - Implicit default context — shipped v0.2.11; defaults to
--branch main --source pushwhen no context flag is given, sorules:if:is always evaluated --list-varsdebug flag — shipped v0.2.11; prints sortedKEY=VALUEof all collected pipeline variables (root file + includes + workflow-rule union + effective context) to stderr- Variable expansion — shipped v0.2.13;
$VAR/${VAR}references within variable values expanded after all sources are merged; transitive chains resolved; visible in--list-vars - Non-string scalar variables — shipped v0.2.13;
BUILD: true,RETRIES: 3rendered and injected correctly instead of being silently dropped - YAML
\/escape in double-quoted strings — shipped v0.2.13; regex patterns like/^us\//in double-quotedif:blocks no longer cause a parse error - Workflow rule strict evaluation — shipped v0.2.14; unparseable
if:skips the rule instead of matching everything; prevents wrong variables being injected - Single
=operator — shipped v0.2.14; bare=accepted as alias for==inrules:if:expressions rules:changes:evaluation — shipped v0.2.21;--changes PATHand--changes-from REFflags; doublestar glob matching (*within segment,**across segments); permissive when no file list provided- Multi-context simulation — shipped v0.2.22;
--context KEY=VALUE[,...]; repeatable; prints a comparison table ofactive/manual/skipped/blockedper job across all contexts - Context-scoped linting — shipped v0.2.23; jobs evaluated as
JobSkippedin the supplied context are excluded fromneeds:/dependencies:cross-checks (GL027–GL031) to eliminate false-positive errors for conditionally-gated jobs
Lint coverage
The current rule set covers the most common sources of broken pipelines. These are the gaps most likely to matter in practice.
- Variable reference validation (GL032) — shipped v0.2.11; warns when a
rules:if:expression references$VAR/${VAR}not declared anywhere in pipeline YAML; predefined GitLab namespaces (CI_*,GITLAB_*, …) exempt; variables from included files are also considered rules:if:static reachability (GL033) — shipped v0.2.15; warns when every rule in a job'srules:block haswhen: never, making the job permanently excluded from any pipeline run; noif:evaluation requiredservices:validation (GL034) — shipped v0.2.16; map form requiresname;aliasmust be a valid DNS labelrules:changes/rules:existsabsolute path detection (GL035) — shipped v0.2.16; warns when a path starts with/; GitLab CI paths are always relative to the repo roottimeoutformat validation (GL036) — shipped v0.2.16; validates job-level anddefault.timeoutagainst recognised GitLab CI duration stringsid_tokens:/secrets:required-key checks (GL037, GL038) — shipped v0.2.16;id_tokensentries must haveaud;secretsentries must declare a providerpages:publish+artifacts.pathsconsistency (GL039) — shipped v0.2.16; warns when the publish directory is missing fromartifacts.paths- Duplicate stage names (GL040) — shipped v0.2.16; warns when a stage appears more than once in
stages: cache:key:filesmust be exact paths (GL041) — shipped v0.2.16; warns when entries look like glob patterns- Unreachable jobs — covered by GL033 (shipped v0.2.15); every-
when:neverrules block is statically dead inherit:completeness (GL043) — shipped v0.2.20; warns wheninherit: default:is declared but there's nodefault:block, or list form names fields not set indefault:
Include resolution
include: local:full resolution — shipped v0.2.0; local files are read from disk, recursively resolved, and merged before lintinginclude: remote:(URL) — shipped post-v0.2.0; plain HTTPS URLs are fetched (unauthenticated), parsed, and merged; sub-includes are resolved recursively; unreachable URLs emit[WARNING]and linting continues- Recursive include depth limit — shipped v0.2.17; depth capped at 100 (matching GitLab); project/component includes now tracked in visited set to prevent cross-file cycles
- Offline mode / cache — shipped v0.2.17;
--cache-dir DIRpersists fetched templates;--offlineserves from cache only; default cache dir (~/.cache/glint) used automatically with--offline include: inputs:— shipped v0.2.17;$[[ inputs.KEY ]]and$[[ inputs.KEY | default(…) ]]placeholders in fetched component YAML are substituted from the include'swith:block before parsing
Output formats
- JSON (
--format json) — shipped v0.2.18; machine-readable findings with stable schema (version 1) - SARIF (
--format sarif) — shipped v0.2.18; SARIF 2.1.0; consumed natively by GitHub Code Scanning and GitLab SAST - JUnit XML (
--format junit) — shipped v0.2.18; lets CI pipelines publish lint results as a test report artifact - GitHub annotation format (
--format github) — shipped v0.2.18; emits::error file=…,line=…,title=RULE::messagelines so findings appear as inline comments in PR diffs
Pipeline graph improvements
The SVG renderer and terminal tree cover the basic layout. These would bring it closer to GitLab's full interactive view.
- Terminal job tree — shipped v0.2.0 as
glint graph tree; stages as branches, jobs as leaves, context-aware annotations glint graph includesshows jobs per file — shipped post-v0.2.0; each include node shows the jobs it defines as dashed-arrow rounded nodes in a distinct style- Multi-job connector accuracy — shipped v0.2.25; classic mode uses a bus-bar pattern (vertical rail at the midpoint + horizontal stubs per job) instead of a single center-to-center line, so uneven columns look correct
- Job tooltip / detail panel — shipped v0.2.25; each chip is wrapped in
<g data-job="…"><title>…</title><desc>…</desc>— SVG viewers show stage, when, image, and needs on hover; HTML output uses the data for the sidebar when: on_failurevisual distinction — shipped v0.2.25; dashed chip border + X-mark icon + red circle (#d9534f); legend entry added; Mermaidon_failureclass wired- Blocked / skipped state colouring — shipped v0.2.25;
glint graph pipelineaccepts context flags (--branch,--tag, etc.); jobs evaluated as skipped are greyed out (#868686) with dimmed text and no icon - Interactive HTML output — shipped v0.2.25;
glint graph pipeline --format htmlwrites a self-contained.htmlfile with mouse pan/zoom and a click-to-open job-detail sidebar; no external dependencies - Mermaid pipeline output — shipped v0.2.25;
glint graph pipeline --format mermaidprints a Mermaid flowchart to stdout (paste into mermaid.live) - Same-stage job ordering — shipped v0.2.26; jobs within a stage that have
needs:between each other are placed in topological sub-columns (left-to-right by depth); stage header spans all sub-columns - Graph links rendered behind job chips — shipped v0.2.26; SVG connectors (Bézier curves and bus-bar stubs) are drawn before job chips so lines pass behind rectangles
Findings quality
- File and line numbers on findings — shipped post-v0.2.0; every finding includes the source file and exact line of the job key; works across local includes, remote project templates, and fetched component templates
- Ruff-style output format — shipped v0.2.11; findings follow
file:line: RULEID [severity] messagematching the convention used by ruff and other modern linters needs: optional: truefalse-positive errors — shipped post-v0.2.0; optional missing needs are downgraded to[WARNING]extends:jobs with missing script false errors — shipped post-v0.2.0; jobs usingextends:that have noscriptafter resolution emit[WARNING](the script may come from an unfetchable remote base)rules:if:static reachability (GL042) — shipped v0.2.20; warns when allrules:if:conditions evaluate to false given declared variable values (only fires when all referenced vars are declared in YAML)
CI / editor integration
- GitLab CI template — shipped v0.2.28;
templates/check.ymlis a GitLab CI/CD Catalog component withspec:inputs for stage, file, version, allow_failure, and extra args; also usable as a plain local/remote include - GitHub Actions action — shipped v0.2.28;
action.ymlcomposite action downloads the glint Linux binary and runsglint check; mirror to GitHub ask3nny/glintto reference asuses: k3nny/glint@v0.2.28 - Pre-commit hook — shipped v0.2.28;
.pre-commit-hooks.yamldefineslanguage: golanghook; pre-commit builds glint from source on first run and re-runs on staged.gitlab-ci.ymlchanges - LSP server — shipped v0.2.29;
glint lspruns a JSON-RPC 2.0 LSP server over stdin/stdout;textDocument/didOpen,didChange,didSave,didCloseall publish diagnostics; rule IDs appear as the diagnosticcode; include resolution is best-effort using env-var token and default cache dir - VS Code extension — thin wrapper around the LSP server with syntax highlighting for
.gitlab-ci.yml
Configuration
.glint.ymlconfig file — shipped v0.2.19;ignore:,severity:,stages:,token:,url:,cache_dir:; searched from the pipeline directory up to the git root- Inline suppression comments — shipped v0.2.19;
# glint: ignore GL007before a job definition; comma/space-separated rules;# glint: ignore allwildcard
Reliability and developer experience
- Structured rule IDs — shipped post-v0.2.0; GL001–GL031 assigned; GL032 added v0.2.11; GL033 added v0.2.15; GL034–GL041 added v0.2.16; output formats added v0.2.18; GL042–GL043 added v0.2.20; GL044 added v0.2.24; graph improvements shipped v0.2.25–v0.2.26
glint explain <rule-id>— shipped v0.2.20; prints rule description, rationale, bad-YAML example, and fix;glint explain(no arg) lists all rules- Semantic versioning and first release — shipped v0.1.0 (2026-06-07)
- Subcommand CLI — shipped v0.2.0 (2026-06-11);
glint check/glint graph [mode]with ruff-style--help - Changelog automation — shipped v0.2.27;
cliff.tomlconfigures git-cliff to produce Keep-a-Changelog–compatible release notes from Conventional Commits;task changelogregeneratesCHANGELOG.md,task changelog-nextpreviews unreleased entries - Fuzz testing — shipped v0.2.27;
FuzzParseBytesandFuzzSanitizeYAMLEscapesininternal/model/fuzz_test.go; seeds run as regular tests in CI;task fuzzruns them continuously (default 30 s)