Skip to content

Commit 87984fe

Browse files
authored
feat: add source dir optional configuration (#169)
1 parent bffef42 commit 87984fe

File tree

8 files changed

+73
-45
lines changed

8 files changed

+73
-45
lines changed

action.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ inputs:
88
required: false
99
default: ""
1010
type: string
11-
11+
source-dir:
12+
description: Sets relative path to source files.
13+
required: false
14+
default: ""
15+
type: string
16+
1217
# Individual properties
1318
profile:
1419
description: Path to the coverage profile file. Overrides value from configuration.
@@ -132,6 +137,7 @@ runs:
132137
args:
133138
- --config=${{ inputs.config || '''''' }}
134139
- --profile=${{ inputs.profile || '''''' }}
140+
- --source-dir=${{ inputs.source-dir || '''''' }}
135141
- --github-action-output=true
136142
- --threshold-file=${{ inputs.threshold-file }}
137143
- --threshold-package=${{ inputs.threshold-package }}

docs/github_action.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ Alternatively, if you don't need advanced configuration options from a config fi
3838
3939
Note: When using a config file alongside action properties, specifying these parameters will override the corresponding values in the config file.
4040
41+
## Source Directory
42+
43+
Some projects, such as monorepos with multiple projects under the root directory, may require specifying the path to a project's source.
44+
In such cases, the `source-dir` property can be used to specify the source files location relative to the root directory.
45+
46+
```yml
47+
- name: check test coverage
48+
uses: vladopajic/go-test-coverage@v2
49+
with:
50+
config: ./.testcoverage.yml
51+
source-dir: ./some_project
52+
```
53+
4154
## Liberal Coverage Check
4255

4356
The `go-test-coverage` GitHub Action can be configured to report the current test coverage without enforcing specific thresholds. To enable this functionality in your GitHub workflow, include the `continue-on-error: true` property in the job step configuration. This ensures that the workflow proceeds even if the coverage check fails.

main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type args struct {
2727
ConfigPath string `arg:"-c,--config"`
2828
Profile string `arg:"-p,--profile" help:"path to coverage profile"`
2929
LocalPrefix string `arg:"-l,--local-prefix"` // deprecated
30+
SourceDir string `arg:"-s,--source-dir"`
3031
GithubActionOutput bool `arg:"-o,--github-action-output"`
3132
ThresholdFile int `arg:"-f,--threshold-file"`
3233
ThresholdPackage int `arg:"-k,--threshold-package"`
@@ -56,6 +57,7 @@ func newArgs() args {
5657
ConfigPath: ciDefaultString,
5758
Profile: ciDefaultString,
5859
LocalPrefix: ciDefaultString,
60+
SourceDir: ciDefaultString,
5961
GithubActionOutput: false,
6062
ThresholdFile: ciDefaultInt,
6163
ThresholdPackage: ciDefaultInt,
@@ -102,6 +104,10 @@ func (a *args) overrideConfig(cfg testcoverage.Config) (testcoverage.Config, err
102104
cfg.LocalPrefixDeprecated = a.LocalPrefix
103105
}
104106

107+
if !isCIDefaultString(a.SourceDir) {
108+
cfg.SourceDir = a.SourceDir
109+
}
110+
105111
if !isCIDefaultInt(a.ThresholdFile) {
106112
cfg.Threshold.File = a.ThresholdFile
107113
}

pkg/testcoverage/check.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func GenerateCoverageStats(cfg Config) ([]coverage.Stats, error) {
7474
return coverage.GenerateCoverageStats(coverage.Config{ //nolint:wrapcheck // err wrapped above
7575
Profiles: strings.Split(cfg.Profile, ","),
7676
ExcludePaths: cfg.Exclude.Paths,
77-
RootDir: cfg.RootDir,
77+
SourceDir: cfg.SourceDir,
7878
})
7979
}
8080

pkg/testcoverage/check_test.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ const (
2222
breakdownOK = testdataDir + testdata.BreakdownOK
2323
breakdownNOK = testdataDir + testdata.BreakdownNOK
2424

25-
prefix = "github.com/vladopajic/go-test-coverage/v2"
26-
rootDir = "../../"
25+
prefix = "github.com/vladopajic/go-test-coverage/v2"
26+
sourceDir = "../../"
2727
)
2828

2929
func TestCheck(t *testing.T) {
@@ -60,7 +60,7 @@ func TestCheck(t *testing.T) {
6060
t.Parallel()
6161

6262
buf := &bytes.Buffer{}
63-
cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 65}, RootDir: rootDir}
63+
cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 65}, SourceDir: sourceDir}
6464
pass := Check(buf, cfg)
6565
assert.True(t, pass)
6666
assertGithubActionErrorsCount(t, buf.String(), 0)
@@ -79,7 +79,7 @@ func TestCheck(t *testing.T) {
7979
Exclude: Exclude{
8080
Paths: []string{`cdn\.go$`, `github\.go$`, `cover\.go$`, `check\.go$`, `path\.go$`},
8181
},
82-
RootDir: rootDir,
82+
SourceDir: sourceDir,
8383
}
8484
pass := Check(buf, cfg)
8585
assert.True(t, pass)
@@ -92,7 +92,7 @@ func TestCheck(t *testing.T) {
9292
t.Parallel()
9393

9494
buf := &bytes.Buffer{}
95-
cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 100}, RootDir: rootDir}
95+
cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 100}, SourceDir: sourceDir}
9696
pass := Check(buf, cfg)
9797
assert.False(t, pass)
9898
assertGithubActionErrorsCount(t, buf.String(), 0)
@@ -113,7 +113,7 @@ func TestCheck(t *testing.T) {
113113
Profile: profileOK,
114114
Threshold: Threshold{File: 100},
115115
Override: []Override{{Threshold: 10, Path: "^pkg"}},
116-
RootDir: rootDir,
116+
SourceDir: sourceDir,
117117
}
118118
pass := Check(buf, cfg)
119119
assert.True(t, pass)
@@ -131,7 +131,7 @@ func TestCheck(t *testing.T) {
131131
Profile: profileOK,
132132
Threshold: Threshold{File: 10},
133133
Override: []Override{{Threshold: 100, Path: "^pkg"}},
134-
RootDir: rootDir,
134+
SourceDir: sourceDir,
135135
}
136136
pass := Check(buf, cfg)
137137
assert.False(t, pass)
@@ -153,7 +153,7 @@ func TestCheck(t *testing.T) {
153153
Profile: profileOK,
154154
Threshold: Threshold{File: 70},
155155
Override: []Override{{Threshold: 60, Path: "pkg/testcoverage/badgestorer/github.go"}},
156-
RootDir: rootDir,
156+
SourceDir: sourceDir,
157157
}
158158
pass := Check(buf, cfg)
159159
assert.True(t, pass)
@@ -171,7 +171,7 @@ func TestCheck(t *testing.T) {
171171
Profile: profileOK,
172172
Threshold: Threshold{File: 70},
173173
Override: []Override{{Threshold: 80, Path: "pkg/testcoverage/badgestorer/github.go"}},
174-
RootDir: rootDir,
174+
SourceDir: sourceDir,
175175
}
176176
pass := Check(buf, cfg)
177177
assert.False(t, pass)
@@ -195,7 +195,7 @@ func TestCheck(t *testing.T) {
195195
Badge: Badge{
196196
FileName: t.TempDir(), // should failed because this is dir
197197
},
198-
RootDir: rootDir,
198+
SourceDir: sourceDir,
199199
}
200200
pass := Check(buf, cfg)
201201
assert.False(t, pass)
@@ -209,7 +209,7 @@ func TestCheck(t *testing.T) {
209209
cfg := Config{
210210
Profile: profileOK,
211211
BreakdownFileName: t.TempDir(), // should failed because this is dir
212-
RootDir: rootDir,
212+
SourceDir: sourceDir,
213213
}
214214
pass := Check(buf, cfg)
215215
assert.False(t, pass)
@@ -223,7 +223,7 @@ func TestCheck(t *testing.T) {
223223
cfg := Config{
224224
Profile: profileOK,
225225
BreakdownFileName: t.TempDir() + "/breakdown.testcoverage",
226-
RootDir: rootDir,
226+
SourceDir: sourceDir,
227227
}
228228
pass := Check(buf, cfg)
229229
assert.True(t, pass)
@@ -246,7 +246,7 @@ func TestCheck(t *testing.T) {
246246
Diff: Diff{
247247
BaseBreakdownFileName: t.TempDir(), // should failed because this is dir
248248
},
249-
RootDir: rootDir,
249+
SourceDir: sourceDir,
250250
}
251251
pass := Check(buf, cfg)
252252
assert.False(t, pass)
@@ -268,7 +268,7 @@ func TestCheckNoParallel(t *testing.T) {
268268
Profile: profileOK,
269269
GithubActionOutput: true,
270270
Threshold: Threshold{Total: 100},
271-
RootDir: rootDir,
271+
SourceDir: sourceDir,
272272
}
273273
pass := Check(buf, cfg)
274274
assert.False(t, pass)
@@ -283,7 +283,7 @@ func TestCheckNoParallel(t *testing.T) {
283283
Profile: profileOK,
284284
GithubActionOutput: true,
285285
Threshold: Threshold{Total: 10},
286-
RootDir: rootDir,
286+
SourceDir: sourceDir,
287287
}
288288
pass := Check(buf, cfg)
289289
assert.True(t, pass)
@@ -302,7 +302,7 @@ func TestCheckNoParallel(t *testing.T) {
302302
Profile: profileOK,
303303
GithubActionOutput: true,
304304
Threshold: Threshold{Total: 100},
305-
RootDir: rootDir,
305+
SourceDir: sourceDir,
306306
}
307307
pass := Check(buf, cfg)
308308
assert.False(t, pass)

pkg/testcoverage/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ var (
2424
type Config struct {
2525
Profile string `yaml:"profile"`
2626
LocalPrefixDeprecated string `yaml:"-"`
27+
SourceDir string `yaml:"-"`
2728
Threshold Threshold `yaml:"threshold"`
2829
Override []Override `yaml:"override,omitempty"`
2930
Exclude Exclude `yaml:"exclude"`
3031
BreakdownFileName string `yaml:"breakdown-file-name"`
3132
GithubActionOutput bool `yaml:"github-action-output"`
3233
Diff Diff `yaml:"diff"`
3334
Badge Badge `yaml:"-"`
34-
RootDir string `yaml:"-"`
3535
}
3636

3737
type Threshold struct {

pkg/testcoverage/coverage/cover.go

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const IgnoreText = "coverage-ignore"
2121
type Config struct {
2222
Profiles []string
2323
ExcludePaths []string
24-
RootDir string
24+
SourceDir string
2525
}
2626

2727
func GenerateCoverageStats(cfg Config) ([]Stats, error) {
@@ -30,7 +30,7 @@ func GenerateCoverageStats(cfg Config) ([]Stats, error) {
3030
return nil, fmt.Errorf("parsing profiles: %w", err)
3131
}
3232

33-
files, err := findFiles(profiles, cfg.RootDir)
33+
files, err := findFiles(profiles, cfg.SourceDir)
3434
if err != nil {
3535
return nil, err
3636
}
@@ -121,17 +121,7 @@ func findFiles(profiles []*cover.Profile, rootDir string) (map[string]fileInfo,
121121
return result, nil
122122
}
123123

124-
func defaultRootDir(rootDir string) string {
125-
if rootDir == "" {
126-
rootDir = "."
127-
}
128-
129-
return rootDir
130-
}
131-
132124
func findFileCreator(rootDir string) func(file string) (string, string, bool) {
133-
rootDir = defaultRootDir(rootDir)
134-
135125
cache := make(map[string]*build.Package)
136126
findBuildImport := func(file string) (string, string, bool) {
137127
dir, file := filepath.Split(file)
@@ -155,6 +145,7 @@ func findFileCreator(rootDir string) func(file string) (string, string, bool) {
155145
return file, noPrefixName, err == nil
156146
}
157147

148+
rootDir = defaultRootDir(rootDir)
158149
prefix := findModuleDirective(rootDir)
159150
files := listAllFiles(rootDir)
160151
findWalk := func(file, prefix string) (string, string, bool) {
@@ -177,9 +168,24 @@ func findFileCreator(rootDir string) func(file string) (string, string, bool) {
177168
}
178169
}
179170

171+
func defaultRootDir(rootDir string) string {
172+
if rootDir == "" {
173+
rootDir = "."
174+
}
175+
176+
return rootDir
177+
}
178+
180179
func listAllFiles(rootDir string) []fileInfo {
181180
files := make([]fileInfo, 0)
182181

182+
makeName := func(file string) string {
183+
name, _ := strings.CutPrefix(file, rootDir)
184+
name = path.NormalizeForTool(name)
185+
186+
return name
187+
}
188+
183189
//nolint:errcheck // error ignored because there is fallback mechanism for finding files
184190
filepath.Walk(rootDir, func(file string, info os.FileInfo, err error) error {
185191
if err != nil { // coverage-ignore
@@ -189,12 +195,9 @@ func listAllFiles(rootDir string) []fileInfo {
189195
if !info.IsDir() &&
190196
strings.HasSuffix(file, ".go") &&
191197
!strings.HasSuffix(file, "_test.go") {
192-
name, _ := strings.CutPrefix(file, rootDir)
193-
name = path.NormalizeForTool(name)
194-
195198
files = append(files, fileInfo{
196199
path: file,
197-
name: name,
200+
name: makeName(file),
198201
})
199202
}
200203

pkg/testcoverage/coverage/cover_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const (
2525
prefix = "github.com/vladopajic/go-test-coverage/v2"
2626
coverFilename = "pkg/testcoverage/coverage/cover.go"
2727

28-
rootDir = "../../../"
28+
sourceDir = "../../../"
2929
)
3030

3131
func Test_GenerateCoverageStats(t *testing.T) {
@@ -42,16 +42,16 @@ func Test_GenerateCoverageStats(t *testing.T) {
4242

4343
// should get error parsing invalid profile file
4444
stats, err = GenerateCoverageStats(Config{
45-
Profiles: []string{profileNOK},
46-
RootDir: rootDir,
45+
Profiles: []string{profileNOK},
46+
SourceDir: sourceDir,
4747
})
4848
assert.Error(t, err)
4949
assert.Empty(t, stats)
5050

5151
// should be okay to read valid profile
5252
stats1, err := GenerateCoverageStats(Config{
53-
Profiles: []string{profileOK},
54-
RootDir: rootDir,
53+
Profiles: []string{profileOK},
54+
SourceDir: sourceDir,
5555
})
5656
assert.NoError(t, err)
5757
assert.NotEmpty(t, stats1)
@@ -60,7 +60,7 @@ func Test_GenerateCoverageStats(t *testing.T) {
6060
stats2, err := GenerateCoverageStats(Config{
6161
Profiles: []string{profileOK},
6262
ExcludePaths: []string{`cover\.go$`},
63-
RootDir: rootDir,
63+
SourceDir: sourceDir,
6464
})
6565
assert.NoError(t, err)
6666
assert.NotEmpty(t, stats2)
@@ -69,17 +69,17 @@ func Test_GenerateCoverageStats(t *testing.T) {
6969

7070
// should have total coverage because of second profile
7171
stats3, err := GenerateCoverageStats(Config{
72-
Profiles: []string{profileOK, profileOKFull},
73-
RootDir: rootDir,
72+
Profiles: []string{profileOK, profileOKFull},
73+
SourceDir: sourceDir,
7474
})
7575
assert.NoError(t, err)
7676
assert.NotEmpty(t, stats3)
7777
assert.Equal(t, 100, StatsCalcTotal(stats3).CoveredPercentage())
7878

7979
// should not have `badge/generate.go` in statistics because it has no statements
8080
stats4, err := GenerateCoverageStats(Config{
81-
Profiles: []string{profileOKNoStatements},
82-
RootDir: rootDir,
81+
Profiles: []string{profileOKNoStatements},
82+
SourceDir: sourceDir,
8383
})
8484
assert.NoError(t, err)
8585
assert.Len(t, stats4, 1)

0 commit comments

Comments
 (0)