github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/artifactory/utils/buildutils.go (about) 1 package utils 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/jfrog/jfrog-cli-go/utils/cliutils" 17 "github.com/jfrog/jfrog-client-go/artifactory/buildinfo" 18 "github.com/jfrog/jfrog-client-go/auth" 19 "github.com/jfrog/jfrog-client-go/utils/errorutils" 20 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 21 "github.com/jfrog/jfrog-client-go/utils/log" 22 ) 23 24 const BuildInfoDetails = "details" 25 const BuildTempPath = "jfrog/builds/" 26 27 func GetBuildDir(buildName, buildNumber string) (string, error) { 28 encodedDirName := base64.StdEncoding.EncodeToString([]byte(buildName + "_" + buildNumber)) 29 buildsDir := filepath.Join(cliutils.GetCliPersistentTempDirPath(), BuildTempPath, encodedDirName) 30 err := os.MkdirAll(buildsDir, 0777) 31 if errorutils.CheckError(err) != nil { 32 return "", err 33 } 34 return buildsDir, nil 35 } 36 37 func CreateBuildProperties(buildName, buildNumber string) (string, error) { 38 if buildName == "" || buildNumber == "" { 39 return "", nil 40 } 41 buildGeneralDetails, err := ReadBuildInfoGeneralDetails(buildName, buildNumber) 42 if err != nil { 43 return fmt.Sprintf("build.name=%s;build.number=%s", buildName, buildNumber), err 44 } 45 timestamp := strconv.FormatInt(buildGeneralDetails.Timestamp.UnixNano()/int64(time.Millisecond), 10) 46 return fmt.Sprintf("build.name=%s;build.number=%s;build.timestamp=%s", buildName, buildNumber, timestamp), nil 47 } 48 49 func getPartialsBuildDir(buildName, buildNumber string) (string, error) { 50 buildDir, err := GetBuildDir(buildName, buildNumber) 51 if err != nil { 52 return "", err 53 } 54 buildDir = filepath.Join(buildDir, "partials") 55 err = os.MkdirAll(buildDir, 0777) 56 if errorutils.CheckError(err) != nil { 57 return "", err 58 } 59 return buildDir, nil 60 } 61 62 func saveBuildData(action interface{}, buildName, buildNumber string) error { 63 b, err := json.Marshal(&action) 64 if errorutils.CheckError(err) != nil { 65 return err 66 } 67 var content bytes.Buffer 68 err = json.Indent(&content, b, "", " ") 69 if errorutils.CheckError(err) != nil { 70 return err 71 } 72 dirPath, err := getPartialsBuildDir(buildName, buildNumber) 73 if err != nil { 74 return err 75 } 76 log.Debug("Creating temp build file at:", dirPath) 77 tempFile, err := ioutil.TempFile(dirPath, "temp") 78 if err != nil { 79 return err 80 } 81 defer tempFile.Close() 82 _, err = tempFile.Write([]byte(content.String())) 83 return err 84 } 85 86 func SaveBuildInfo(buildName, buildNumber string, buildInfo *buildinfo.BuildInfo) error { 87 b, err := json.Marshal(buildInfo) 88 if errorutils.CheckError(err) != nil { 89 return err 90 } 91 var content bytes.Buffer 92 err = json.Indent(&content, b, "", " ") 93 if errorutils.CheckError(err) != nil { 94 return err 95 } 96 dirPath, err := GetBuildDir(buildName, buildNumber) 97 if err != nil { 98 return err 99 } 100 log.Debug("Creating temp build file at: " + dirPath) 101 tempFile, err := ioutil.TempFile(dirPath, "temp") 102 if errorutils.CheckError(err) != nil { 103 return err 104 } 105 defer tempFile.Close() 106 _, err = tempFile.Write([]byte(content.String())) 107 return errorutils.CheckError(err) 108 } 109 110 func SaveBuildGeneralDetails(buildName, buildNumber string) error { 111 partialsBuildDir, err := getPartialsBuildDir(buildName, buildNumber) 112 if err != nil { 113 return err 114 } 115 log.Debug("Saving build general details at: " + partialsBuildDir) 116 detailsFilePath := filepath.Join(partialsBuildDir, BuildInfoDetails) 117 var exists bool 118 exists, err = fileutils.IsFileExists(detailsFilePath, false) 119 if err != nil { 120 return err 121 } 122 if exists { 123 return nil 124 } 125 meta := buildinfo.General{ 126 Timestamp: time.Now(), 127 } 128 b, err := json.Marshal(&meta) 129 if err != nil { 130 return errorutils.CheckError(err) 131 } 132 var content bytes.Buffer 133 err = json.Indent(&content, b, "", " ") 134 if err != nil { 135 return errorutils.CheckError(err) 136 } 137 err = ioutil.WriteFile(detailsFilePath, []byte(content.String()), 0600) 138 return errorutils.CheckError(err) 139 } 140 141 type populatePartialBuildInfo func(partial *buildinfo.Partial) 142 143 func SavePartialBuildInfo(buildName, buildNumber string, populatePartialBuildInfoFunc populatePartialBuildInfo) error { 144 partialBuildInfo := new(buildinfo.Partial) 145 partialBuildInfo.Timestamp = time.Now().UnixNano() / int64(time.Millisecond) 146 populatePartialBuildInfoFunc(partialBuildInfo) 147 return saveBuildData(partialBuildInfo, buildName, buildNumber) 148 } 149 150 func GetGeneratedBuildsInfo(buildName, buildNumber string) ([]*buildinfo.BuildInfo, error) { 151 buildDir, err := GetBuildDir(buildName, buildNumber) 152 if err != nil { 153 return nil, err 154 } 155 buildFiles, err := fileutils.ListFiles(buildDir, false) 156 if err != nil { 157 return nil, err 158 } 159 160 var generatedBuildsInfo []*buildinfo.BuildInfo 161 for _, buildFile := range buildFiles { 162 dir, err := fileutils.IsDirExists(buildFile, false) 163 if err != nil { 164 return nil, err 165 } 166 if dir { 167 continue 168 } 169 content, err := fileutils.ReadFile(buildFile) 170 if err != nil { 171 return nil, err 172 } 173 buildInfo := new(buildinfo.BuildInfo) 174 json.Unmarshal(content, &buildInfo) 175 generatedBuildsInfo = append(generatedBuildsInfo, buildInfo) 176 } 177 return generatedBuildsInfo, nil 178 } 179 180 func ReadPartialBuildInfoFiles(buildName, buildNumber string) (buildinfo.Partials, error) { 181 var partials buildinfo.Partials 182 partialsBuildDir, err := getPartialsBuildDir(buildName, buildNumber) 183 if err != nil { 184 return nil, err 185 } 186 buildFiles, err := fileutils.ListFiles(partialsBuildDir, false) 187 if err != nil { 188 return nil, err 189 } 190 for _, buildFile := range buildFiles { 191 dir, err := fileutils.IsDirExists(buildFile, false) 192 if err != nil { 193 return nil, err 194 } 195 if dir { 196 continue 197 } 198 if strings.HasSuffix(buildFile, BuildInfoDetails) { 199 continue 200 } 201 content, err := fileutils.ReadFile(buildFile) 202 if err != nil { 203 return nil, err 204 } 205 partial := new(buildinfo.Partial) 206 json.Unmarshal(content, &partial) 207 partials = append(partials, partial) 208 } 209 210 return partials, nil 211 } 212 213 func ReadBuildInfoGeneralDetails(buildName, buildNumber string) (*buildinfo.General, error) { 214 partialsBuildDir, err := getPartialsBuildDir(buildName, buildNumber) 215 if err != nil { 216 return nil, err 217 } 218 generalDetailsFilePath := filepath.Join(partialsBuildDir, BuildInfoDetails) 219 content, err := fileutils.ReadFile(generalDetailsFilePath) 220 if err != nil { 221 return nil, err 222 } 223 details := new(buildinfo.General) 224 json.Unmarshal(content, &details) 225 return details, nil 226 } 227 228 func RemoveBuildDir(buildName, buildNumber string) error { 229 tempDirPath, err := GetBuildDir(buildName, buildNumber) 230 if err != nil { 231 return err 232 } 233 exists, err := fileutils.IsDirExists(tempDirPath, false) 234 if err != nil { 235 return err 236 } 237 if exists { 238 return errorutils.CheckError(os.RemoveAll(tempDirPath)) 239 } 240 return nil 241 } 242 243 type BuildInfoConfiguration struct { 244 artDetails auth.CommonDetails 245 DryRun bool 246 EnvInclude string 247 EnvExclude string 248 } 249 250 func (config *BuildInfoConfiguration) GetArtifactoryDetails() auth.CommonDetails { 251 return config.artDetails 252 } 253 254 func (config *BuildInfoConfiguration) SetArtifactoryDetails(art auth.CommonDetails) { 255 config.artDetails = art 256 } 257 258 func (config *BuildInfoConfiguration) IsDryRun() bool { 259 return config.DryRun 260 } 261 262 type BuildConfiguration struct { 263 BuildName string 264 BuildNumber string 265 Module string 266 } 267 268 func ValidateBuildAndModuleParams(buildConfig *BuildConfiguration) error { 269 if (buildConfig.BuildName == "" && buildConfig.BuildNumber != "") || (buildConfig.BuildName != "" && buildConfig.BuildNumber == "") { 270 return errors.New("the build-name and build-number options cannot be provided separately") 271 } 272 if buildConfig.Module != "" && buildConfig.BuildName == "" && buildConfig.BuildNumber == "" { 273 return errors.New("the build-name and build-number options are mandatory when the module option is provided") 274 } 275 return nil 276 }