github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/acceptance/config/asset_manager.go (about) 1 //go:build acceptance 2 // +build acceptance 3 4 package config 5 6 import ( 7 "fmt" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "regexp" 12 "testing" 13 14 acceptanceOS "github.com/buildpacks/pack/acceptance/os" 15 "github.com/buildpacks/pack/internal/builder" 16 "github.com/buildpacks/pack/internal/config" 17 "github.com/buildpacks/pack/internal/style" 18 "github.com/buildpacks/pack/pkg/blob" 19 h "github.com/buildpacks/pack/testhelpers" 20 ) 21 22 const ( 23 defaultCompilePackVersion = "0.0.0" 24 ) 25 26 var ( 27 currentPackFixturesDir = filepath.Join("testdata", "pack_fixtures") 28 previousPackFixturesOverridesDir = filepath.Join("testdata", "pack_previous_fixtures_overrides") 29 lifecycleTgzExp = regexp.MustCompile(`lifecycle-v\d+.\d+.\d+(-pre.\d+)?(-rc.\d+)?\+linux.x86-64.tgz`) 30 ) 31 32 type AssetManager struct { 33 packPath string 34 packFixturesPath string 35 previousPackPath string 36 previousPackFixturesPaths []string 37 githubAssetFetcher *GithubAssetFetcher 38 lifecyclePath string 39 lifecycleDescriptor builder.LifecycleDescriptor 40 lifecycleImage string 41 previousLifecyclePath string 42 previousLifecycleDescriptor builder.LifecycleDescriptor 43 previousLifecycleImage string 44 defaultLifecycleDescriptor builder.LifecycleDescriptor 45 testObject *testing.T 46 } 47 48 func ConvergedAssetManager(t *testing.T, assert h.AssertionManager, inputConfig InputConfigurationManager) AssetManager { 49 t.Helper() 50 51 var ( 52 convergedCurrentPackPath string 53 convergedPreviousPackPath string 54 convergedPreviousPackFixturesPaths []string 55 convergedCurrentLifecyclePath string 56 convergedCurrentLifecycleImage string 57 convergedCurrentLifecycleDescriptor builder.LifecycleDescriptor 58 convergedPreviousLifecyclePath string 59 convergedPreviousLifecycleImage string 60 convergedPreviousLifecycleDescriptor builder.LifecycleDescriptor 61 convergedDefaultLifecycleDescriptor builder.LifecycleDescriptor 62 ) 63 64 githubAssetFetcher, err := NewGithubAssetFetcher(t, inputConfig.githubToken) 65 h.AssertNil(t, err) 66 67 assetBuilder := assetManagerBuilder{ 68 testObject: t, 69 assert: assert, 70 inputConfig: inputConfig, 71 githubAssetFetcher: githubAssetFetcher, 72 } 73 74 if inputConfig.combinations.requiresCurrentPack() { 75 convergedCurrentPackPath = assetBuilder.ensureCurrentPack() 76 } 77 78 if inputConfig.combinations.requiresPreviousPack() { 79 convergedPreviousPackPath = assetBuilder.ensurePreviousPack() 80 convergedPreviousPackFixturesPath := assetBuilder.ensurePreviousPackFixtures() 81 82 convergedPreviousPackFixturesPaths = []string{previousPackFixturesOverridesDir, convergedPreviousPackFixturesPath} 83 } 84 85 if inputConfig.combinations.requiresCurrentLifecycle() { 86 convergedCurrentLifecyclePath, convergedCurrentLifecycleImage, convergedCurrentLifecycleDescriptor = assetBuilder.ensureCurrentLifecycle() 87 } 88 89 if inputConfig.combinations.requiresPreviousLifecycle() { 90 convergedPreviousLifecyclePath, convergedPreviousLifecycleImage, convergedPreviousLifecycleDescriptor = assetBuilder.ensurePreviousLifecycle() 91 } 92 93 if inputConfig.combinations.requiresDefaultLifecycle() { 94 convergedDefaultLifecycleDescriptor = assetBuilder.defaultLifecycleDescriptor() 95 } 96 97 return AssetManager{ 98 packPath: convergedCurrentPackPath, 99 packFixturesPath: currentPackFixturesDir, 100 previousPackPath: convergedPreviousPackPath, 101 previousPackFixturesPaths: convergedPreviousPackFixturesPaths, 102 lifecyclePath: convergedCurrentLifecyclePath, 103 lifecycleImage: convergedCurrentLifecycleImage, 104 lifecycleDescriptor: convergedCurrentLifecycleDescriptor, 105 previousLifecyclePath: convergedPreviousLifecyclePath, 106 previousLifecycleImage: convergedPreviousLifecycleImage, 107 previousLifecycleDescriptor: convergedPreviousLifecycleDescriptor, 108 defaultLifecycleDescriptor: convergedDefaultLifecycleDescriptor, 109 testObject: t, 110 } 111 } 112 113 func (a AssetManager) PackPaths(kind ComboValue) (packPath string, packFixturesPaths []string) { 114 a.testObject.Helper() 115 116 switch kind { 117 case Current: 118 packPath = a.packPath 119 packFixturesPaths = []string{a.packFixturesPath} 120 case Previous: 121 packPath = a.previousPackPath 122 packFixturesPaths = a.previousPackFixturesPaths 123 default: 124 a.testObject.Fatalf("pack kind must be current or previous, was %s", kind) 125 } 126 127 return packPath, packFixturesPaths 128 } 129 130 func (a AssetManager) LifecyclePath(kind ComboValue) string { 131 a.testObject.Helper() 132 133 switch kind { 134 case Current: 135 return a.lifecyclePath 136 case Previous: 137 return a.previousLifecyclePath 138 case DefaultKind: 139 return "" 140 } 141 142 a.testObject.Fatalf("lifecycle kind must be previous, current or default was %s", kind) 143 return "" // Unreachable 144 } 145 146 func (a AssetManager) LifecycleDescriptor(kind ComboValue) builder.LifecycleDescriptor { 147 a.testObject.Helper() 148 149 switch kind { 150 case Current: 151 return a.lifecycleDescriptor 152 case Previous: 153 return a.previousLifecycleDescriptor 154 case DefaultKind: 155 return a.defaultLifecycleDescriptor 156 } 157 158 a.testObject.Fatalf("lifecycle kind must be previous, current or default was %s", kind) 159 return builder.LifecycleDescriptor{} // Unreachable 160 } 161 162 func (a AssetManager) LifecycleImage(kind ComboValue) string { 163 a.testObject.Helper() 164 165 switch kind { 166 case Current: 167 return a.lifecycleImage 168 case Previous: 169 return a.previousLifecycleImage 170 case DefaultKind: 171 return fmt.Sprintf("%s:%s", config.DefaultLifecycleImageRepo, a.defaultLifecycleDescriptor.Info.Version) 172 } 173 174 a.testObject.Fatalf("lifecycle kind must be previous, current or default was %s", kind) 175 return "" // Unreachable 176 } 177 178 type assetManagerBuilder struct { 179 testObject *testing.T 180 assert h.AssertionManager 181 inputConfig InputConfigurationManager 182 githubAssetFetcher *GithubAssetFetcher 183 } 184 185 func (b assetManagerBuilder) ensureCurrentPack() string { 186 b.testObject.Helper() 187 188 if b.inputConfig.packPath != "" { 189 return b.inputConfig.packPath 190 } 191 192 compileWithVersion := b.inputConfig.compilePackWithVersion 193 if compileWithVersion == "" { 194 compileWithVersion = defaultCompilePackVersion 195 } 196 197 return b.buildPack(compileWithVersion) 198 } 199 200 func (b assetManagerBuilder) ensurePreviousPack() string { 201 b.testObject.Helper() 202 203 if b.inputConfig.previousPackPath != "" { 204 return b.inputConfig.previousPackPath 205 } 206 207 b.testObject.Logf( 208 "run combinations %+v require %s to be set", 209 b.inputConfig.combinations, 210 style.Symbol(envPreviousPackPath), 211 ) 212 213 version, err := b.githubAssetFetcher.FetchReleaseVersion("buildpacks", "pack", 0) 214 b.assert.Nil(err) 215 216 assetDir, err := b.githubAssetFetcher.FetchReleaseAsset( 217 "buildpacks", 218 "pack", 219 version, 220 acceptanceOS.PackBinaryExp, 221 true, 222 ) 223 b.assert.Nil(err) 224 assetPath := filepath.Join(assetDir, acceptanceOS.PackBinaryName) 225 226 b.testObject.Logf("using %s for previous pack path", assetPath) 227 228 return assetPath 229 } 230 231 func (b assetManagerBuilder) ensurePreviousPackFixtures() string { 232 b.testObject.Helper() 233 234 if b.inputConfig.previousPackFixturesPath != "" { 235 return b.inputConfig.previousPackFixturesPath 236 } 237 238 b.testObject.Logf( 239 "run combinations %+v require %s to be set", 240 b.inputConfig.combinations, 241 style.Symbol(envPreviousPackFixturesPath), 242 ) 243 244 version, err := b.githubAssetFetcher.FetchReleaseVersion("buildpacks", "pack", 0) 245 b.assert.Nil(err) 246 247 sourceDir, err := b.githubAssetFetcher.FetchReleaseSource("buildpacks", "pack", version) 248 b.assert.Nil(err) 249 250 sourceDirFiles, err := os.ReadDir(sourceDir) 251 b.assert.Nil(err) 252 // GitHub source tarballs have a top-level directory whose name includes the current commit sha. 253 innerDir := sourceDirFiles[0].Name() 254 fixturesDir := filepath.Join(sourceDir, innerDir, "acceptance", "testdata", "pack_fixtures") 255 256 b.testObject.Logf("using %s for previous pack fixtures path", fixturesDir) 257 258 return fixturesDir 259 } 260 261 func (b assetManagerBuilder) ensureCurrentLifecycle() (string, string, builder.LifecycleDescriptor) { 262 b.testObject.Helper() 263 264 lifecyclePath := b.inputConfig.lifecyclePath 265 266 if lifecyclePath == "" { 267 b.testObject.Logf( 268 "run combinations %+v require %s to be set", 269 b.inputConfig.combinations, 270 style.Symbol(envLifecyclePath), 271 ) 272 273 lifecyclePath = b.downloadLifecycleRelative(0) 274 275 b.testObject.Logf("using %s for current lifecycle path", lifecyclePath) 276 } 277 278 lifecycle, err := builder.NewLifecycle(blob.NewBlob(lifecyclePath)) 279 b.assert.Nil(err) 280 281 lifecycleImage := b.inputConfig.lifecycleImage 282 283 if lifecycleImage == "" { 284 lifecycleImage = fmt.Sprintf("%s:%s", config.DefaultLifecycleImageRepo, lifecycle.Descriptor().Info.Version) 285 286 b.testObject.Logf("using %s for current lifecycle image", lifecycleImage) 287 } 288 289 return lifecyclePath, lifecycleImage, lifecycle.Descriptor() 290 } 291 292 func (b assetManagerBuilder) ensurePreviousLifecycle() (string, string, builder.LifecycleDescriptor) { 293 b.testObject.Helper() 294 295 previousLifecyclePath := b.inputConfig.previousLifecyclePath 296 297 if previousLifecyclePath == "" { 298 b.testObject.Logf( 299 "run combinations %+v require %s to be set", 300 b.inputConfig.combinations, 301 style.Symbol(envPreviousLifecyclePath), 302 ) 303 304 previousLifecyclePath = b.downloadLifecycleRelative(-1) 305 306 b.testObject.Logf("using %s for previous lifecycle path", previousLifecyclePath) 307 } 308 309 lifecycle, err := builder.NewLifecycle(blob.NewBlob(previousLifecyclePath)) 310 b.assert.Nil(err) 311 312 previousLifecycleImage := b.inputConfig.previousLifecycleImage 313 314 if previousLifecycleImage == "" { 315 previousLifecycleImage = fmt.Sprintf("%s:%s", config.DefaultLifecycleImageRepo, lifecycle.Descriptor().Info.Version) 316 317 b.testObject.Logf("using %s for previous lifecycle image", previousLifecycleImage) 318 } 319 320 return previousLifecyclePath, previousLifecycleImage, lifecycle.Descriptor() 321 } 322 323 func (b assetManagerBuilder) downloadLifecycle(version string) string { 324 path, err := b.githubAssetFetcher.FetchReleaseAsset( 325 "buildpacks", 326 "lifecycle", 327 version, 328 lifecycleTgzExp, 329 false, 330 ) 331 b.assert.Nil(err) 332 333 return path 334 } 335 336 func (b assetManagerBuilder) downloadLifecycleRelative(relativeVersion int) string { 337 b.testObject.Helper() 338 339 version, err := b.githubAssetFetcher.FetchReleaseVersion("buildpacks", "lifecycle", relativeVersion) 340 b.assert.Nil(err) 341 342 return b.downloadLifecycle(version) 343 } 344 345 func (b assetManagerBuilder) buildPack(compileVersion string) string { 346 b.testObject.Helper() 347 348 packTmpDir, err := os.MkdirTemp("", "pack.acceptance.binary.") 349 b.assert.Nil(err) 350 351 packPath := filepath.Join(packTmpDir, acceptanceOS.PackBinaryName) 352 353 cwd, err := os.Getwd() 354 b.assert.Nil(err) 355 356 cmd := exec.Command("go", "build", 357 "-ldflags", fmt.Sprintf("-X 'github.com/buildpacks/pack/cmd.Version=%s'", compileVersion), 358 "-o", packPath, 359 "./cmd/pack", 360 ) 361 if filepath.Base(cwd) == "acceptance" { 362 cmd.Dir = filepath.Dir(cwd) 363 } 364 365 b.testObject.Logf("building pack: [CWD=%s] %s", cmd.Dir, cmd.Args) 366 _, err = cmd.CombinedOutput() 367 b.assert.Nil(err) 368 369 return packPath 370 } 371 372 func (b assetManagerBuilder) defaultLifecycleDescriptor() builder.LifecycleDescriptor { 373 lifecyclePath := b.downloadLifecycle("v" + builder.DefaultLifecycleVersion) 374 375 b.testObject.Logf("using %s for default lifecycle path", lifecyclePath) 376 377 lifecycle, err := builder.NewLifecycle(blob.NewBlob(lifecyclePath)) 378 b.assert.Nil(err) 379 380 return lifecycle.Descriptor() 381 }