Skip to content

Commit bae3f57

Browse files
feat: [CI-4372]: add dotnet support (#33741)
* [CI-4372]: add dotnet support * [CI-3708]: add dotnet runner * [CI-3708]: add dotnet runner * [CI-3708]: add dotnet runner * [CI-4372]: add dotnet support * [CI-4372]: add dotnet support * [CI-4372]: add dotnet support * [CI-4372]: add dotnet support * [CI-4372]: add dotnet support * [CI-4372]: add dotnet support * [CI-4372]: add dotnet support * [CI-4372]: fix tests * [CI-4372]: fix tests * [CI-4372]: fix tests * [CI-4372]: fix tests * [CI-4372]: fix tests * [CI-4372]: fix go build
1 parent 1a149e5 commit bae3f57

File tree

15 files changed

+643
-52
lines changed

15 files changed

+643
-52
lines changed

.github/workflows/go_build.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
gobuild:
1313
if: contains(github.event.pull_request.labels.*.name, 'go') || contains(github.event.pull_request.labels.*.name, 'gojava')
1414
name: Go Build
15-
runs-on: ubuntu-18.04
15+
runs-on: ubuntu-22.04
1616
steps:
1717
- name: Checkout code
1818
uses: actions/checkout@v2
@@ -62,5 +62,5 @@ jobs:
6262
echo $PATH
6363
echo $GOPATH
6464
echo "Adding gocovmerge package... "
65-
go get -u github.com/wadey/gocovmerge
65+
go install github.com/wadey/gocovmerge@latest
6666
tools/go/generate_coverage.sh func

product/ci/addon/go.mod

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
github.com/ghodss/yaml v1.0.0
1818
github.com/go-critic/go-critic v0.4.3 // indirect
1919
github.com/go-toolsmith/typep v1.0.2 // indirect
20-
github.com/golang/mock v1.4.4
20+
github.com/golang/mock v1.6.0
2121
github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d // indirect
2222
github.com/golangci/misspell v0.3.5 // indirect
2323
github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039 // indirect
@@ -27,6 +27,9 @@ require (
2727
github.com/goreleaser/nfpm v1.3.0 // indirect
2828
github.com/gostaticanalysis/analysisutil v0.0.3 // indirect
2929
github.com/grpc-ecosystem/go-grpc-middleware v1.2.1
30+
github.com/harness/harness-core v0.0.0-20220210161509-69d6cb167b7a
31+
github.com/harness/harness-core/commons/go/lib v0.0.0-20220222141117-7659b7eca599
32+
github.com/harness/harness-core/product/ci/engine v0.0.0-20220526003445-374c61227e45
3033
github.com/hashicorp/go-retryablehttp v0.6.6 // indirect
3134
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
3235
github.com/mattn/go-colorable v0.1.6 // indirect
@@ -41,20 +44,16 @@ require (
4144
github.com/spf13/cast v1.3.1 // indirect
4245
github.com/spf13/jwalterweatherman v1.1.0 // indirect
4346
github.com/spf13/viper v1.7.0 // indirect
44-
github.com/stretchr/testify v1.6.1
47+
github.com/stretchr/testify v1.7.0
4548
github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b // indirect
4649
github.com/tetafro/godot v0.4.2 // indirect
4750
github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94 // indirect
4851
github.com/tj/assert v0.0.0-20171129193455-018094318fb0
4952
github.com/vdemeester/k8s-pkg-credentialprovider v1.18.1-0.20201019120933-f1d16962a4db
50-
github.com/harness/harness-core v0.0.0-20220210161509-69d6cb167b7a
51-
github.com/harness/harness-core/commons/go/lib v0.0.0-20220222141117-7659b7eca599
52-
github.com/harness/harness-core/product/ci/engine v0.0.0-20220222141117-7659b7eca599
5353
github.com/xanzy/go-gitlab v0.32.0 // indirect
5454
go.uber.org/zap v1.16.0
55-
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
56-
google.golang.org/api v0.25.0 // indirect
57-
google.golang.org/grpc v1.32.0
55+
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d
56+
google.golang.org/grpc v1.43.0
5857
gopkg.in/ini.v1 v1.56.0 // indirect
5958
honnef.co/go/tools v0.0.1-2020.1.5 // indirect
6059
k8s.io/api v0.20.1

product/ci/addon/go.sum

Lines changed: 237 additions & 5 deletions
Large diffs are not rendered by default.

product/ci/addon/tasks/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ go_library(
2929
"//product/ci/engine/consts",
3030
"//product/ci/engine/grpc/client",
3131
"//product/ci/engine/proto",
32+
"//product/ci/ti-service/client",
3233
"//product/ci/ti-service/types",
3334
"@com_github_ghodss_yaml//:yaml",
3435
"@com_github_grpc_ecosystem_go_grpc_middleware//retry",

product/ci/addon/tasks/runtests.go

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var (
4242
collectTestReportsFn = collectTestReports
4343
runCmdFn = runCmd
4444
isManualFn = external.IsManualExecution
45+
installAgentFn = installAgents
4546
getWorkspace = external.GetWrkspcPath
4647
)
4748

@@ -69,7 +70,10 @@ type runTestsTask struct {
6970
language string // language of codebase
7071
buildTool string // buildTool used for codebase
7172
packages string // Packages ti will generate callgraph for
73+
namespaces string // Namespaces TI will generate callgraph for, similar to package
7274
annotations string // Annotations to identify tests for instrumentation
75+
buildEnvironment string // Dotnet build environment
76+
frameworkVersion string // Dotnet framework version
7377
runOnlySelectedTests bool // Flag to be used for disabling testIntelligence and running all tests
7478
envVarOutputs []string
7579
environment map[string]string
@@ -112,6 +116,8 @@ func NewRunTestsTask(step *pb.UnitStep, tmpFilePath string, log *zap.SugaredLogg
112116
runOnlySelectedTests: r.GetRunOnlySelectedTests(),
113117
envVarOutputs: r.GetEnvVarOutputs(),
114118
environment: r.GetEnvironment(),
119+
buildEnvironment: r.GetBuildEnvironment(),
120+
frameworkVersion: r.GetFrameworkVersion(),
115121
cmdContextFactory: exec.OsCommandContextGracefulWithLog(log),
116122
logMetrics: logMetrics,
117123
log: log,
@@ -216,6 +222,55 @@ instrPackages: %s`, dir, r.packages)
216222
return iniFile, nil
217223
}
218224

225+
/*
226+
Creates config.yaml file for .NET agent to consume and returns the path to config.yaml file on successful creation.
227+
Args:
228+
None
229+
Returns:
230+
configPath (string): Path to the config.yaml file. Empty string on errors.
231+
err (error): Error if there's one, nil otherwise.
232+
*/
233+
func (r *runTestsTask) createDotNetConfigFile() (string, error) {
234+
// Create config file
235+
dir := fmt.Sprintf(outDir, r.tmpFilePath)
236+
err := r.fs.MkdirAll(dir, os.ModePerm)
237+
if err != nil {
238+
r.log.Errorw(fmt.Sprintf("could not create nested directory %s", dir), zap.Error(err))
239+
return "", err
240+
}
241+
242+
if r.namespaces == "" {
243+
r.log.Errorw("Dotnet does not support auto detect namespaces", zap.Error(err))
244+
}
245+
var data string
246+
var outputFile string
247+
248+
outputFile = fmt.Sprintf("%s/config.yaml", r.tmpFilePath)
249+
namespaceArray := strings.Split(r.namespaces, ",")
250+
for idx, s := range namespaceArray {
251+
namespaceArray[idx] = fmt.Sprintf("'%s'", s)
252+
}
253+
data = fmt.Sprintf(`outDir: '%s'
254+
logLevel: 0
255+
writeTo: [COVERAGE_JSON]
256+
instrPackages: [%s]`, dir, strings.Join(namespaceArray, ","))
257+
258+
r.log.Infow(fmt.Sprintf("attempting to write %s to %s", data, outputFile))
259+
f, err := r.fs.Create(outputFile)
260+
if err != nil {
261+
r.log.Errorw(fmt.Sprintf("could not create file %s", outputFile), zap.Error(err))
262+
return "", err
263+
}
264+
_, err = f.Write([]byte(data))
265+
defer f.Close()
266+
if err != nil {
267+
r.log.Errorw(fmt.Sprintf("could not write %s to file %s", data, outputFile), zap.Error(err))
268+
return "", err
269+
}
270+
// Return path to the config.yaml file
271+
return outputFile, nil
272+
}
273+
219274
func valid(tests []types.RunnableTest) bool {
220275
for _, t := range tests {
221276
if t.Class == "" {
@@ -225,7 +280,7 @@ func valid(tests []types.RunnableTest) bool {
225280
return true
226281
}
227282

228-
func (r *runTestsTask) getCmd(ctx context.Context, outputVarFile string) (string, error) {
283+
func (r *runTestsTask) getCmd(ctx context.Context, agentPath, outputVarFile string) (string, error) {
229284
// Get the tests that need to be run if we are running selected tests
230285
var selection types.SelectTestsResp
231286
var files []types.File
@@ -273,7 +328,9 @@ func (r *runTestsTask) getCmd(ctx context.Context, outputVarFile string) (string
273328
{
274329
switch r.buildTool {
275330
case "dotnet":
276-
runner = csharp.NewDotnetRunner(r.log, r.fs, r.cmdContextFactory)
331+
runner = csharp.NewDotnetRunner(r.log, r.fs, r.cmdContextFactory, agentPath)
332+
case "nunitconsole":
333+
runner = csharp.NewNunitConsoleRunner(r.log, r.fs, r.cmdContextFactory, agentPath)
277334
default:
278335
return "", fmt.Errorf("build tool: %s is not supported for csharp", r.buildTool)
279336
}
@@ -287,12 +344,26 @@ func (r *runTestsTask) getCmd(ctx context.Context, outputVarFile string) (string
287344
outputVarCmd += fmt.Sprintf("\necho %s $%s >> %s", o, o, outputVarFile)
288345
}
289346

290-
// Create the java agent config file
291-
iniFilePath, err := r.createJavaAgentConfigFile(runner)
292-
if err != nil {
293-
return "", err
347+
var iniFilePath, agentArg string
348+
349+
switch r.language {
350+
case "java":
351+
{
352+
// Create the java agent config file
353+
iniFilePath, err = r.createJavaAgentConfigFile(runner)
354+
if err != nil {
355+
return "", err
356+
}
357+
agentArg = fmt.Sprintf(javaAgentArg, iniFilePath)
358+
}
359+
case "csharp":
360+
{
361+
iniFilePath, err = r.createDotNetConfigFile()
362+
if err != nil {
363+
return "", err
364+
}
365+
}
294366
}
295-
agentArg := fmt.Sprintf(javaAgentArg, iniFilePath)
296367

297368
testCmd, err := runner.GetCmd(ctx, selection.Tests, r.args, iniFilePath, isManual, !r.runOnlySelectedTests)
298369
if err != nil {
@@ -316,8 +387,14 @@ func (r *runTestsTask) execute(ctx context.Context, retryCount int32) (map[strin
316387
ctx, cancel := context.WithTimeout(ctx, time.Second*time.Duration(r.timeoutSecs))
317388
defer cancel()
318389

390+
// Install agent artifacts if not present
391+
agentPath, err := installAgentFn(ctx, r.tmpFilePath, r.language, r.buildTool, r.frameworkVersion, r.buildEnvironment, r.log, r.fs)
392+
if err != nil {
393+
return nil, err
394+
}
395+
319396
outputFile := filepath.Join(r.tmpFilePath, fmt.Sprintf("%s%s", r.id, outputEnvSuffix))
320-
cmdToExecute, err := r.getCmd(ctx, outputFile)
397+
cmdToExecute, err := r.getCmd(ctx, agentPath, outputFile)
321398
if err != nil {
322399
r.log.Errorw("could not create run command", zap.Error(err))
323400
return nil, err

product/ci/addon/tasks/runtests_test.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export HARNESS_JAVA_AGENT=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.
172172
echo x
173173
mvn -am -DharnessArgLine=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.ini -DargLine=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.ini clean test
174174
echo y`
175-
got, err := r.getCmd(ctx, outputFile)
175+
got, err := r.getCmd(ctx, "/tmp/addon/agent", outputFile)
176176
assert.Nil(t, err)
177177
assert.Equal(t, r.runOnlySelectedTests, false) // If no errors, we should run only selected tests
178178
assert.Equal(t, got, want)
@@ -245,7 +245,7 @@ export HARNESS_JAVA_AGENT=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.
245245
echo x
246246
mvn -am -DharnessArgLine=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.ini -DargLine=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.ini clean test
247247
echo y`
248-
got, err := r.getCmd(ctx, outputFile)
248+
got, err := r.getCmd(ctx, "/tmp/addon/agent", outputFile)
249249
assert.Nil(t, err)
250250
assert.Equal(t, r.runOnlySelectedTests, false) // Since selection returns all the tests
251251
assert.Equal(t, got, want)
@@ -313,7 +313,7 @@ export HARNESS_JAVA_AGENT=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.
313313
echo x
314314
mvn -am -DharnessArgLine=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.ini -DargLine=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.ini clean test
315315
echo y`
316-
got, err := r.getCmd(ctx, outputFile)
316+
got, err := r.getCmd(ctx, "/tmp/addon/agent", outputFile)
317317
assert.Nil(t, err)
318318
assert.Equal(t, r.runOnlySelectedTests, false) // Since there was an error in execution
319319
assert.Equal(t, got, want)
@@ -381,7 +381,7 @@ export HARNESS_JAVA_AGENT=-javaagent:/addon/bin/java-agent.jar=/test/tmp/config.
381381
echo x
382382
mvn clean test
383383
echo y`
384-
got, err := r.getCmd(ctx, outputFile)
384+
got, err := r.getCmd(ctx, "/tmp/addon/agent", outputFile)
385385
assert.Nil(t, err)
386386
assert.Equal(t, r.runOnlySelectedTests, false) // Since it's a manual execution
387387
assert.Equal(t, got, want)
@@ -443,7 +443,7 @@ instrPackages: p1, p2, p3`
443443
return false
444444
}
445445

446-
_, err := r.getCmd(ctx, outputFile)
446+
_, err := r.getCmd(ctx, "/tmp/addon/agent", outputFile)
447447
assert.NotNil(t, err)
448448
}
449449

@@ -581,6 +581,14 @@ instrPackages: p1, p2, p3`
581581
return nil
582582
}
583583

584+
oldInstallAgent := installAgentFn
585+
defer func() {
586+
installAgentFn = oldInstallAgent
587+
}()
588+
installAgentFn = func(ctx context.Context, path, language, framework, frameworkVersion, buildEnvironment string, log *zap.SugaredLogger, fs filesystem.FileSystem) (string, error) {
589+
return "", nil
590+
}
591+
584592
_, _, err := r.Run(ctx)
585593
assert.Nil(t, err)
586594
assert.Equal(t, called, 2) // Make sure both CG collection and report collection are called
@@ -693,6 +701,14 @@ instrPackages: p1, p2, p3`
693701
return nil
694702
}
695703

704+
oldInstallAgent := installAgentFn
705+
defer func() {
706+
installAgentFn = oldInstallAgent
707+
}()
708+
installAgentFn = func(ctx context.Context, path, language, framework, frameworkVersion, buildEnvironment string, log *zap.SugaredLogger, fs filesystem.FileSystem) (string, error) {
709+
return "", nil
710+
}
711+
696712
_, _, err := r.Run(ctx)
697713
assert.Equal(t, err, expErr)
698714
assert.Equal(t, called, 2) // makes ure both functions are called even on failure
@@ -802,6 +818,13 @@ instrPackages: p1, p2, p3`
802818
return nil
803819
}
804820

821+
oldInstallAgent := installAgentFn
822+
defer func() {
823+
installAgentFn = oldInstallAgent
824+
}()
825+
installAgentFn = func(ctx context.Context, path, language, framework, frameworkVersion, buildEnvironment string, log *zap.SugaredLogger, fs filesystem.FileSystem) (string, error) {
826+
return "", nil
827+
}
805828
_, _, err := r.Run(ctx)
806829
assert.Equal(t, err, errCg)
807830
}
@@ -910,6 +933,14 @@ instrPackages: p1, p2, p3`
910933
return errReport
911934
}
912935

936+
oldInstallAgent := installAgentFn
937+
defer func() {
938+
installAgentFn = oldInstallAgent
939+
}()
940+
installAgentFn = func(ctx context.Context, path, language, framework, frameworkVersion, buildEnvironment string, log *zap.SugaredLogger, fs filesystem.FileSystem) (string, error) {
941+
return "", nil
942+
}
943+
913944
_, _, err := r.Run(ctx)
914945
assert.Equal(t, err, errReport)
915946
}

0 commit comments

Comments
 (0)