github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/step/step_unstash.go (about) 1 package step 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7 "net/url" 8 "path/filepath" 9 "strings" 10 "time" 11 12 "github.com/olli-ai/jx/v2/pkg/cmd/opts/step" 13 14 "github.com/olli-ai/jx/v2/pkg/cmd/helper" 15 16 "github.com/jenkins-x/jx-logging/pkg/log" 17 "github.com/olli-ai/jx/v2/pkg/auth" 18 "github.com/olli-ai/jx/v2/pkg/cloud/buckets" 19 "github.com/olli-ai/jx/v2/pkg/cmd/opts" 20 "github.com/olli-ai/jx/v2/pkg/cmd/templates" 21 "github.com/olli-ai/jx/v2/pkg/gits" 22 "github.com/olli-ai/jx/v2/pkg/util" 23 "github.com/pkg/errors" 24 "github.com/spf13/cobra" 25 ) 26 27 // StepUnstashOptions contains the command line flags 28 type StepUnstashOptions struct { 29 step.StepOptions 30 31 URL string 32 OutDir string 33 Timeout time.Duration 34 } 35 36 var ( 37 stepUnstashLong = templates.LongDesc(` 38 This pipeline step unstashes the files in storage to a local file or the console 39 ` + StorageSupportDescription + helper.SeeAlsoText("jx step stash", "jx edit storage")) 40 41 stepUnstashExample = templates.Examples(` 42 # unstash a file to the reports directory 43 jx step unstash --url s3://mybucket/tests/myOrg/myRepo/mybranch/3/junit.xml -o reports 44 45 # unstash the file to the from GCS to the console 46 jx step unstash -u gs://mybucket/foo/bar/output.log 47 `) 48 ) 49 50 // NewCmdStepUnstash creates the CLI command 51 func NewCmdStepUnstash(commonOpts *opts.CommonOptions) *cobra.Command { 52 options := StepUnstashOptions{ 53 StepOptions: step.StepOptions{ 54 CommonOptions: commonOpts, 55 }, 56 } 57 cmd := &cobra.Command{ 58 Use: "unstash", 59 Short: "Unstashes files generated as part of a pipeline to a local file or directory or displays on the console", 60 Aliases: []string{"collect"}, 61 Long: stepUnstashLong, 62 Example: stepUnstashExample, 63 Run: func(cmd *cobra.Command, args []string) { 64 options.Cmd = cmd 65 options.Args = args 66 err := options.Run() 67 helper.CheckErr(err) 68 }, 69 } 70 cmd.Flags().StringVarP(&options.URL, "url", "u", "", "The fully qualified URL to the file to unstash including the storage host, path and file name") 71 cmd.Flags().StringVarP(&options.OutDir, "output", "o", "", "The output file or directory") 72 cmd.Flags().DurationVarP(&options.Timeout, "timeout", "t", time.Second*30, "The timeout period before we should fail unstashing the entry") 73 return cmd 74 } 75 76 // Run runs the command 77 func (o *StepUnstashOptions) Run() error { 78 authSvc, err := o.GitAuthConfigService() 79 if err != nil { 80 return err 81 } 82 return Unstash(o.URL, o.OutDir, o.Timeout, authSvc) 83 } 84 85 func Unstash(u string, outDir string, timeout time.Duration, authSvc auth.ConfigService) error { 86 if u == "" { 87 // TODO lets guess from the project etc... 88 return util.MissingOption("url") 89 } 90 file := outDir 91 if file != "" { 92 isDir, err := util.DirExists(file) 93 if err != nil { 94 return errors.Wrapf(err, "failed to check if %s is a directory", file) 95 } 96 if isDir { 97 u2, err := url.Parse(u) 98 if err != nil { 99 return errors.Wrapf(err, "failed to parse URL %s", u) 100 } 101 name := u2.Path 102 if name == "" || strings.HasSuffix(name, "/") { 103 name += "output.txt" 104 } 105 file = filepath.Join(file, name) 106 } 107 } 108 109 reader, err := buckets.ReadURL(u, timeout, CreateBucketHTTPFn(authSvc)) 110 if err != nil { 111 return err 112 } 113 defer reader.Close() 114 data, err := ioutil.ReadAll(reader) 115 if err != nil { 116 return err 117 } 118 if file == "" { 119 log.Logger().Infof("%s", string(data)) 120 return nil 121 } 122 err = ioutil.WriteFile(file, data, util.DefaultWritePermissions) 123 if err != nil { 124 return errors.Wrapf(err, "failed to write file %s", file) 125 } 126 log.Logger().Infof("wrote: %s", util.ColorInfo(file)) 127 return nil 128 } 129 130 // CreateBucketHTTPFn creates a function to transform a git URL to add the token and possible header function for accessing a git based bucket 131 func CreateBucketHTTPFn(authSvc auth.ConfigService) func(string) (string, func(*http.Request), error) { 132 return func(urlText string) (string, func(*http.Request), error) { 133 headerFunc := func(*http.Request) { 134 return 135 } 136 if authSvc != nil { 137 gitInfo, err := gits.ParseGitURL(urlText) 138 if err != nil { 139 log.Logger().Warnf("Could not find the git token to access urlText %s due to: %s", urlText, err) 140 } 141 gitServerURL := gitInfo.HostURL() 142 gitKind := "" 143 gitServer := authSvc.Config().GetServer(gitServerURL) 144 if gitServer != nil { 145 gitKind = gitServer.Kind 146 } 147 tokenPrefix := "" 148 auths := authSvc.Config().FindUserAuths(gitServerURL) 149 for _, a := range auths { 150 if a.ApiToken != "" { 151 if gitKind == gits.KindBitBucketServer { 152 tokenPrefix = fmt.Sprintf("%s:%s", a.Username, a.ApiToken) 153 } else if gitKind == gits.KindGitlab { 154 headerFunc = func(r *http.Request) { 155 r.Header.Set("PRIVATE-TOKEN", a.ApiToken) 156 } 157 } else if gitKind == gits.KindGitHub && !gitInfo.IsGitHub() { 158 // If we're on GitHub Enterprise, we need to put the token as a parameter to the URL. 159 tokenPrefix = a.ApiToken 160 } else { 161 tokenPrefix = a.ApiToken 162 } 163 break 164 } 165 } 166 if gitServerURL == "https://raw.githubusercontent.com" { 167 auths := authSvc.Config().FindUserAuths(gits.GitHubURL) 168 for _, a := range auths { 169 if a.ApiToken != "" { 170 tokenPrefix = a.ApiToken 171 break 172 } 173 } 174 } 175 if tokenPrefix != "" { 176 idx := strings.Index(urlText, "://") 177 if idx > 0 { 178 idx += 3 179 urlText = urlText[0:idx] + tokenPrefix + "@" + urlText[idx:] 180 } 181 } 182 } 183 return urlText, headerFunc, nil 184 } 185 }