Skip to content

Release v0.25.4

Choose a tag to compare

@github-actions github-actions released this 07 Aug 17:25
· 8 commits to master since this release
4442e29

Docker Image

The Docker image for this release has been published to DockerHub:

Repository: gooddata/gooddata-goodchanges

Tags:

  • gooddata/gooddata-goodchanges:0.25.4
  • gooddata/gooddata-goodchanges:latest

Pull Commands

# Pull specific version
docker pull gooddata/gooddata-goodchanges:0.25.4

# Pull latest
docker pull gooddata/gooddata-goodchanges:latest

Run Command

docker run --rm gooddata/gooddata-goodchanges:0.25.4 [command]

Standalone Binaries

Download the binary for your platform from the assets below.

Platform Architecture Asset
Linux x86_64 goodchanges-linux-amd64.tar.gz
Linux ARM64 goodchanges-linux-arm64.tar.gz
macOS Intel goodchanges-darwin-amd64.tar.gz
macOS Apple Silicon goodchanges-darwin-arm64.tar.gz
Windows x86_64 goodchanges-windows-amd64.zip
Windows ARM64 goodchanges-windows-arm64.zip
All platforms
  • goodchanges-darwin-amd64.tar.gz
  • goodchanges-darwin-amd64.tar.gz.sha256
  • goodchanges-darwin-arm64.tar.gz
  • goodchanges-darwin-arm64.tar.gz.sha256
  • goodchanges-linux-amd64.tar.gz
  • goodchanges-linux-amd64.tar.gz.sha256
  • goodchanges-linux-arm64.tar.gz
  • goodchanges-linux-arm64.tar.gz.sha256
  • goodchanges-windows-amd64.zip
  • goodchanges-windows-amd64.zip.sha256
  • goodchanges-windows-arm64.zip
  • goodchanges-windows-arm64.zip.sha256

Install (Linux/macOS)

# Example: download and install linux/amd64
curl -sL https://github.com/gooddata/gooddata-goodchanges/releases/download/v0.25.4/goodchanges-linux-amd64.tar.gz | tar xz
chmod +x goodchanges-linux-amd64
sudo mv goodchanges-linux-amd64 /usr/local/bin/goodchanges

Changelog

0.25.4 - 2026-08-07

Fixed

  • Intra-file taint propagation now matches symbol names as whole identifiers instead of raw substrings. The dependency/usage checks used strings.Contains(body, name), so a symbol whose name is a substring of another was falsely linked — e.g. removing the unused chooseAction tainted the surviving, used chooseActionByIndex (its body "contains" the string chooseAction), which then propagated to a spec and flagged gdc-dashboards-e2e for a dead-code deletion. All six propagation sites (astdiff.go intra-file graph, plus the seed/importer/usage propagation in analyzer.go) now require the name to appear flanked by non-identifier characters ([A-Za-z0-9_$]) via a shared containsIdentifier helper; non-identifier tokens like the * wildcard keep the substring behaviour. Strictly more precise (it only drops matches that were substrings inside a larger identifier — never a real usage), so no false negatives.

0.25.3 - 2026-08-07

Fixed

  • Replaced the fine-grained path's whole-file * fallback with import-time-aware detection, so an empty symbol diff no longer floods every importer. Previously, when a changed file produced no symbol-level diff, FindAffectedFiles tainted the entire file with * — so a comment-only edit, a formatting change, a type-only change, or reordering imports in a widely-imported helper flagged all its consumers. That blanket is removed; a change now wildcards a file only when something that actually runs at import time changed:
    • a top-level side-effect statement (console.log(...), describe(...), test(...), etc.) — already detected via hasSideEffectStmtChanges;
    • a bare side-effect import (import "./x") added, removed, or re-pointed.
  • Named-import re-pointing is now handled precisely instead of via the blanket. When a binding keeps its name but resolves to a different module/export (import { x } from "./a" → "./b", or { a as x } → { b as x }), its usages don't change textually and the symbol diff missed them; those usages are now tainted directly. Reordering imports and re-pointing a type-only import (import type, when includeTypes is off) correctly taint nothing. Import statement type-only-ness is now tracked on tsparse.Import.

