Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [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
Expand Down Expand Up @@ -78,6 +83,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Multi-stage Docker build
- Automated vendor upgrade workflow

[0.6.0]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.5.1...v0.6.0
[0.5.1]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.3.0...v0.4.0
Expand Down
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ JSON array of target objects:

## Environment variables

| Variable | Description | Default |
|---|---|---|
| `LOG_LEVEL` | Logging verbosity. `BASIC` for standard logging, `DEBUG` for verbose AST/taint tracing to stderr | _(no logging)_ |
| `INCLUDE_TYPES` | When set to any non-empty value, includes type-only changes (interfaces, type aliases, type annotations) in taint propagation | _(disabled)_ |
| `INCLUDE_CSS` | When set to any non-empty value, enables CSS/SCSS change detection and taint propagation through `@use`/`@import` chains | _(disabled)_ |
| `COMPARE_COMMIT` | Specific git commit hash to compare against (overrides branch-based comparison) | _(empty)_ |
| `COMPARE_BRANCH` | Git branch to compute merge base against | `origin/master` |
| Variable | Description | Default |
|------------------|-------------------------------------------------------------------------------------------------------------------------------|-----------------|
| `LOG_LEVEL` | Logging verbosity. `BASIC` for standard logging, `DEBUG` for verbose AST/taint tracing to stderr | _(no logging)_ |
| `INCLUDE_TYPES` | When set to any non-empty value, includes type-only changes (interfaces, type aliases, type annotations) in taint propagation | _(disabled)_ |
| `INCLUDE_CSS` | When set to any non-empty value, enables CSS/SCSS change detection and taint propagation through `@use`/`@import` chains | _(disabled)_ |
| `COMPARE_COMMIT` | Specific git commit hash to compare against (overrides branch-based comparison) | _(empty)_ |
| `COMPARE_BRANCH` | Git branch to compute merge base against | `origin/master` |
| `TARGETS` | Comma-delimited list of target names to include in output. Supports `*` wildcard (e.g. `*backstop*,@gooddata/sdk-*`). | _(all targets)_ |

## Library vs app detection

Expand Down Expand Up @@ -127,13 +128,13 @@ Each `changeDirs` entry is an object with:

### Fields reference

| Field | Type | Used by | Description |
|---|---|---|---|
| `type` | `"target"` \| `"virtual-target"` | Both | Declares what kind of target this project is |
| `app` | `string` | Target | Package name of the corresponding app this e2e package tests |
| `targetName` | `string` | Virtual target | Output name emitted when the virtual target is triggered |
| `changeDirs` | `ChangeDir[]` | Virtual target | Directories to watch. Each entry: `{"path": "...", "type?": "fine-grained"}` |
| `ignores` | `string[]` | Both | Glob patterns for files to exclude from change detection |
| Field | Type | Used by | Description |
|--------------|----------------------------------|----------------|------------------------------------------------------------------------------|
| `type` | `"target"` \| `"virtual-target"` | Both | Declares what kind of target this project is |
| `app` | `string` | Target | Package name of the corresponding app this e2e package tests |
| `targetName` | `string` | Virtual target | Output name emitted when the virtual target is triggered |
| `changeDirs` | `ChangeDir[]` | Virtual target | Directories to watch. Each entry: `{"path": "...", "type?": "fine-grained"}` |
| `ignores` | `string[]` | Both | Glob patterns for files to exclude from change detection |

The `.goodchangesrc.json` file itself is always ignored.

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.1
0.6.0
39 changes: 39 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -364,6 +365,18 @@ func main() {
return e2eList[i].Name < e2eList[j].Name
})

// Filter targets if TARGETS env is set (comma-delimited, supports * globs)
if targetsEnv := os.Getenv("TARGETS"); targetsEnv != "" {
patterns := strings.Split(targetsEnv, ",")
var filtered []*TargetResult
for _, result := range e2eList {
if matchesTargetFilter(result.Name, patterns) {
filtered = append(filtered, result)
}
}
e2eList = filtered
}

if flagLog {
logf("Affected e2e packages (%d):\n", len(e2eList))
for _, result := range e2eList {
Expand Down Expand Up @@ -417,3 +430,29 @@ func findLockfileAffectedProjects(config *rush.Config, mergeBase string) map[str
}
return result
}

// matchesTargetFilter checks if a target name matches any of the given patterns.
// Patterns support * as a wildcard matching any characters (including /).
func matchesTargetFilter(name string, patterns []string) bool {
for _, p := range patterns {
p = strings.TrimSpace(p)
if p == "" {
continue
}
// Convert glob pattern to regex: * -> .*, escape the rest
var re strings.Builder
re.WriteString("^")
for _, ch := range p {
if ch == '*' {
re.WriteString(".*")
} else {
re.WriteString(regexp.QuoteMeta(string(ch)))
}
}
re.WriteString("$")
if matched, _ := regexp.MatchString(re.String(), name); matched {
return true
}
}
return false
}