You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	golangBuild: update the way of installing golangci-lint (#4145)
* Add the OS agnostic way of installing golangci-lint * Fix * Clean up * Modify unit tests * Rename downloaded archive * Refactor * Expose golangci-lint url as a parameter * Clean up * Rename parameter * Update mock * Fix golangci-lint version
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							74a3133f35
						
					
				
				
					commit
					6a9ade78ff
				
			| @@ -35,8 +35,6 @@ const ( | ||||
| 	golangTestsumPackage        = "gotest.tools/gotestsum@latest" | ||||
| 	golangCycloneDXPackage      = "github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest" | ||||
| 	sbomFilename                = "bom-golang.xml" | ||||
| 	golangciLintURL             = "https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh" | ||||
| 	golangciLintVersion         = "latest" | ||||
| ) | ||||
|  | ||||
| type golangBuildUtils interface { | ||||
| @@ -49,6 +47,7 @@ type golangBuildUtils interface { | ||||
| 	getDockerImageValue(stepName string) (string, error) | ||||
| 	GetExitCode() int | ||||
| 	DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error | ||||
| 	Untar(src string, dest string, stripComponentLevel int) error | ||||
|  | ||||
| 	// Add more methods here, or embed additional interfaces, or remove/replace as required. | ||||
| 	// The golangBuildUtils interface should be descriptive of your runtime dependencies, | ||||
| @@ -78,6 +77,10 @@ func (g *golangBuildUtilsBundle) getDockerImageValue(stepName string) (string, e | ||||
| 	return GetDockerImageValue(stepName) | ||||
| } | ||||
|  | ||||
| func (g *golangBuildUtilsBundle) Untar(src string, dest string, stripComponentLevel int) error { | ||||
| 	return piperutils.Untar(src, dest, stripComponentLevel) | ||||
| } | ||||
|  | ||||
| func newGolangBuildUtils(config golangBuildOptions) golangBuildUtils { | ||||
| 	httpClientOptions := piperhttp.ClientOptions{} | ||||
|  | ||||
| @@ -175,7 +178,7 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD | ||||
| 		goPath := os.Getenv("GOPATH") | ||||
| 		golangciLintDir := filepath.Join(goPath, "bin") | ||||
|  | ||||
| 		if err := retrieveGolangciLint(utils, golangciLintDir); err != nil { | ||||
| 		if err := retrieveGolangciLint(utils, golangciLintDir, config.GolangciLintURL); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| @@ -433,19 +436,14 @@ func reportGolangTestCoverage(config *golangBuildOptions, utils golangBuildUtils | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func retrieveGolangciLint(utils golangBuildUtils, golangciLintDir string) error { | ||||
| 	installationScript := "./install.sh" | ||||
| 	err := utils.DownloadFile(golangciLintURL, installationScript, nil, nil) | ||||
| func retrieveGolangciLint(utils golangBuildUtils, golangciLintDir, golangciLintURL string) error { | ||||
| 	archiveName := "golangci-lint.tar.gz" | ||||
| 	err := utils.DownloadFile(golangciLintURL, archiveName, nil, nil) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to download golangci-lint: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	err = utils.Chmod(installationScript, 0777) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	err = utils.RunExecutable(installationScript, "-b", golangciLintDir, golangciLintVersion) | ||||
| 	err = utils.Untar(archiveName, golangciLintDir, 1) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to install golangci-lint: %w", err) | ||||
| 	} | ||||
| @@ -455,6 +453,7 @@ func retrieveGolangciLint(utils golangBuildUtils, golangciLintDir string) error | ||||
|  | ||||
| func runGolangciLint(utils golangBuildUtils, golangciLintDir string, lintSettings map[string]string) error { | ||||
| 	binaryPath := filepath.Join(golangciLintDir, "golangci-lint") | ||||
|  | ||||
| 	var outputBuffer bytes.Buffer | ||||
| 	utils.Stdout(&outputBuffer) | ||||
| 	err := utils.RunExecutable(binaryPath, "run", "--out-format", lintSettings["reportStyle"]) | ||||
|   | ||||
| @@ -46,6 +46,7 @@ type golangBuildOptions struct { | ||||
| 	PrivateModules               string   `json:"privateModules,omitempty"` | ||||
| 	PrivateModulesGitToken       string   `json:"privateModulesGitToken,omitempty"` | ||||
| 	ArtifactVersion              string   `json:"artifactVersion,omitempty"` | ||||
| 	GolangciLintURL              string   `json:"golangciLintUrl,omitempty"` | ||||
| } | ||||
|  | ||||
| type golangBuildCommonPipelineEnvironment struct { | ||||
| @@ -245,6 +246,7 @@ func addGolangBuildFlags(cmd *cobra.Command, stepConfig *golangBuildOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.PrivateModules, "privateModules", os.Getenv("PIPER_privateModules"), "Tells go which modules shall be considered to be private (by setting [GOPRIVATE](https://pkg.go.dev/cmd/go#hdr-Configuration_for_downloading_non_public_code)).") | ||||
| 	cmd.Flags().StringVar(&stepConfig.PrivateModulesGitToken, "privateModulesGitToken", os.Getenv("PIPER_privateModulesGitToken"), "GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ArtifactVersion, "artifactVersion", os.Getenv("PIPER_artifactVersion"), "Version of the artifact to be built.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.GolangciLintURL, "golangciLintUrl", `https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.1-linux-amd64.tar.gz`, "Specifies the download url of the Golangci-Lint Linux amd64 tar binary file. This can be found at https://github.com/golangci/golangci-lint/releases.") | ||||
|  | ||||
| 	cmd.MarkFlagRequired("targetArchitectures") | ||||
| } | ||||
| @@ -531,6 +533,15 @@ func golangBuildMetadata() config.StepData { | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_artifactVersion"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "golangciLintUrl", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     `https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.1-linux-amd64.tar.gz`, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Containers: []config.Container{ | ||||
|   | ||||
| @@ -27,9 +27,11 @@ type golangBuildMockUtils struct { | ||||
| 	returnFileUploadStatus  int   // expected to be set upfront | ||||
| 	returnFileUploadError   error // expected to be set upfront | ||||
| 	returnFileDownloadError error // expected to be set upfront | ||||
| 	returnFileUntarError    error // expected to be set upfront | ||||
|  | ||||
| 	clientOptions []piperhttp.ClientOptions // set by mock | ||||
| 	fileUploads   map[string]string         // set by mock | ||||
| 	clientOptions  []piperhttp.ClientOptions // set by mock | ||||
| 	fileUploads    map[string]string         // set by mock | ||||
| 	untarFileNames []string | ||||
| } | ||||
|  | ||||
| func (g *golangBuildMockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { | ||||
| @@ -74,6 +76,16 @@ func (g *golangBuildMockUtils) getDockerImageValue(stepName string) (string, err | ||||
| 	return "golang:latest", nil | ||||
| } | ||||
|  | ||||
| func (g *golangBuildMockUtils) Untar(src string, dest string, stripComponentLevel int) error { | ||||
| 	if g.returnFileUntarError != nil { | ||||
| 		return g.returnFileUntarError | ||||
| 	} | ||||
| 	for _, file := range g.untarFileNames { | ||||
| 		g.AddFile(filepath.Join(dest, file), []byte("test content")) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func newGolangBuildTestsUtils() *golangBuildMockUtils { | ||||
| 	utils := golangBuildMockUtils{ | ||||
| 		ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| @@ -290,15 +302,12 @@ go 1.17` | ||||
| 		err := runGolangBuild(&config, &telemetry, utils, &cpe) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		b, err := utils.FileRead("install.sh") | ||||
| 		b, err := utils.FileRead("golangci-lint.tar.gz") | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		assert.Equal(t, []byte("content"), b) | ||||
| 		assert.Equal(t, "./install.sh", utils.Calls[0].Exec) | ||||
| 		assert.Equal(t, []string{"-b", golangciLintDir, golangciLintVersion}, utils.Calls[0].Params) | ||||
| 		assert.Equal(t, binaryPath, utils.Calls[1].Exec) | ||||
| 		assert.Equal(t, []string{"run", "--out-format", "checkstyle"}, utils.Calls[1].Params) | ||||
|  | ||||
| 		assert.Equal(t, binaryPath, utils.Calls[0].Exec) | ||||
| 		assert.Equal(t, []string{"run", "--out-format", "checkstyle"}, utils.Calls[0].Params) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failure - install pre-requisites for testing", func(t *testing.T) { | ||||
| @@ -476,20 +485,16 @@ go 1.17` | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failure - RunLint: retrieveGolangciLint failed", func(t *testing.T) { | ||||
| 		goPath := os.Getenv("GOPATH") | ||||
| 		golangciLintDir := filepath.Join(goPath, "bin") | ||||
|  | ||||
| 		config := golangBuildOptions{ | ||||
| 			RunLint: true, | ||||
| 		} | ||||
|  | ||||
| 		utils := newGolangBuildTestsUtils() | ||||
| 		utils.AddFile("go.mod", []byte(modTestFile)) | ||||
| 		utils.ShouldFailOnCommand = map[string]error{ | ||||
| 			fmt.Sprintf("./install.sh -b %s %s", golangciLintDir, golangciLintVersion): fmt.Errorf("installation err"), | ||||
| 		} | ||||
| 		utils.returnFileDownloadError = fmt.Errorf("downloading error") | ||||
| 		telemetry := telemetry.CustomData{} | ||||
| 		err := runGolangBuild(&config, &telemetry, utils, &cpe) | ||||
| 		assert.EqualError(t, err, "failed to install golangci-lint: installation err") | ||||
| 		assert.EqualError(t, err, "failed to download golangci-lint: downloading error") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failure - RunLint: runGolangciLint failed", func(t *testing.T) { | ||||
| @@ -1023,6 +1028,7 @@ func TestRunGolangciLint(t *testing.T) { | ||||
| 	goPath := os.Getenv("GOPATH") | ||||
| 	golangciLintDir := filepath.Join(goPath, "bin") | ||||
| 	binaryPath := filepath.Join(golangciLintDir, "golangci-lint") | ||||
|  | ||||
| 	lintSettings := map[string]string{ | ||||
| 		"reportStyle":      "checkstyle", | ||||
| 		"reportOutputPath": "golangci-lint-report.xml", | ||||
| @@ -1070,8 +1076,8 @@ func TestRunGolangciLint(t *testing.T) { | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, test := range tt { | ||||
| 		i, test := i, test | ||||
| 	for _, test := range tt { | ||||
| 		test := test | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			t.Parallel() | ||||
| 			utils := newGolangBuildTestsUtils() | ||||
| @@ -1081,8 +1087,8 @@ func TestRunGolangciLint(t *testing.T) { | ||||
| 			err := runGolangciLint(utils, golangciLintDir, lintSettings) | ||||
|  | ||||
| 			if test.expectedErr == nil { | ||||
| 				assert.Equal(t, test.expectedCommand[0], utils.Calls[i].Exec) | ||||
| 				assert.Equal(t, test.expectedCommand[1:], utils.Calls[i].Params) | ||||
| 				assert.Equal(t, test.expectedCommand[0], utils.Calls[0].Exec) | ||||
| 				assert.Equal(t, test.expectedCommand[1:], utils.Calls[0].Params) | ||||
| 			} else { | ||||
| 				assert.EqualError(t, err, test.expectedErr.Error()) | ||||
| 			} | ||||
| @@ -1097,48 +1103,48 @@ func TestRetrieveGolangciLint(t *testing.T) { | ||||
| 	golangciLintDir := filepath.Join(goPath, "bin") | ||||
|  | ||||
| 	tt := []struct { | ||||
| 		name                string | ||||
| 		shouldFailOnCommand map[string]error | ||||
| 		downloadErr         error | ||||
| 		expectedCommand     []string | ||||
| 		expectedErr         error | ||||
| 		name        string | ||||
| 		downloadErr error | ||||
| 		untarErr    error | ||||
| 		expectedErr error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:                "success", | ||||
| 			shouldFailOnCommand: map[string]error{}, | ||||
| 			downloadErr:         nil, | ||||
| 			expectedCommand:     []string{"./install.sh", "-b", golangciLintDir, golangciLintVersion}, | ||||
| 			expectedErr:         nil, | ||||
| 			name: "success", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                "failure - failed to download golangci-lint", | ||||
| 			shouldFailOnCommand: map[string]error{}, | ||||
| 			downloadErr:         fmt.Errorf("download err"), | ||||
| 			expectedCommand:     []string{}, | ||||
| 			expectedErr:         fmt.Errorf("failed to download golangci-lint: download err"), | ||||
| 			name:        "failure - failed to download golangci-lint", | ||||
| 			downloadErr: fmt.Errorf("download err"), | ||||
| 			expectedErr: fmt.Errorf("failed to download golangci-lint: download err"), | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                "failure - failed to install golangci-lint with sh error", | ||||
| 			shouldFailOnCommand: map[string]error{fmt.Sprintf("./install.sh -b %s %s", golangciLintDir, golangciLintVersion): fmt.Errorf("installation err")}, | ||||
| 			expectedCommand:     []string{}, | ||||
| 			expectedErr:         fmt.Errorf("failed to install golangci-lint: installation err"), | ||||
| 			name:        "failure - failed to install golangci-lint", | ||||
| 			untarErr:    fmt.Errorf("retrieve archive err"), | ||||
| 			expectedErr: fmt.Errorf("failed to install golangci-lint: retrieve archive err"), | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, test := range tt { | ||||
| 		i, test := i, test | ||||
| 	for _, test := range tt { | ||||
| 		test := test | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			t.Parallel() | ||||
| 			utils := newGolangBuildTestsUtils() | ||||
| 			utils.ShouldFailOnCommand = test.shouldFailOnCommand | ||||
| 			utils.returnFileDownloadError = test.downloadErr | ||||
| 			err := retrieveGolangciLint(utils, golangciLintDir) | ||||
| 			utils.returnFileUntarError = test.untarErr | ||||
| 			utils.untarFileNames = []string{"golangci-lint"} | ||||
| 			config := golangBuildOptions{ | ||||
| 				GolangciLintURL: "https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.0-darwin-amd64.tar.gz", | ||||
| 			} | ||||
| 			err := retrieveGolangciLint(utils, golangciLintDir, config.GolangciLintURL) | ||||
|  | ||||
| 			if test.expectedErr == nil { | ||||
| 				assert.Equal(t, test.expectedCommand[0], utils.Calls[i].Exec) | ||||
| 				assert.Equal(t, test.expectedCommand[1:], utils.Calls[i].Params) | ||||
| 			} else { | ||||
| 			if test.expectedErr != nil { | ||||
| 				assert.EqualError(t, err, test.expectedErr.Error()) | ||||
| 			} else { | ||||
| 				b, err := utils.ReadFile("golangci-lint.tar.gz") | ||||
| 				assert.NoError(t, err) | ||||
| 				assert.Equal(t, []byte("content"), b) | ||||
| 				b, err = utils.ReadFile(filepath.Join(golangciLintDir, "golangci-lint")) | ||||
| 				assert.NoError(t, err) | ||||
| 				assert.Equal(t, []byte("test content"), b) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
|   | ||||
| @@ -241,6 +241,13 @@ spec: | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: artifactVersion | ||||
|       - name: golangciLintUrl | ||||
|         type: string | ||||
|         description: Specifies the download url of the Golangci-Lint Linux amd64 tar binary file. This can be found at https://github.com/golangci/golangci-lint/releases. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STEPS | ||||
|         default: "https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.1-linux-amd64.tar.gz" | ||||
|   outputs: | ||||
|     resources: | ||||
|       - name: commonPipelineEnvironment | ||||
|   | ||||
		Reference in New Issue
	
	Block a user