Together these keep genuine import-time changes flagged while eliminating the large false-positive class where a comment or dead-code edit to a shared file re-ran every dependent target.

  • Removing an unused export no longer floods every importer with taint. A deleted symbol was logged but never recorded as a change, so the per-file AST diff returned no affected symbols — and in the fine-grained path (FindAffectedFiles) an empty diff falls through to tainting the whole file with *. Deleting one unused export from a widely-imported helper (e.g. ERROR_MESSAGE from gdc-ldm-modeler-e2e's playwright/helpers/selectors.ts) therefore tainted every file that imported it, flagging all ~48 dependent specs. Deleted symbols are now recorded as changed and propagate by name, so a removed export taints exactly the files that imported that symbol: an unused one taints nobody, while a removed used export still flags its importers (no false negative). The deleted names are appended after intra-file propagation (which walks only surviving symbols) and before the whole-file side-effect fallback, so a deletion-only change is carried precisely instead of being widened.

0.25.1 - 2026-08-07

Fixed

  • Destructuring default initializers are now included in a binding's taint span. A binding's default (const { a = compute() } = obj, const [a = fallbackVal] = arr) is a real second dependency — it supplies the value when the destructured slot is undefined — but it lives on the pattern (LHS), disjoint from the mapped source (RHS), so the element-wise span recorded in 0.25.0 covered only the source and excluded the default. A symbol used only inside such a default therefore escaped findTaintedSymbolsByUsage — a false negative. The binding's span is now widened to cover the default expression as well as its mapped source. (Narrow in scope: only bites when a tainted symbol appears solely in a binding default and nowhere else in the file, but false negatives are always worth closing.)

0.25.0 - 2026-08-03

Changed

  • Destructured bindings are now attributed element-wise when the initializer is an array or object literal, refining the whole-initializer attribution added in 0.24.13. Previously every binding in const [a, b] = [tainted(), safe()] (or const { a, b } = { a: tainted(), b: safe() }) shared the entire initializer's span, so a change touching only one element tainted all the bindings — a false positive. Each binding is now mapped to its corresponding element (by index for array literals, by key for object literals, following nested patterns), and only falls back to the shared initializer span when mapping can't be done statically: a non-literal initializer (a call/identifier/member access — e.g. createStore(), where all bindings genuinely share the dependency), rest bindings (...rest), spreads, computed keys, or out-of-range indices. Net effect: a depends on tainted() and b on safe(), so a change to safe() no longer flags consumers of a.

0.24.13 - 2026-08-01

Fixed

  • Destructuring variable declarations (const { a, b } = expr / const [a, b] = expr) are now decomposed into their individual bindings for both symbol and export extraction. Previously getDeclName only handled plain identifiers and returned "" for binding patterns, so destructured names were registered as neither symbols nor exports — they simply didn't exist in the file model. That silently broke taint propagation through a very common pattern: e.g. export const { store, startSagas, … } = createStore() in gdc-analytical-designer-runtime's reduxStore.ts. A runtime change to the reducers feeding createStore tainted createStore, but the taint could not reach store/startSagas/…, so the package reported 0 affected exports and nothing propagated to the AD module/harness (or the dashboards harness that embeds it) — a false negative. Each destructured binding is now emitted as a symbol/export; renames ({ a: b } → b), rest elements (...x), nested patterns and array holes are handled. To stay precise, a binding's symbol span is the initializer expression (not the whole statement), so the sibling binding names don't bleed into the compared body and cross-link in the AST diff — each binding is attributed exactly to the initializer it destructures.

0.24.12 - 2026-07-30

Fixed

  • App taint propagation (added in 0.24.1) no longer over-flags downstream targets. An affected app was seeded into the upstream-taint map — tainting everything that imports it — whenever it was merely reachable in the affected set, i.e. a transitive dependent of any touched package. So a change to a library an app depends on flagged that app's harness/host consumers even when the change affected no export the app actually imports (e.g. removing unused exports from gdc-analytical-designer-runtime flagged gdc-analytical-designer-harness, gdc-dashboards-harness, and gdc-host-application). The wholesale-taint seed is now gated on the app being genuinely affected — the same conditions its own target detection uses: directly changed (has changed files), a changed lockfile dependency, or an actual tainted import from upstream (HasTaintedImportsForGlob). Apps that are only transitively reachable but import nothing that changed no longer propagate taint; real changes to exports an app imports still propagate as before. The per-package upstream-taint filter is also factored into a shared buildPkgUpstreamTaint helper used by both the library and app paths.

0.24.11 - 2026-07-30

Changed

0.24.10 - 2026-07-30

Fixed

  • Symbol-level AST diff no longer marks an unchanged declaration as changed when a neighboring declaration is edited or removed. Each symbol's body text was extracted starting at stmt.Pos(), which in the TS AST includes the symbol's leading trivia (the preceding comments and blank lines). Deleting a sibling — or otherwise changing what comes before a symbol — re-attaches the intervening comment (e.g. a // SECTION header) to the next symbol, so its extracted body differed between the old and new versions and it was reported as a runtime change. That false "change" then spread through the intra-file reference graph and out via the library's exports, over-tainting downstream consumers. Symbol start lines are now taken from the first real token (scanner.SkipTrivia), excluding leading comments/blank lines from the compared body. Example: removing three unused createSelector exports from bootstrap_selector.ts previously tainted nine untouched sibling selectors (and everything reachable from them); it now taints none.

0.24.9 - 2026-07-30

Changed

  • Renamed the LOG_LEVEL=BASIC/DEBUG summary line Affected e2e packages (N): to Affected targets (N):. The list has always contained resolved .goodchangesrc.json targets (unit-test targets, app/harness targets, etc.), not just e2e packages, so the label now reflects its actual contents. Log wording only — the JSON result on stdout is unchanged.

0.24.8 - 2026-07-23

Changed

0.24.7 - 2026-07-23

Changed

0.24.6 - 2026-07-23

Changed

0.24.5 - 2026-07-23

Changed

0.24.4 - 2026-07-23

Changed

0.24.3 - 2026-07-23

Changed

0.24.2 - 2026-07-23

Changed

[0.24.1] - 2026-07-21

Fixed

  • Affected apps now propagate taint to packages that import them. When a package is not a library, its per-symbol export analysis is skipped — but it was also seeding no taint at all, so the taint chain died at the app boundary. A consumer importing from an affected app (e.g. a thin harness that dynamically imports its app package: () => import("gdc-analytical-designer-module")) saw a clean upstream-taint map and was never flagged, so app/harness targets sitting behind an intermediate app went undetected. Now an affected app is tainted wholesale: all of its entrypoint exports are seeded into the upstream-taint map (mirroring the existing global-changeDirs full-taint seeding for libraries), so downstream importers match via the normal import graph — including bare/dynamic side-effect imports (empty import names), which match on any non-empty symbol set for the package. Example: a change in gdc-analytical-designer-runtime now correctly reaches gdc-analytical-designer-harness through the intermediate gdc-analytical-designer-module app.

0.24.0 - 2026-06-08

Added

  • CSS/SCSS taint now bridges into JS imports for the "JS-bundled CSS" pattern (most libs/gdc-*). Previously, a changed SCSS file propagated through cross-library @use chains (e.g. gdc-dashboards-runtime/src/styles/app.scss @uses @gooddata/sdk-ui-dashboard) but the taint lived in a separate __css__: namespace that was only matched against style imports. A consumer that pulls the styles in purely via a JavaScript import — import { Root } from "gdc-dashboards-runtime", where Root.tsx does import "./styles/app.scss" — never matched, so prod-affecting CSS changes failed to trigger app targets like gdc-dashboards. Now, while analysing each library (with INCLUDE_CSS=1), a local style file is treated as tainted if it @uses the styles of a CSS-tainted upstream package; any TS file that side-effect-imports that style file inherits taint on its exported symbols, which then rides the normal TS import graph into JS consumers. The __css__ closure is computed before library analysis (and threaded through the per-package upstream-taint filter) so it is available during seeding. This implements Stage 3 of properly-support-tree-shaken-scss-or-scss-modules.md; package.json sideEffects gating is still to come.

0.23.0 - 2026-06-07

Removed

  • Breaking: The app field on target definitions in .goodchangesrc.json (the "app-relationship" feature) and its IGNORE_APP_RELATIONSHIP env var are removed. Targets are no longer triggered just because a referenced app is affected — linking e2e targets to applications is the caller's responsibility, done after change detection. While this was helpful to us initially, it was later decided to be outside the scope of the change detector, which should be repository agnostic. It also conflated two distinct questions ("which apps need testing" vs "which e2e libs changed directly"), and forced a second invocation with IGNORE_APP_RELATIONSHIP to surface fine-grained detections the app check would otherwise hide. The app field is now silently ignored if present. Also removed the now-unused analyzer.HasTaintedImports helper.

0.22.0 - 2026-06-07

Changed

  • LOG_LEVEL=BASIC output is now prefixed with [BASIC] on every line, mirroring the existing [DEBUG] prefix. log.Basicf now prepends [BASIC] and appends the trailing newline itself (matching Debugf), so callers no longer carry their own \n. Output is otherwise unchanged.

0.21.3 - 2026-06-07

Fixed

  • LOG_LEVEL=BASIC (and the BASIC-gated output under DEBUG) emitted nothing. main set the local flagLog from LOG_LEVEL but only ever assigned log.Debug, never log.Basic, so the package-level Basic flag stayed false and every log.Basicf(...) call was silently swallowed. log.Basic is now set from flagLog, restoring the progress/affected-package logging on stderr while the JSON result stays on stdout.

0.21.2 - 2026-06-01

Fixed

  • Targets that reference an app (e.g. e2e targets with "app": "gdc-analytical-designer") are now triggered when that app is affected via a changed dependency. When TARGETS was set, the relevant-package set was seeded only from each matched target's own package and its transitive dependencies — but a target's app is a logical relationship, not an npm dependency, so the app and its dependency subtree (e.g. the runtime library whose change is meant to trigger the e2e target) were excluded from analysis, produced no taint, and the app-taint check always came up empty. The seed set now also includes td.App (unless IGNORE_APP_RELATIONSHIP is set), so the app and its dependencies are analyzed and the app-taint check fires.

0.21.1 - 2026-05-31

Fixed

  • Aliased named imports (import { X as Y }) now propagate taint correctly. The import parser only captured the local binding name (Y) and discarded the original imported name (X), so taint matching — which keys on the name the source module exports — never matched, and propagation stopped at the renamed hop. Imports now carry both names: the source-side name is used to match exported/affected symbols, and the local name is used to scan the importing file's body for usage. This fixes cases like import { Root as InnerRoot } where a change to Root failed to reach the importing file's exports (and therefore its entrypoint and dependent targets).

0.21.0 - 2026-05-02

Added

  • Top-level type field in .goodchangesrc.json ("library" or "app"). When set, overrides the automatic library-vs-app inference from package.json. Invalid values cause a fatal error at startup.

0.20.0 - 2026-05-01

Changed

  • LOG_LEVEL=BASIC output now goes to stderr instead of stdout. Stdout is reserved for the JSON result, so piping goodchanges | jq … works with logging enabled.

0.19.4 - 2026-04-29

Changed

0.19.3 - 2026-04-28

Changed

0.19.2 - 2026-04-24

Fixed

  • Bare dynamic import("pkg") calls (e.g. () => import("pkg") passed to a loader, or const mod = await import("pkg") used opaquely without property access) are now recorded as side-effect imports, so taint on the target package propagates to the importing file. Previously only the three pattern forms (var+property-access, destructure, .then callback) produced an Import record, leaving bare calls invisible to taint propagation.

0.19.1 - 2026-04-23

Fixed

  • Global changeDirs taint now enumerates every export from each entrypoint (including recursively via export * from "./local") instead of seeding a "*" wildcard. Downstream packages consume exports by exact name, so the wildcard never matched named imports — taint stopped at the first hop and targets transitively dependent on the tainted library were missed.

0.19.0 - 2026-04-20

Added

  • IGNORE_APP_RELATIONSHIP env var. When set, the app field in target configs is ignored — targets are no longer triggered just because their corresponding app is tainted (only direct changes, lockfile changes, and tainted workspace imports apply).

0.18.1 - 2026-04-13

Changed

0.18.0 - 2026-04-10

Added

  • Global changeDirs field in .goodchangesrc.json (top-level, next to ignores). Matching files taint all exports (libraries) and trigger all targets in the package.

0.17.1 - 2026-04-10

Fixed

  • Detect runtime side-effect statements (e.g. console.log()) in entrypoint/barrel files as affecting all exports — previously these were misclassified as "comments/imports only" and seeded zero taint

0.17.0 - 2026-04-04

Changed

  • Breaking: Lockfile dep change detection now parses old and new pnpm-lock.yaml as YAML (gopkg.in/yaml.v3) instead of diffing text lines. Compares resolved versions for direct deps per importer, and BFS-walks the snapshots section to detect transitive dep version changes — a transitive change taints the direct dep that pulled it in.

0.16.7 - 2026-04-04

Changed

0.16.6 - 2026-04-04

Changed

0.16.5 - 2026-04-04

Changed

0.16.4 - 2026-04-04

Changed

0.16.3 - 2026-04-04

Changed

0.16.2 - 2026-04-04

Changed

0.16.1 - 2026-04-04

Changed

0.16.0 - 2026-04-04

Changed

  • Breaking: Merged target and virtual-target types into a unified target definition. The type field is removed. All targets now support app, targetName, changeDirs, lockfile detection, and fine-grained mode. targetName defaults to the package name when not set. changeDirs defaults to **/* when not set.

0.15.3 - 2026-02-23

Fixed

  • Add intra-file taint propagation after seeding phase in both AnalyzeLibraryPackage and FindAffectedFiles, so that symbols referencing other tainted symbols in the same file are also marked as tainted before BFS starts

0.15.2 - 2026-02-20

Fixed

  • Fix export const/export let declarations not being added to the exports list in the TS parser, causing locally declared exported variables (e.g. export const allScenarios = [...]) to be invisible during entrypoint taint checking

0.15.1 - 2026-02-17

Changed

0.15.0 - 2026-02-17

Added

  • lockfileVersion change detection: when lockfileVersion changes in a subspace's pnpm-lock.yaml, all projects in that subspace are treated as having all external deps changed, and all library exports are wildcard-tainted. This propagates transitively through the existing dependency graph and taint analysis.
  • ParseLockfileVersion using proper YAML parsing (gopkg.in/yaml.v3) to compare old vs new lockfile versions

0.14.2 - 2026-02-16

Added

  • Comprehensive debug logging across all analyzer functions: FindAffectedFiles, FindEntrypoints, CollectEntrypointExports, HasTaintedImports, HasTaintedImportsForGlob, FindCSSTaintedPackages, and import resolution (resolve.go)

0.14.1 - 2026-02-16

Changed

0.14.0 - 2026-02-14

Added

  • JSON import taint propagation: changed .json files now taint TS/JS files that import them, with symbol-level granularity based on usage of the imported binding

0.13.0 - 2026-02-14

Added

  • Per-target ignores field in target definitions. Per-target ignores are additive with the global ignores and only apply to the specific target's detection.

0.12.0 - 2026-02-14

Changed

  • Breaking: .goodchangesrc.json now uses a targets array instead of a single top-level target definition. Each entry in targets is a target object with type, app, targetName, and changeDirs. The ignores field remains at the top level (shared across all targets).

0.11.2 - 2026-02-14

Fixed

  • Fine-grained detection now seeds taint from changed CSS/SCSS files within the project (with CSS module granularity for *.module.scss/*.module.css)

0.11.1 - 2026-02-14

Changed

  • Fine-grained detection now uses symbol-level taint propagation matching library analysis: AST diffs identify changed symbols, import graph tracks name mappings, BFS only propagates to importers of actually changed symbols, with intra-file and re-export handling

0.11.0 - 2026-02-14

Added

  • -v / --version flag prints the embedded version from the VERSION file

0.10.0 - 2026-02-14

Added

  • Fine-grained changeDirs entries now support an optional filter field to narrow output results (e.g. {"glob": "src/**/*", "filter": "src/**/*.test.ts", "type": "fine-grained"} analyzes all files but only returns affected test files)

0.9.5 - 2026-02-14

Changed

  • Fine-grained changeDirs now AST-diff changed files against the merge base; whitespace-only or comment-only changes no longer cascade through importers

0.9.4 - 2026-02-14

Fixed

  • Fine-grained BFS propagation now follows re-exports (export { X } from "./foo", export * from "./foo") so barrel files no longer break the chain

0.9.3 - 2026-02-14

Fixed

  • Fine-grained changeDirs now detect lockfile dependency changes (pnpm-lock.yaml upgrades taint files importing the affected external dep)

0.9.2 - 2026-02-14

Changed

  • CSS module imports (*.module.scss/*.module.css) with named bindings now use granular taint: only symbols that reference the imported binding are tainted, instead of all exports in the file

0.9.1 - 2026-02-14

Fixed

  • Changed CSS/SCSS files within a library now taint TS files that relatively import them (e.g. import "./styles.scss" taints all exports of the importing file)

0.9.0 - 2026-02-14

Changed

  • Breaking: changeDirs entries now use glob patterns instead of directory paths ("glob" field replaces "path")
  • Glob matching uses doublestar: * matches files in current dir, **/* matches all nested files, **/*.stories.tsx matches specific patterns
  • Ignores override glob matches: if a file matches a glob but is also in ignores, it is excluded
  • Fine-grained changeDirs only match TS/TSX source files

0.8.0 - 2026-02-14

Changed

  • When TARGETS is set, compute relevant package set (active targets + transitive dependencies) and skip change detection, library analysis, and transitive dependent walks for irrelevant packages

0.7.1 - 2026-02-14

Fixed

  • Load all .goodchangesrc.json configs once at startup instead of re-reading from disk per changed file and again during target detection

0.7.0 - 2026-02-14

Changed

  • Skip expensive target detection (file scanning, taint import checks) for targets excluded by TARGETS filter

0.6.0 - 2026-02-14

Added

  • Optional TARGETS env var to filter output by target name (comma-delimited, supports * wildcard globs)

0.5.1 - 2026-02-14

Fixed

  • Fix ignore globs not supporting ** patterns (e.g. scenarios/**/*.md) by replacing filepath.Match with doublestar.Match

0.5.0 - 2026-02-13

Added

  • Fine-grained virtual target detection: changeDirs entries can specify "type": "fine-grained" to collect specific affected files instead of triggering a full run
  • New FindAffectedFiles analyzer function for transitive file-level taint propagation within directories
  • Output format changed from []string to []{"name", "detections?"} for richer target information

Changed

  • changeDirs config field is now an array of objects ({"path": "...", "type?": "..."}) instead of plain strings

0.4.0 - 2026-02-13

Changed

  • Parallelize library analysis within the same topological level using goroutines

0.3.0 - 2026-02-13

Added

  • install.sh script for downloading and installing standalone binaries with SHA-256 verification

0.2.5 - 2026-02-13

Changed

0.2.4 - 2026-02-12

Changed

  • Trim release binaries to 6 targets: linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64, windows/arm64

0.2.3 - 2026-02-12

Added

  • SHA-256 hash files (.sha256) for every release binary

0.2.2 - 2026-02-12

Fixed

  • Fix runner label for GitHub release job (runners-cxa-xlarge, not cxa-xlarge)

0.2.1 - 2026-02-12

Changed

  • Use cxa-xlarge runner for GitHub release job (cross-compiling 32 binaries)
  • Docker images limited to linux/amd64 and linux/arm64 only (other platforms served via standalone binaries)

0.2.0 - 2026-02-12

Added

  • Cross-platform standalone binaries attached to GitHub releases (32 targets)
  • Support for Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, Solaris, Illumos, AIX, DragonFlyBSD

Changed

  • Docker build uses Go cross-compilation instead of QEMU emulation for faster multi-platform builds

0.1.0 - 2026-02-11

Added

  • Initial release
  • AST-level change detection for Rush monorepo libraries using vendored typescript-go parser
  • Taint propagation through workspace dependency graph (unlimited BFS hops)
  • Target and virtual target support via .goodchangesrc.json configuration
  • Lockfile dependency change detection (pnpm-lock.yaml)
  • Optional CSS/SCSS taint tracking and propagation through @use/@import chains
  • Optional type-only change detection (interfaces, type aliases, annotations)
  • Multi-stage Docker build
  • Automated vendor upgrade workflow

Build Information

  • Commit: 4442e29
  • Build Date: 2026-08-07 17:25:58 UTC
  • Workflow Run: #83