github.com/joshdk/godel@v0.0.0-20170529232908-862138a45aee/apps/distgo/cmd/dist/dist_test.go (about) 1 // Copyright 2016 Palantir Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dist_test 16 17 import ( 18 "archive/tar" 19 "compress/gzip" 20 "crypto/sha256" 21 "encoding/hex" 22 "fmt" 23 "io" 24 "io/ioutil" 25 "os" 26 "os/exec" 27 "path" 28 "regexp" 29 "testing" 30 "time" 31 32 "github.com/nmiyake/pkg/dirs" 33 "github.com/palantir/pkg/matcher" 34 "github.com/stretchr/testify/assert" 35 "github.com/stretchr/testify/require" 36 37 "github.com/palantir/godel/apps/distgo/cmd/build" 38 "github.com/palantir/godel/apps/distgo/cmd/dist" 39 "github.com/palantir/godel/apps/distgo/params" 40 "github.com/palantir/godel/apps/distgo/pkg/git" 41 "github.com/palantir/godel/apps/distgo/pkg/git/gittest" 42 "github.com/palantir/godel/apps/distgo/pkg/osarch" 43 ) 44 45 const ( 46 testMain = `package main 47 48 import "fmt" 49 50 var testVersionVar = "defaultVersion" 51 52 func main() { 53 fmt.Println(testVersionVar) 54 } 55 ` 56 expectManifest = `manifest-version: "1.0" 57 product-group: com.test.group 58 product-name: foo 59 product-version: 0.1.0 60 ` 61 expectManifestWithOptionalFields = `manifest-version: "1.0" 62 product-group: com.test.group 63 product-name: foo 64 product-version: 0.1.0 65 product-type: service.v1 66 extensions: 67 bool-ext: true 68 map-ext: 69 hello: world 70 ` 71 ) 72 73 func TestDist(t *testing.T) { 74 tmp, cleanup, err := dirs.TempDir("", "") 75 defer cleanup() 76 require.NoError(t, err) 77 78 for i, currCase := range []struct { 79 name string 80 skip func() bool 81 spec func(projectDir string) params.ProductBuildSpecWithDeps 82 preDistAction func(projectDir string, buildSpec params.ProductBuildSpec) 83 skipBuild bool 84 wantErrorRegexp string 85 validate func(caseNum int, name string, projectDir string) 86 }{ 87 { 88 name: "builds product and creates distribution directory and tgz", 89 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 90 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 91 projectDir, 92 "foo", 93 git.ProjectInfo{ 94 Version: "0.1.0", 95 }, 96 params.Product{ 97 Build: params.Build{ 98 MainPkg: "./.", 99 }, 100 }, 101 params.Project{ 102 GroupID: "com.test.group", 103 }, 104 ), nil) 105 require.NoError(t, err) 106 return specWithDeps 107 }, 108 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 109 gittest.CreateGitTag(t, projectDir, "0.1.0") 110 }, 111 validate: func(caseNum int, name string, projectDir string) { 112 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "deployment", "manifest.yml")) 113 require.NoError(t, err) 114 assert.Equal(t, expectManifest, string(bytes), "Case %d: %s", caseNum, name) 115 116 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0.sls.tgz")) 117 require.NoError(t, err) 118 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 119 120 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", "init.sh")) 121 require.NoError(t, err) 122 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 123 124 info, err = os.Stat(path.Join(projectDir, "build", "0.1.0", osarch.Current().String(), "foo")) 125 require.NoError(t, err) 126 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 127 128 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", osarch.Current().String(), "foo")) 129 require.NoError(t, err) 130 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 131 }, 132 }, 133 { 134 name: "SLS fails if GroupID is not specified", 135 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 136 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 137 projectDir, 138 "foo", 139 git.ProjectInfo{ 140 Version: "0.1.0", 141 }, 142 params.Product{ 143 Build: params.Build{ 144 MainPkg: "./.", 145 }, 146 }, 147 params.Project{}, 148 ), nil) 149 require.NoError(t, err) 150 return specWithDeps 151 }, 152 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 153 gittest.CreateGitTag(t, projectDir, "0.1.0") 154 }, 155 wantErrorRegexp: "^failed to create manifest for SLS distribution: required properties were missing: group-id$", 156 }, 157 { 158 name: "SLS fails if generated artifact does not conform to SLS specification (missing manifest.yml)", 159 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 160 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 161 projectDir, 162 "foo", 163 git.ProjectInfo{ 164 Version: "0.1.0", 165 }, 166 params.Product{ 167 Build: params.Build{ 168 MainPkg: "./.", 169 }, 170 Dist: []params.Dist{{ 171 Script: "rm $DIST_DIR/deployment/manifest.yml", 172 }}, 173 }, 174 params.Project{ 175 GroupID: "com.test.group", 176 }, 177 ), nil) 178 require.NoError(t, err) 179 return specWithDeps 180 }, 181 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 182 gittest.CreateGitTag(t, projectDir, "0.1.0") 183 }, 184 wantErrorRegexp: `(?s).+distribution directory failed SLS validation: foo-0.1.0/deployment/manifest.yml does not exist$`, 185 }, 186 { 187 name: "SLS fails if configuration.yml contains invalid YML", 188 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 189 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 190 projectDir, 191 "foo", 192 git.ProjectInfo{ 193 Version: "0.1.0", 194 }, 195 params.Product{ 196 Build: params.Build{ 197 MainPkg: "./.", 198 }, 199 Dist: []params.Dist{{ 200 Script: `echo "{788=fads\n\tthis is invalid YML" > $DIST_DIR/deployment/configuration.yml`, 201 }}, 202 }, 203 params.Project{ 204 GroupID: "com.test.group", 205 }, 206 ), nil) 207 require.NoError(t, err) 208 return specWithDeps 209 }, 210 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 211 gittest.CreateGitTag(t, projectDir, "0.1.0") 212 }, 213 wantErrorRegexp: `(?s).+distribution directory failed SLS validation: invalid YML files: \[foo-0.1.0/deployment/configuration.yml\] 214 If these files are known to be correct, exclude them from validation using the SLS YML validation exclude matcher.$`, 215 }, 216 { 217 name: "SLS succeeds with invalid YML if it is excluded by matcher", 218 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 219 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 220 projectDir, 221 "foo", 222 git.ProjectInfo{ 223 Version: "0.1.0", 224 }, 225 params.Product{ 226 Build: params.Build{ 227 MainPkg: "./.", 228 }, 229 Dist: []params.Dist{{ 230 Script: `echo "{788=fads\n\tthis is invalid YML" > $DIST_DIR/deployment/configuration.yml`, 231 Info: ¶ms.SLSDistInfo{ 232 YMLValidationExclude: matcher.Path("deployment"), 233 }, 234 }}, 235 }, 236 params.Project{ 237 GroupID: "com.test.group", 238 }, 239 ), nil) 240 require.NoError(t, err) 241 return specWithDeps 242 }, 243 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 244 gittest.CreateGitTag(t, projectDir, "0.1.0") 245 }, 246 }, 247 { 248 name: "copies executable from build location if it already exists", 249 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 250 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 251 projectDir, 252 "foo", 253 git.ProjectInfo{ 254 Version: "0.1.0", 255 }, 256 params.Product{ 257 Build: params.Build{ 258 MainPkg: "./.", 259 OSArchs: []osarch.OSArch{ 260 { 261 OS: "fake", 262 Arch: "fake", 263 }, 264 }, 265 }, 266 }, 267 params.Project{ 268 GroupID: "com.test.group", 269 }, 270 ), nil) 271 require.NoError(t, err) 272 return specWithDeps 273 }, 274 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 275 gittest.CreateGitTag(t, projectDir, "0.1.0") 276 277 // write fake executable 278 artifactPath, ok := build.ArtifactPaths(buildSpec)[osarch.OSArch{OS: "fake", Arch: "fake"}] 279 require.True(t, ok) 280 281 err := os.MkdirAll(path.Dir(artifactPath), 0755) 282 require.NoError(t, err) 283 284 err = ioutil.WriteFile(artifactPath, []byte("test-content"), 0755) 285 require.NoError(t, err) 286 }, 287 validate: func(caseNum int, name string, projectDir string) { 288 bytes, err := ioutil.ReadFile(path.Join(projectDir, "build", "0.1.0", "fake-fake", "foo")) 289 require.NoError(t, err) 290 assert.Equal(t, "test-content", string(bytes), "Case %d: %s", caseNum, name) 291 }, 292 }, 293 { 294 name: "re-builds executable if source files are newer than executable", 295 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 296 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 297 projectDir, 298 "foo", 299 git.ProjectInfo{ 300 Version: "0.1.0", 301 }, 302 params.Product{ 303 Build: params.Build{ 304 MainPkg: "./.", 305 }, 306 }, 307 params.Project{ 308 GroupID: "com.test.group", 309 }, 310 ), nil) 311 require.NoError(t, err) 312 return specWithDeps 313 }, 314 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 315 gittest.CreateGitTag(t, projectDir, "0.1.0") 316 317 // write fake executable 318 artifactPath, ok := build.ArtifactPaths(buildSpec)[osarch.Current()] 319 require.True(t, ok) 320 321 err := os.MkdirAll(path.Dir(artifactPath), 0755) 322 require.NoError(t, err) 323 err = ioutil.WriteFile(artifactPath, []byte("test-content"), 0755) 324 require.NoError(t, err) 325 326 // write newer version of source file (sleep to ensure timestamp is later) 327 time.Sleep(time.Second) 328 err = ioutil.WriteFile(path.Join(projectDir, "main.go"), []byte(testMain+"\n"), 0644) 329 require.NoError(t, err) 330 }, 331 validate: func(caseNum int, name string, projectDir string) { 332 // content should not be fake executable (build should be executed and overwrite content) 333 bytes, err := ioutil.ReadFile(path.Join(projectDir, "build", "0.1.0", osarch.Current().String(), "foo")) 334 require.NoError(t, err) 335 assert.NotEqual(t, "test-content", string(bytes), "Case %d: %s", caseNum, name) 336 }, 337 }, 338 { 339 name: "copies layout from specified SLS input directory and ignores .gitkeep files", 340 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 341 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 342 projectDir, 343 "foo", 344 git.ProjectInfo{ 345 Version: "0.1.0", 346 }, 347 params.Product{ 348 Build: params.Build{ 349 MainPkg: "./.", 350 }, 351 Dist: []params.Dist{{ 352 InputDir: "sls", 353 }}, 354 Publish: params.Publish{ 355 GroupID: "com.test.group", 356 }, 357 }, 358 params.Project{}, 359 ), nil) 360 require.NoError(t, err) 361 return specWithDeps 362 }, 363 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 364 gittest.CreateGitTag(t, projectDir, "0.1.0") 365 366 // write manifest file that will be overwritten 367 err := os.MkdirAll(path.Join(projectDir, "sls", "deployment"), 0755) 368 require.NoError(t, err) 369 err = ioutil.WriteFile(path.Join(projectDir, "sls", "deployment", "manifest.yml"), []byte("test-content"), 0644) 370 require.NoError(t, err) 371 372 // write .gitkeep file that should be ignored in top-level directory 373 err = ioutil.WriteFile(path.Join(projectDir, "sls", ".gitkeep"), []byte(""), 0644) 374 require.NoError(t, err) 375 376 // write .gitkeep file that should be ignored in child directory 377 err = os.MkdirAll(path.Join(projectDir, "sls", "empty"), 0755) 378 require.NoError(t, err) 379 err = ioutil.WriteFile(path.Join(projectDir, "sls", "empty", ".gitkeep"), []byte(""), 0644) 380 require.NoError(t, err) 381 382 // write test file that will be copied 383 err = os.MkdirAll(path.Join(projectDir, "sls", "other"), 0755) 384 require.NoError(t, err) 385 err = ioutil.WriteFile(path.Join(projectDir, "sls", "other", "testfile"), []byte("test-content"), 0644) 386 require.NoError(t, err) 387 }, 388 validate: func(caseNum int, name string, projectDir string) { 389 // manifest should be overwritten by dist 390 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "deployment", "manifest.yml")) 391 require.NoError(t, err) 392 assert.Equal(t, expectManifest, string(bytes), "Case %d: %s", caseNum, name) 393 394 // top-level .gitkeep should not exist 395 fileInfo, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", ".gitkeep")) 396 assert.True(t, os.IsNotExist(err), "Case %d: %s", caseNum, name) 397 398 // empty directory should exist, but .gitkeep should not 399 fileInfo, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "empty")) 400 assert.NoError(t, err, "Case %d: %s", caseNum, name) 401 assert.True(t, fileInfo.IsDir(), "Case %d: %s", caseNum, name) 402 fileInfo, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "empty", ".gitkeep")) 403 assert.True(t, os.IsNotExist(err), "Case %d: %s", caseNum, name) 404 405 // test file should exist 406 bytes, err = ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "other", "testfile")) 407 require.NoError(t, err) 408 assert.Equal(t, "test-content", string(bytes), "Case %d: %s", caseNum, name) 409 }, 410 }, 411 { 412 name: "writes full SLS manifest with optional fields", 413 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 414 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 415 projectDir, 416 "foo", 417 git.ProjectInfo{ 418 Version: "0.1.0", 419 }, 420 params.Product{ 421 Build: params.Build{ 422 MainPkg: "./.", 423 }, 424 Dist: []params.Dist{{ 425 Info: ¶ms.SLSDistInfo{ 426 ProductType: "service.v1", 427 ManifestExtensions: map[string]interface{}{ 428 "bool-ext": true, 429 "map-ext": map[string]string{ 430 "hello": "world", 431 }, 432 }, 433 }, 434 }}, 435 Publish: params.Publish{ 436 GroupID: "com.test.group", 437 }, 438 }, 439 params.Project{}, 440 ), nil) 441 require.NoError(t, err) 442 return specWithDeps 443 }, 444 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 445 gittest.CreateGitTag(t, projectDir, "0.1.0") 446 }, 447 validate: func(caseNum int, name string, projectDir string) { 448 // manifest should be overwritten by dist 449 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "deployment", "manifest.yml")) 450 require.NoError(t, err) 451 assert.Equal(t, expectManifestWithOptionalFields, string(bytes), "Case %d: %s", caseNum, name) 452 }, 453 }, 454 { 455 name: "copies Windows executables", 456 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 457 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 458 projectDir, 459 "foo", 460 git.ProjectInfo{ 461 Version: "0.1.0", 462 }, 463 params.Product{ 464 Build: params.Build{ 465 MainPkg: "./.", 466 OSArchs: []osarch.OSArch{ 467 { 468 OS: "windows", 469 Arch: "amd64", 470 }, 471 }, 472 }, 473 }, 474 params.Project{ 475 GroupID: "com.test.group", 476 }, 477 ), nil) 478 require.NoError(t, err) 479 return specWithDeps 480 }, 481 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 482 gittest.CreateGitTag(t, projectDir, "0.1.0") 483 }, 484 validate: func(caseNum int, name string, projectDir string) { 485 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", "windows-amd64", "foo.exe")) 486 require.NoError(t, err) 487 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 488 }, 489 }, 490 { 491 name: "runs custom dist script", 492 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 493 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 494 projectDir, 495 "foo", 496 git.ProjectInfo{ 497 Version: "0.1.0", 498 }, 499 params.Product{ 500 Build: params.Build{ 501 MainPkg: "./.", 502 }, 503 Dist: []params.Dist{{ 504 Script: "touch $DIST_DIR/test-file.txt", 505 }}, 506 }, 507 params.Project{ 508 GroupID: "com.test.group", 509 }, 510 ), nil) 511 require.NoError(t, err) 512 return specWithDeps 513 }, 514 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 515 gittest.CreateGitTag(t, projectDir, "0.1.0") 516 }, 517 validate: func(caseNum int, name string, projectDir string) { 518 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "test-file.txt")) 519 require.NoError(t, err) 520 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 521 }, 522 }, 523 { 524 name: "supports creating TGZ files that contain long paths", 525 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 526 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 527 projectDir, 528 "foo", 529 git.ProjectInfo{ 530 Version: "0.1.0", 531 }, 532 params.Product{ 533 Build: params.Build{ 534 MainPkg: "./.", 535 }, 536 Dist: []params.Dist{{ 537 Script: ` 538 mkdir -p $DIST_DIR/0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/ 539 touch $DIST_DIR/0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/file.txt`, 540 }}, 541 }, 542 params.Project{ 543 GroupID: "com.test.group", 544 }, 545 ), nil) 546 require.NoError(t, err) 547 return specWithDeps 548 }, 549 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 550 gittest.CreateGitTag(t, projectDir, "0.1.0") 551 }, 552 validate: func(caseNum int, name string, projectDir string) { 553 dst, err := ioutil.TempDir(projectDir, "expandedTGZDir") 554 require.NoError(t, err) 555 556 cmd := exec.Command("tar", "-C", dst, "-xzvf", path.Join(projectDir, "dist", "foo-0.1.0.sls.tgz")) 557 output, err := cmd.CombinedOutput() 558 require.NoError(t, err, "Command %v failed: %v", cmd.Args, string(output)) 559 560 // long file in tgz should be expanded properly 561 _, err = os.Stat(path.Join(dst, "foo-0.1.0", "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/file.txt")) 562 require.NoError(t, err, "Case %d: %s", caseNum, name) 563 564 // stray file should not exist 565 _, err = os.Stat(path.Join(dst, "file.txt")) 566 require.Error(t, err, fmt.Sprintf("Case %d: %s", caseNum, name)) 567 }, 568 }, 569 { 570 name: "custom dist script inherits process environment variables", 571 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 572 err := os.Setenv("DIST_TEST_KEY", "distTestVal") 573 require.NoError(t, err) 574 err = os.Setenv("DIST_DIR", projectDir) 575 require.NoError(t, err) 576 577 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 578 projectDir, 579 "foo", 580 git.ProjectInfo{ 581 Version: "0.1.0", 582 }, 583 params.Product{ 584 Build: params.Build{ 585 MainPkg: "./.", 586 }, 587 Dist: []params.Dist{{ 588 Script: `touch $DIST_DIR/$DIST_TEST_KEY.txt 589 touch $DIST_DIR/product:$PRODUCT 590 touch $DIST_DIR/version:$VERSION 591 touch $DIST_DIR/snapshot:$IS_SNAPSHOT`, 592 }}, 593 }, 594 params.Project{ 595 GroupID: "com.test.group", 596 }, 597 ), nil) 598 require.NoError(t, err) 599 return specWithDeps 600 }, 601 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 602 gittest.CreateGitTag(t, projectDir, "0.1.0") 603 }, 604 validate: func(caseNum int, name string, projectDir string) { 605 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "distTestVal.txt")) 606 require.NoError(t, err) 607 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 608 609 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "product:foo")) 610 require.NoError(t, err) 611 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 612 613 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "version:0.1.0")) 614 require.NoError(t, err) 615 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 616 617 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "snapshot:0")) 618 require.NoError(t, err) 619 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 620 621 err = os.Unsetenv("DIST_TEST_KEY") 622 require.NoError(t, err) 623 }, 624 }, 625 { 626 name: "custom dist script inherits dist script include", 627 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 628 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 629 projectDir, 630 "foo", 631 git.ProjectInfo{ 632 Version: "0.1.0", 633 }, 634 params.Product{ 635 Build: params.Build{ 636 MainPkg: "./.", 637 }, 638 Dist: []params.Dist{{ 639 Script: `touch $DIST_DIR/$VERSION 640 helper_func`, 641 }}, 642 }, 643 params.Project{ 644 DistScriptInclude: `touch $DIST_DIR/foo.txt 645 helper_func() { 646 touch $DIST_DIR/$IS_SNAPSHOT 647 }`, 648 GroupID: "com.test.group", 649 }, 650 ), nil) 651 require.NoError(t, err) 652 return specWithDeps 653 }, 654 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 655 gittest.CreateGitTag(t, projectDir, "0.1.0") 656 }, 657 validate: func(caseNum int, name string, projectDir string) { 658 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "foo.txt")) 659 require.NoError(t, err) 660 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 661 662 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "0.1.0")) 663 require.NoError(t, err) 664 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 665 666 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "0")) 667 require.NoError(t, err) 668 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 669 }, 670 }, 671 { 672 name: "custom dist script include does not run if script is not provided", 673 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 674 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 675 projectDir, 676 "foo", 677 git.ProjectInfo{ 678 Version: "0.1.0", 679 }, 680 params.Product{ 681 Build: params.Build{ 682 MainPkg: "./.", 683 }, 684 }, 685 params.Project{ 686 DistScriptInclude: "touch $DIST_DIR/foo.txt", 687 GroupID: "com.test.group", 688 }, 689 ), nil) 690 require.NoError(t, err) 691 return specWithDeps 692 }, 693 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 694 gittest.CreateGitTag(t, projectDir, "0.1.0") 695 }, 696 validate: func(caseNum int, name string, projectDir string) { 697 _, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "foo.txt")) 698 assert.True(t, os.IsNotExist(err), "Case %d: %s", caseNum, name) 699 }, 700 }, 701 { 702 name: "copies dependent products", 703 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 704 osArchsMap := make(map[osarch.OSArch]bool) 705 osArchsMap[osarch.OSArch{ 706 OS: "darwin", 707 Arch: "amd64", 708 }] = true 709 osArchsMap[osarch.OSArch{ 710 OS: "linux", 711 Arch: "amd64", 712 }] = true 713 osArchsMap[osarch.Current()] = true 714 715 var osArchsSlice []osarch.OSArch 716 for osArch := range osArchsMap { 717 osArchsSlice = append(osArchsSlice, osArch) 718 } 719 720 barSpec := params.NewProductBuildSpec( 721 projectDir, 722 "bar", 723 git.ProjectInfo{ 724 Version: "0.1.0", 725 }, 726 params.Product{ 727 Build: params.Build{ 728 MainPkg: "./.", 729 OSArchs: osArchsSlice, 730 }, 731 }, 732 params.Project{ 733 GroupID: "com.test.group", 734 }, 735 ) 736 737 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 738 projectDir, 739 "foo", 740 git.ProjectInfo{ 741 Version: "0.1.0", 742 }, 743 params.Product{ 744 Build: params.Build{ 745 MainPkg: "./.", 746 }, 747 Dist: []params.Dist{{ 748 InputProducts: []string{ 749 "bar", 750 }, 751 }}, 752 }, 753 params.Project{ 754 GroupID: "com.test.group", 755 }, 756 ), map[string]params.ProductBuildSpec{ 757 "bar": barSpec, 758 }) 759 require.NoError(t, err) 760 return specWithDeps 761 }, 762 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 763 gittest.CreateGitTag(t, projectDir, "0.1.0") 764 }, 765 validate: func(caseNum int, name string, projectDir string) { 766 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", osarch.Current().String(), "foo")) 767 require.NoError(t, err) 768 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 769 770 info, err = os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", osarch.Current().String(), "bar")) 771 require.NoError(t, err) 772 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 773 }, 774 }, 775 { 776 name: "uses custom manifest when provided", 777 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 778 manifestName := "test-manifest.yml" 779 err := ioutil.WriteFile(path.Join(projectDir, manifestName), []byte(`--- 780 manifestVersion: 1.0.0-alpha 781 productGroup: {{.Publish.GroupID}} 782 productName: {{.ProductName}} 783 productVersion: {{.ProductVersion}} 784 daemon: true 785 `), 0644) 786 require.NoError(t, err) 787 788 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 789 projectDir, 790 "foo", 791 git.ProjectInfo{ 792 Version: "0.1.0", 793 }, 794 params.Product{ 795 Build: params.Build{ 796 MainPkg: "./.", 797 }, 798 Dist: []params.Dist{{ 799 Info: ¶ms.SLSDistInfo{ 800 ManifestTemplateFile: manifestName, 801 }, 802 }}, 803 }, 804 params.Project{ 805 GroupID: "com.test.group", 806 }, 807 ), nil) 808 require.NoError(t, err) 809 return specWithDeps 810 }, 811 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 812 gittest.CreateGitTag(t, projectDir, "0.1.0") 813 }, 814 validate: func(caseNum int, name string, projectDir string) { 815 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "deployment", "manifest.yml")) 816 require.NoError(t, err) 817 assert.Equal(t, `--- 818 manifestVersion: 1.0.0-alpha 819 productGroup: com.test.group 820 productName: foo 821 productVersion: 0.1.0 822 daemon: true 823 `, string(bytes), "Case %d: %s", caseNum, name) 824 }, 825 }, 826 { 827 name: "uses custom init.sh when provided", 828 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 829 initShName := "test-init.sh" 830 err := ioutil.WriteFile(path.Join(projectDir, initShName), []byte(`init {{.ProductName}} {{.ProductVersion}} {{.Publish.GroupID}}`), 0644) 831 require.NoError(t, err) 832 833 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 834 projectDir, 835 "foo", 836 git.ProjectInfo{ 837 Version: "0.1.0", 838 }, 839 params.Product{ 840 Build: params.Build{ 841 MainPkg: "./.", 842 }, 843 Dist: []params.Dist{{ 844 Info: ¶ms.SLSDistInfo{ 845 InitShTemplateFile: initShName, 846 }, 847 }}, 848 }, 849 params.Project{ 850 GroupID: "com.test.group", 851 }, 852 ), nil) 853 require.NoError(t, err) 854 return specWithDeps 855 }, 856 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 857 gittest.CreateGitTag(t, projectDir, "0.1.0") 858 }, 859 validate: func(caseNum int, name string, projectDir string) { 860 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", "init.sh")) 861 require.NoError(t, err) 862 assert.Equal(t, `init foo 0.1.0 com.test.group`, string(bytes), "Case %d: %s", caseNum, name) 863 }, 864 }, 865 { 866 name: "properly templatizes init.sh when ServiceArgs is empty", 867 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 868 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 869 projectDir, 870 "foo", 871 git.ProjectInfo{ 872 Version: "0.1.0", 873 }, 874 params.Product{ 875 Build: params.Build{ 876 MainPkg: "./.", 877 }, 878 Dist: []params.Dist{{ 879 Info: ¶ms.SLSDistInfo{}, 880 }}, 881 }, 882 params.Project{ 883 GroupID: "com.test.group", 884 }, 885 ), nil) 886 require.NoError(t, err) 887 return specWithDeps 888 }, 889 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 890 gittest.CreateGitTag(t, projectDir, "0.1.0") 891 }, 892 validate: func(caseNum int, name string, projectDir string) { 893 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", "init.sh")) 894 require.NoError(t, err) 895 assert.Regexp(t, `SERVICE_CMD="\$SERVICE_HOME/service/bin/\$OS_ARCH/\$SERVICE "\n`, string(bytes), "Case %d: %s", caseNum, name) 896 }, 897 }, 898 { 899 name: "properly templatizes init.sh with ServiceArgs", 900 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 901 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 902 projectDir, 903 "foo", 904 git.ProjectInfo{ 905 Version: "0.1.0", 906 }, 907 params.Product{ 908 Build: params.Build{ 909 MainPkg: "./.", 910 }, 911 Dist: []params.Dist{{ 912 Info: ¶ms.SLSDistInfo{ 913 ServiceArgs: "providedArgs arg2", 914 }, 915 }}, 916 }, 917 params.Project{ 918 GroupID: "com.test.group", 919 }, 920 ), nil) 921 require.NoError(t, err) 922 return specWithDeps 923 }, 924 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 925 gittest.CreateGitTag(t, projectDir, "0.1.0") 926 }, 927 validate: func(caseNum int, name string, projectDir string) { 928 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", "init.sh")) 929 require.NoError(t, err) 930 assert.Regexp(t, `SERVICE_CMD="\$SERVICE_HOME/service/bin/\$OS_ARCH/\$SERVICE providedArgs arg2"\n`, string(bytes), "Case %d: %s", caseNum, name) 931 }, 932 }, 933 { 934 name: "properly templatizes init.sh with Reloadable: false", 935 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 936 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 937 projectDir, 938 "foo", 939 git.ProjectInfo{ 940 Version: "0.1.0", 941 }, 942 params.Product{ 943 Build: params.Build{ 944 MainPkg: "./.", 945 }, 946 Dist: []params.Dist{{ 947 Info: ¶ms.SLSDistInfo{}, 948 }}, 949 }, 950 params.Project{ 951 GroupID: "com.test.group", 952 }, 953 ), nil) 954 require.NoError(t, err) 955 return specWithDeps 956 }, 957 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 958 gittest.CreateGitTag(t, projectDir, "0.1.0") 959 }, 960 validate: func(caseNum int, name string, projectDir string) { 961 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", "init.sh")) 962 require.NoError(t, err) 963 assert.Regexp(t, `does not support reload`, string(bytes), "Case %d: %s", caseNum, name) 964 }, 965 }, 966 { 967 name: "properly templatizes init.sh with Reloadable: true", 968 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 969 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 970 projectDir, 971 "foo", 972 git.ProjectInfo{ 973 Version: "0.1.0", 974 }, 975 params.Product{ 976 Build: params.Build{ 977 MainPkg: "./.", 978 }, 979 Dist: []params.Dist{{ 980 Info: ¶ms.SLSDistInfo{ 981 Reloadable: true, 982 }, 983 }}, 984 }, 985 params.Project{ 986 GroupID: "com.test.group", 987 }, 988 ), nil) 989 require.NoError(t, err) 990 return specWithDeps 991 }, 992 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 993 gittest.CreateGitTag(t, projectDir, "0.1.0") 994 }, 995 validate: func(caseNum int, name string, projectDir string) { 996 bytes, err := ioutil.ReadFile(path.Join(projectDir, "dist", "foo-0.1.0", "service", "bin", "init.sh")) 997 require.NoError(t, err) 998 assert.Regexp(t, `Reloading`, string(bytes), "Case %d: %s", caseNum, name) 999 }, 1000 }, 1001 { 1002 name: "creates outputs using bin mode", 1003 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1004 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1005 projectDir, 1006 "foo", 1007 git.ProjectInfo{ 1008 Version: "0.1.0", 1009 }, 1010 params.Product{ 1011 Build: params.Build{ 1012 MainPkg: "./.", 1013 }, 1014 Dist: []params.Dist{{ 1015 Info: ¶ms.BinDistInfo{}, 1016 }}, 1017 }, 1018 params.Project{}, 1019 ), nil) 1020 require.NoError(t, err) 1021 return specWithDeps 1022 }, 1023 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1024 gittest.CreateGitTag(t, projectDir, "0.1.0") 1025 }, 1026 validate: func(caseNum int, name string, projectDir string) { 1027 // bin directory exists in top-level directory 1028 fileInfo, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "bin")) 1029 require.NoError(t, err) 1030 assert.True(t, fileInfo.IsDir(), "Case %d: %s", caseNum, name) 1031 1032 // executable should exist in os-arch directory 1033 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", "bin", osarch.Current().String(), "foo")) 1034 require.NoError(t, err) 1035 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 1036 }, 1037 }, 1038 { 1039 name: "osarch dist produces archive that contains executable for current OS/Arch by default", 1040 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1041 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1042 projectDir, 1043 "foo", 1044 git.ProjectInfo{ 1045 Version: "0.1.0", 1046 }, 1047 params.Product{ 1048 Build: params.Build{ 1049 MainPkg: "./.", 1050 }, 1051 Dist: []params.Dist{{ 1052 Info: ¶ms.OSArchsBinDistInfo{}, 1053 }}, 1054 }, 1055 params.Project{}, 1056 ), nil) 1057 require.NoError(t, err) 1058 return specWithDeps 1059 }, 1060 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1061 gittest.CreateGitTag(t, projectDir, "0.1.0") 1062 }, 1063 validate: func(caseNum int, name string, projectDir string) { 1064 // executable should exist in dist directory 1065 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", osarch.Current().String(), "foo")) 1066 require.NoError(t, err) 1067 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 1068 1069 // tgz should contain executable 1070 tgzFiles, err := pathsInTGZ(path.Join(projectDir, "dist", fmt.Sprintf("foo-0.1.0-%v.tgz", osarch.Current()))) 1071 require.NoError(t, err) 1072 assert.Equal(t, map[string]struct{}{"foo": {}}, tgzFiles) 1073 }, 1074 }, 1075 { 1076 name: "osarch dist produces archive that contains executable", 1077 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1078 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1079 projectDir, 1080 "foo", 1081 git.ProjectInfo{ 1082 Version: "0.1.0", 1083 }, 1084 params.Product{ 1085 Build: params.Build{ 1086 MainPkg: "./.", 1087 }, 1088 Dist: []params.Dist{{ 1089 Info: ¶ms.OSArchsBinDistInfo{ 1090 OSArchs: []osarch.OSArch{ 1091 osarch.Current(), 1092 }, 1093 }, 1094 }}, 1095 }, 1096 params.Project{}, 1097 ), nil) 1098 require.NoError(t, err) 1099 return specWithDeps 1100 }, 1101 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1102 gittest.CreateGitTag(t, projectDir, "0.1.0") 1103 }, 1104 validate: func(caseNum int, name string, projectDir string) { 1105 // executable should exist in dist directory 1106 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0", osarch.Current().String(), "foo")) 1107 require.NoError(t, err) 1108 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 1109 1110 // tgz should contain executable 1111 tgzFiles, err := pathsInTGZ(path.Join(projectDir, "dist", fmt.Sprintf("foo-0.1.0-%v.tgz", osarch.Current()))) 1112 require.NoError(t, err) 1113 assert.Equal(t, map[string]struct{}{"foo": {}}, tgzFiles) 1114 }, 1115 }, 1116 { 1117 name: "osarch dist produces archives that are different", 1118 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1119 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1120 projectDir, 1121 "foo", 1122 git.ProjectInfo{ 1123 Version: "0.1.0", 1124 }, 1125 params.Product{ 1126 Build: params.Build{ 1127 MainPkg: "./.", 1128 OSArchs: []osarch.OSArch{ 1129 { 1130 OS: "darwin", 1131 Arch: "amd64", 1132 }, 1133 { 1134 OS: "linux", 1135 Arch: "amd64", 1136 }, 1137 }, 1138 }, 1139 Dist: []params.Dist{{ 1140 Info: ¶ms.OSArchsBinDistInfo{ 1141 OSArchs: []osarch.OSArch{ 1142 { 1143 OS: "darwin", 1144 Arch: "amd64", 1145 }, 1146 { 1147 OS: "linux", 1148 Arch: "amd64", 1149 }, 1150 }, 1151 }, 1152 }}, 1153 }, 1154 params.Project{}, 1155 ), nil) 1156 require.NoError(t, err) 1157 return specWithDeps 1158 }, 1159 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1160 gittest.CreateGitTag(t, projectDir, "0.1.0") 1161 }, 1162 validate: func(caseNum int, name string, projectDir string) { 1163 getHexChecksum := func(tgzPath string) string { 1164 bytes, err := ioutil.ReadFile(tgzPath) 1165 require.NoError(t, err) 1166 sha256Bytes := sha256.Sum256(bytes) 1167 return hex.EncodeToString(sha256Bytes[:]) 1168 } 1169 1170 darwinChecksum := getHexChecksum(path.Join(projectDir, "dist", "foo-0.1.0-darwin-amd64.tgz")) 1171 linuxChecksum := getHexChecksum(path.Join(projectDir, "dist", "foo-0.1.0-linux-amd64.tgz")) 1172 1173 assert.NotEqual(t, darwinChecksum, linuxChecksum, "checksums should differ") 1174 }, 1175 }, 1176 { 1177 name: "osarch dist fails if OS/Arch specified by dist is not supported by build", 1178 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1179 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1180 projectDir, 1181 "foo", 1182 git.ProjectInfo{ 1183 Version: "0.1.0", 1184 }, 1185 params.Product{ 1186 Build: params.Build{ 1187 MainPkg: "./.", 1188 OSArchs: []osarch.OSArch{ 1189 { 1190 OS: "linux", 1191 Arch: "amd64", 1192 }, 1193 }, 1194 }, 1195 Dist: []params.Dist{{ 1196 Info: ¶ms.OSArchsBinDistInfo{ 1197 OSArchs: []osarch.OSArch{ 1198 { 1199 OS: "darwin", 1200 Arch: "amd64", 1201 }, 1202 }, 1203 }, 1204 }}, 1205 }, 1206 params.Project{}, 1207 ), nil) 1208 require.NoError(t, err) 1209 return specWithDeps 1210 }, 1211 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1212 gittest.CreateGitTag(t, projectDir, "0.1.0") 1213 }, 1214 wantErrorRegexp: regexp.QuoteMeta(`The OS/Arch specified for the distribution of a product must be specified as a build target for the product, but product foo does not specify darwin-amd64 as one of its build targets. Current build targets: [linux-amd64]`), 1215 }, 1216 { 1217 name: "manual dist produces output based on script", 1218 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1219 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1220 projectDir, 1221 "foo", 1222 git.ProjectInfo{ 1223 Version: "0.1.0", 1224 }, 1225 params.Product{ 1226 Build: params.Build{ 1227 Skip: true, 1228 }, 1229 Dist: []params.Dist{{ 1230 Script: ` 1231 echo "test-dist-contents" > "$DIST_DIR/$PRODUCT-$VERSION.tgz" 1232 `, 1233 Info: ¶ms.ManualDistInfo{ 1234 Extension: "tgz", 1235 }, 1236 }}, 1237 }, 1238 params.Project{}, 1239 ), nil) 1240 require.NoError(t, err) 1241 return specWithDeps 1242 }, 1243 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1244 gittest.CreateGitTag(t, projectDir, "0.1.0") 1245 }, 1246 validate: func(caseNum int, name string, projectDir string) { 1247 // output tgz should exist and contain test contents 1248 tgzFile := path.Join(projectDir, "dist", "foo-0.1.0", "foo-0.1.0.tgz") 1249 contents, err := ioutil.ReadFile(tgzFile) 1250 require.NoError(t, err) 1251 assert.Equal(t, "test-dist-contents\n", string(contents)) 1252 1253 // dist output tgz should exist and contain test contents 1254 tgzFile = path.Join(projectDir, "dist", "foo-0.1.0.tgz") 1255 contents, err = ioutil.ReadFile(tgzFile) 1256 require.NoError(t, err) 1257 assert.Equal(t, "test-dist-contents\n", string(contents)) 1258 }, 1259 }, 1260 { 1261 name: "builds rpm", 1262 skip: func() bool { 1263 // Run this case only if both fpm and rpmbuild are available 1264 _, fpmErr := exec.LookPath("fpm") 1265 _, rpmbuildErr := exec.LookPath("rpmbuild") 1266 return fpmErr != nil || rpmbuildErr != nil 1267 }, 1268 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1269 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1270 projectDir, 1271 "foo", 1272 git.ProjectInfo{ 1273 Version: "0.1.0", 1274 }, 1275 params.Product{ 1276 Build: params.Build{ 1277 MainPkg: "./.", 1278 OSArchs: []osarch.OSArch{ 1279 { 1280 OS: "linux", 1281 Arch: "amd64", 1282 }, 1283 }, 1284 }, 1285 Dist: []params.Dist{{ 1286 InputDir: "root", 1287 Info: ¶ms.RPMDistInfo{ 1288 ConfigFiles: []string{"/usr/lib/systemd/system/orchestrator.service"}, 1289 BeforeInstallScript: "" + 1290 "/usr/bin/getent group orchestrator || /usr/sbin/groupadd \\\n" + 1291 " -g 380 orchestrator\n" + 1292 "/usr/bin/getent passwd orchestrator || /usr/sbin/useradd -r \\\n" + 1293 " -d /var/lib/orchestrator -g orchestrator -u 380 -m \\\n" + 1294 " -s /sbin/nologin orchestrator\n", 1295 AfterInstallScript: "systemctl daemon-reload\n", 1296 AfterRemoveScript: "systemctl daemon-reload\n", 1297 }, 1298 }}, 1299 }, 1300 params.Project{ 1301 GroupID: "com.test.group", 1302 }, 1303 ), nil) 1304 require.NoError(t, err) 1305 return specWithDeps 1306 }, 1307 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1308 gittest.CreateGitTag(t, projectDir, "0.1.0") 1309 1310 // write fake systemd config file 1311 err := os.MkdirAll(path.Join(projectDir, "root", "usr", "lib", "systemd", "system"), 0755) 1312 require.NoError(t, err) 1313 1314 err = ioutil.WriteFile(path.Join(projectDir, "root", "usr", "lib", "systemd", "system", "orchestrator.service"), []byte("configured"), 0600) 1315 require.NoError(t, err) 1316 }, 1317 validate: func(caseNum int, name string, projectDir string) { 1318 info, err := os.Stat(path.Join(projectDir, "dist", "foo-0.1.0-1.x86_64.rpm")) 1319 require.NoError(t, err) 1320 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 1321 }, 1322 }, 1323 { 1324 name: "more than one dist", 1325 spec: func(projectDir string) params.ProductBuildSpecWithDeps { 1326 specWithDeps, err := params.NewProductBuildSpecWithDeps(params.NewProductBuildSpec( 1327 projectDir, 1328 "foo", 1329 git.ProjectInfo{ 1330 Version: "0.1.0", 1331 }, 1332 params.Product{ 1333 Build: params.Build{ 1334 MainPkg: "./.", 1335 OSArchs: []osarch.OSArch{ 1336 { 1337 OS: "linux", 1338 Arch: "amd64", 1339 }, 1340 }, 1341 }, 1342 Dist: []params.Dist{{ 1343 Info: ¶ms.BinDistInfo{}, 1344 OutputDir: "dist/bin", 1345 Script: "touch $DIST_DIR/dist-1.txt", 1346 }, { 1347 Info: ¶ms.RPMDistInfo{}, 1348 OutputDir: "dist/rpm", 1349 Script: "touch $DIST_DIR/dist-2.txt", 1350 }}, 1351 }, 1352 params.Project{ 1353 GroupID: "com.test.group", 1354 }, 1355 ), nil) 1356 require.NoError(t, err) 1357 return specWithDeps 1358 }, 1359 preDistAction: func(projectDir string, buildSpec params.ProductBuildSpec) { 1360 gittest.CreateGitTag(t, projectDir, "0.1.0") 1361 }, 1362 validate: func(caseNum int, name string, projectDir string) { 1363 info, err := os.Stat(path.Join(projectDir, "dist", "bin", "foo-0.1.0", "dist-1.txt")) 1364 require.NoError(t, err) 1365 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 1366 1367 info, err = os.Stat(path.Join(projectDir, "dist", "rpm", "foo-0.1.0", "dist-2.txt")) 1368 require.NoError(t, err) 1369 assert.False(t, info.IsDir(), "Case %d: %s", caseNum, name) 1370 }, 1371 }, 1372 } { 1373 if currCase.skip != nil && currCase.skip() { 1374 fmt.Fprintln(os.Stderr, "SKIPPING CASE", i) 1375 continue 1376 } 1377 1378 currTmpDir, err := ioutil.TempDir(tmp, "") 1379 require.NoError(t, err, "Case %d: %s", i, currCase.name) 1380 1381 gittest.InitGitDir(t, currTmpDir) 1382 err = ioutil.WriteFile(path.Join(currTmpDir, "main.go"), []byte(testMain), 0644) 1383 require.NoError(t, err, "Case %d: %s", i, currCase.name) 1384 gittest.CommitAllFiles(t, currTmpDir, "Commit") 1385 1386 if currCase.preDistAction != nil { 1387 currCase.preDistAction(currTmpDir, currCase.spec(currTmpDir).Spec) 1388 } 1389 1390 currSpecWithDeps := currCase.spec(currTmpDir) 1391 if !currCase.skipBuild { 1392 err = build.Run(build.RequiresBuild(currSpecWithDeps, nil).Specs(), nil, build.Context{}, ioutil.Discard) 1393 require.NoError(t, err, "Case %d: %s", i, currCase.name) 1394 } 1395 1396 err = dist.Run(currSpecWithDeps, ioutil.Discard) 1397 if currCase.wantErrorRegexp == "" { 1398 require.NoError(t, err, "Case %d: %s", i, currCase.name) 1399 } else { 1400 require.Error(t, err, fmt.Sprintf("Case %d: %s", i, currCase.name)) 1401 assert.Regexp(t, regexp.MustCompile(currCase.wantErrorRegexp), err.Error(), "Case %d: %s", i, currCase.name) 1402 } 1403 1404 if currCase.validate != nil { 1405 currCase.validate(i, currCase.name, currTmpDir) 1406 } 1407 } 1408 } 1409 1410 func pathsInTGZ(tgzFile string) (rPaths map[string]struct{}, rErr error) { 1411 file, err := os.Open(tgzFile) 1412 if err != nil { 1413 return nil, err 1414 } 1415 defer func() { 1416 if err := file.Close(); err != nil && rErr == nil { 1417 rErr = err 1418 } 1419 }() 1420 1421 gzf, err := gzip.NewReader(file) 1422 if err != nil { 1423 return nil, err 1424 } 1425 1426 tarReader := tar.NewReader(gzf) 1427 dirs := make(map[string]struct{}) 1428 for { 1429 header, err := tarReader.Next() 1430 if err == io.EOF { 1431 break 1432 } else if err != nil { 1433 return nil, err 1434 } 1435 1436 switch header.Typeflag { 1437 case tar.TypeReg: 1438 dirs[header.Name] = struct{}{} 1439 default: 1440 } 1441 } 1442 return dirs, nil 1443 }