github.com/xgoffin/jenkins-library@v1.154.0/cmd/integrationArtifactDownload.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "mime" 8 "net/http" 9 "os" 10 "path/filepath" 11 12 "github.com/SAP/jenkins-library/pkg/command" 13 "github.com/SAP/jenkins-library/pkg/cpi" 14 piperhttp "github.com/SAP/jenkins-library/pkg/http" 15 "github.com/SAP/jenkins-library/pkg/log" 16 "github.com/SAP/jenkins-library/pkg/telemetry" 17 "github.com/pkg/errors" 18 ) 19 20 type integrationArtifactDownloadUtils interface { 21 command.ExecRunner 22 23 // Add more methods here, or embed additional interfaces, or remove/replace as required. 24 // The integrationArtifactDownloadUtils interface should be descriptive of your runtime dependencies, 25 // i.e. include everything you need to be able to mock in tests. 26 // Unit tests shall be executable in parallel (not depend on global state), and don't (re-)test dependencies. 27 } 28 29 type integrationArtifactDownloadUtilsBundle struct { 30 *command.Command 31 32 // Embed more structs as necessary to implement methods or interfaces you add to integrationArtifactDownloadUtils. 33 // Structs embedded in this way must each have a unique set of methods attached. 34 // If there is no struct which implements the method you need, attach the method to 35 // integrationArtifactDownloadUtilsBundle and forward to the implementation of the dependency. 36 } 37 38 func newIntegrationArtifactDownloadUtils() integrationArtifactDownloadUtils { 39 utils := integrationArtifactDownloadUtilsBundle{ 40 Command: &command.Command{}, 41 } 42 // Reroute command output to logging framework 43 utils.Stdout(log.Writer()) 44 utils.Stderr(log.Writer()) 45 return &utils 46 } 47 48 func integrationArtifactDownload(config integrationArtifactDownloadOptions, telemetryData *telemetry.CustomData) { 49 // Utils can be used wherever the command.ExecRunner interface is expected. 50 // It can also be used for example as a mavenExecRunner. 51 httpClient := &piperhttp.Client{} 52 53 // For HTTP calls import piperhttp "github.com/SAP/jenkins-library/pkg/http" 54 // and use a &piperhttp.Client{} in a custom system 55 // Example: step checkmarxExecuteScan.go 56 57 // Error situations should be bubbled up until they reach the line below which will then stop execution 58 // through the log.Entry().Fatal() call leading to an os.Exit(1) in the end. 59 err := runIntegrationArtifactDownload(&config, telemetryData, httpClient) 60 if err != nil { 61 log.Entry().WithError(err).Fatal("step execution failed") 62 } 63 } 64 65 func runIntegrationArtifactDownload(config *integrationArtifactDownloadOptions, telemetryData *telemetry.CustomData, httpClient piperhttp.Sender) error { 66 clientOptions := piperhttp.ClientOptions{} 67 header := make(http.Header) 68 header.Add("Accept", "application/zip") 69 serviceKey, err := cpi.ReadCpiServiceKey(config.APIServiceKey) 70 if err != nil { 71 return err 72 } 73 downloadArtifactURL := fmt.Sprintf("%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')/$value", serviceKey.OAuth.Host, config.IntegrationFlowID, config.IntegrationFlowVersion) 74 tokenParameters := cpi.TokenParameters{TokenURL: serviceKey.OAuth.OAuthTokenProviderURL, Username: serviceKey.OAuth.ClientID, Password: serviceKey.OAuth.ClientSecret, Client: httpClient} 75 token, err := cpi.CommonUtils.GetBearerToken(tokenParameters) 76 if err != nil { 77 return errors.Wrap(err, "failed to fetch Bearer Token") 78 } 79 clientOptions.Token = fmt.Sprintf("Bearer %s", token) 80 httpClient.SetOptions(clientOptions) 81 httpMethod := "GET" 82 downloadResp, httpErr := httpClient.SendRequest(httpMethod, downloadArtifactURL, nil, header, nil) 83 if httpErr != nil { 84 return errors.Wrapf(httpErr, "HTTP %v request to %v failed with error", httpMethod, downloadArtifactURL) 85 } 86 if downloadResp == nil { 87 return errors.Errorf("did not retrieve a HTTP response: %v", httpErr) 88 } 89 contentDisposition := downloadResp.Header.Get("Content-Disposition") 90 disposition, params, err := mime.ParseMediaType(contentDisposition) 91 if err != nil { 92 return errors.Wrapf(err, "failed to read filename from http response headers, Content-Disposition "+disposition) 93 } 94 filename := params["filename"] 95 96 if downloadResp != nil && downloadResp.Body != nil { 97 defer downloadResp.Body.Close() 98 } 99 100 if downloadResp.StatusCode == 200 { 101 workspaceRelativePath := config.DownloadPath 102 err = os.MkdirAll(workspaceRelativePath, 0755) 103 if err != nil { 104 return errors.Wrapf(err, "Failed to create workspace directory") 105 } 106 zipFileName := filepath.Join(workspaceRelativePath, filename) 107 file, err := os.Create(zipFileName) 108 if err != nil { 109 return errors.Wrapf(err, "Failed to create integration flow artifact file") 110 } 111 io.Copy(file, downloadResp.Body) 112 return nil 113 } 114 responseBody, readErr := ioutil.ReadAll(downloadResp.Body) 115 116 if readErr != nil { 117 return errors.Wrapf(readErr, "HTTP response body could not be read, Response status code : %v", downloadResp.StatusCode) 118 } 119 120 log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code : %v", string(responseBody), downloadResp.StatusCode) 121 return errors.Errorf("Integration Flow artifact download failed, Response Status code: %v", downloadResp.StatusCode) 122 }