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

[0.13.0]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.12.0...v0.13.0
[0.12.0]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.11.2...v0.12.0
[0.11.2]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.11.1...v0.11.2
[0.11.1]: https://github.com/gooddata/gooddata-goodchanges/compare/v0.11.0...v0.11.1
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ Each `changeDirs` entry is an object with:
| `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 | Glob patterns to match files. Each entry: `{"glob": "...", "filter?": "...", "type?": "fine-grained"}` |
| `ignores` | `string[]` | Both | Per-target ignore globs. Additive with the global `ignores` -- only applies to this target's 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.12.0
0.13.0
16 changes: 15 additions & 1 deletion internal/rush/rush.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ type TargetDef struct {
App *string `json:"app,omitempty"` // rush project name of corresponding app
TargetName *string `json:"targetName,omitempty"` // output name for virtual targets
ChangeDirs []ChangeDir `json:"changeDirs,omitempty"` // globs to watch for virtual targets
Ignores []string `json:"ignores,omitempty"` // per-target ignore globs (additive with global)
}

// IsTarget returns true if this target definition is a regular target.
Expand Down Expand Up @@ -181,7 +182,20 @@ func (pc *ProjectConfig) IsIgnored(relPath string) bool {
return false
}


// WithTargetIgnores returns a new ProjectConfig with the target's ignores merged in.
// The returned config's IsIgnored checks both global and per-target patterns.
func (pc *ProjectConfig) WithTargetIgnores(td TargetDef) *ProjectConfig {
if len(td.Ignores) == 0 {
return pc
}
merged := &ProjectConfig{
Targets: pc.Targets,
Ignores: make([]string, 0, len(pc.Ignores)+len(td.Ignores)),
}
merged.Ignores = append(merged.Ignores, pc.Ignores...)
merged.Ignores = append(merged.Ignores, td.Ignores...)
return merged
}

// FindChangedProjects determines which projects have files in the changed file list.
// Files matching ignore globs in .goodchangesrc.json are excluded.
Expand Down
13 changes: 8 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ func main() {
}

for _, td := range cfg.Targets {
// Merge global + per-target ignores for this target's detection
targetCfg := cfg.WithTargetIgnores(td)

if td.IsTarget() {
if len(targetPatterns) > 0 && !matchesTargetFilter(rp.PackageName, targetPatterns) {
continue
Expand All @@ -332,7 +335,7 @@ func main() {
for _, f := range changedFiles {
if strings.HasPrefix(f, rp.ProjectFolder+"/") {
relPath := strings.TrimPrefix(f, rp.ProjectFolder+"/")
if !cfg.IsIgnored(relPath) {
if !targetCfg.IsIgnored(relPath) {
triggered = true
break
}
Expand All @@ -350,7 +353,7 @@ func main() {
}

// Condition 3: Tainted workspace imports
if analyzer.HasTaintedImports(rp.ProjectFolder, allUpstreamTaint, cfg) {
if analyzer.HasTaintedImports(rp.ProjectFolder, allUpstreamTaint, targetCfg) {
changedE2E[rp.PackageName] = &TargetResult{Name: rp.PackageName}
continue
}
Expand Down Expand Up @@ -388,7 +391,7 @@ func main() {
if cd.Filter != nil {
filterPattern = *cd.Filter
}
detected := analyzer.FindAffectedFiles(cd.Glob, filterPattern, allUpstreamTaint, changedFiles, rp.ProjectFolder, cfg, depChangedDeps[rp.ProjectFolder], mergeBase, flagIncludeTypes)
detected := analyzer.FindAffectedFiles(cd.Glob, filterPattern, allUpstreamTaint, changedFiles, rp.ProjectFolder, targetCfg, depChangedDeps[rp.ProjectFolder], mergeBase, flagIncludeTypes)
if len(detected) > 0 {
fineGrainedDetections = append(fineGrainedDetections, detected...)
}
Expand All @@ -399,7 +402,7 @@ func main() {
continue
}
relPath := strings.TrimPrefix(f, rp.ProjectFolder+"/")
if cfg.IsIgnored(relPath) {
if targetCfg.IsIgnored(relPath) {
continue
}
if matched, _ := doublestar.Match(cd.Glob, relPath); matched {
Expand All @@ -408,7 +411,7 @@ func main() {
}
}
if !normalTriggered {
if analyzer.HasTaintedImportsForGlob(rp.ProjectFolder, cd.Glob, allUpstreamTaint, cfg) {
if analyzer.HasTaintedImportsForGlob(rp.ProjectFolder, cd.Glob, allUpstreamTaint, targetCfg) {
normalTriggered = true
}
}
Expand Down