github.com/triarius/goreleaser@v1.12.5/internal/pipe/archive/archive_test.go (about) 1 package archive 2 3 import ( 4 "archive/tar" 5 "archive/zip" 6 "compress/gzip" 7 "fmt" 8 "io" 9 "os" 10 "path/filepath" 11 "testing" 12 13 "github.com/triarius/goreleaser/internal/artifact" 14 "github.com/triarius/goreleaser/internal/testlib" 15 "github.com/triarius/goreleaser/pkg/archive" 16 "github.com/triarius/goreleaser/pkg/config" 17 "github.com/triarius/goreleaser/pkg/context" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestDescription(t *testing.T) { 22 require.NotEmpty(t, Pipe{}.String()) 23 } 24 25 func createFakeBinary(t *testing.T, dist, arch, bin string) { 26 t.Helper() 27 path := filepath.Join(dist, arch, bin) 28 require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755)) 29 f, err := os.Create(path) 30 require.NoError(t, err) 31 require.NoError(t, f.Close()) 32 } 33 34 func TestRunPipe(t *testing.T) { 35 folder := testlib.Mktmp(t) 36 for _, dets := range []struct { 37 Format string 38 Strip bool 39 }{ 40 { 41 Format: "tar.gz", 42 Strip: true, 43 }, 44 { 45 Format: "tar.gz", 46 Strip: false, 47 }, 48 49 { 50 Format: "zip", 51 Strip: true, 52 }, 53 { 54 Format: "zip", 55 Strip: false, 56 }, 57 } { 58 format := dets.Format 59 name := "archive." + format 60 if dets.Strip { 61 name = "strip_" + name 62 } 63 t.Run(name, func(t *testing.T) { 64 dist := filepath.Join(folder, name+"_dist") 65 require.NoError(t, os.Mkdir(dist, 0o755)) 66 for _, arch := range []string{"darwinamd64v1", "darwinall", "linux386", "linuxarm7", "linuxmipssoftfloat", "linuxamd64v3"} { 67 createFakeBinary(t, dist, arch, "bin/mybin") 68 } 69 createFakeBinary(t, dist, "windowsamd64", "bin/mybin.exe") 70 for _, tt := range []string{"darwin", "linux", "windows"} { 71 f, err := os.Create(filepath.Join(folder, fmt.Sprintf("README.%s.md", tt))) 72 require.NoError(t, err) 73 require.NoError(t, f.Close()) 74 } 75 require.NoError(t, os.MkdirAll(filepath.Join(folder, "foo", "bar", "foobar"), 0o755)) 76 f, err := os.Create(filepath.Join(filepath.Join(folder, "foo", "bar", "foobar", "blah.txt"))) 77 require.NoError(t, err) 78 require.NoError(t, f.Close()) 79 ctx := context.New( 80 config.Project{ 81 Dist: dist, 82 ProjectName: "foobar", 83 Archives: []config.Archive{ 84 { 85 ID: "myid", 86 Builds: []string{"default"}, 87 NameTemplate: defaultNameTemplate, 88 StripParentBinaryFolder: dets.Strip, 89 Files: []config.File{ 90 {Source: "README.{{.Os}}.*"}, 91 {Source: "./foo/**/*"}, 92 }, 93 FormatOverrides: []config.FormatOverride{ 94 { 95 Goos: "windows", 96 Format: "zip", 97 }, 98 }, 99 }, 100 }, 101 }, 102 ) 103 darwinUniversalBinary := &artifact.Artifact{ 104 Goos: "darwin", 105 Goarch: "all", 106 Name: "bin/mybin", 107 Path: filepath.Join(dist, "darwinall", "bin", "mybin"), 108 Type: artifact.UniversalBinary, 109 Extra: map[string]interface{}{ 110 artifact.ExtraBinary: "bin/mybin", 111 artifact.ExtraID: "default", 112 artifact.ExtraReplaces: true, 113 }, 114 } 115 darwinBuild := &artifact.Artifact{ 116 Goos: "darwin", 117 Goarch: "amd64", 118 Goamd64: "v1", 119 Name: "bin/mybin", 120 Path: filepath.Join(dist, "darwinamd64v1", "bin", "mybin"), 121 Type: artifact.Binary, 122 Extra: map[string]interface{}{ 123 artifact.ExtraBinary: "bin/mybin", 124 artifact.ExtraID: "default", 125 }, 126 } 127 linux386Build := &artifact.Artifact{ 128 Goos: "linux", 129 Goarch: "386", 130 Name: "bin/mybin", 131 Path: filepath.Join(dist, "linux386", "bin", "mybin"), 132 Type: artifact.Binary, 133 Extra: map[string]interface{}{ 134 artifact.ExtraBinary: "bin/mybin", 135 artifact.ExtraID: "default", 136 }, 137 } 138 linuxArmBuild := &artifact.Artifact{ 139 Goos: "linux", 140 Goarch: "arm", 141 Goarm: "7", 142 Name: "bin/mybin", 143 Path: filepath.Join(dist, "linuxarm7", "bin", "mybin"), 144 Type: artifact.Binary, 145 Extra: map[string]interface{}{ 146 artifact.ExtraBinary: "bin/mybin", 147 artifact.ExtraID: "default", 148 }, 149 } 150 linuxMipsBuild := &artifact.Artifact{ 151 Goos: "linux", 152 Goarch: "mips", 153 Gomips: "softfloat", 154 Name: "bin/mybin", 155 Path: filepath.Join(dist, "linuxmipssoftfloat", "bin", "mybin"), 156 Type: artifact.Binary, 157 Extra: map[string]interface{}{ 158 artifact.ExtraBinary: "mybin", 159 artifact.ExtraID: "default", 160 }, 161 } 162 windowsBuild := &artifact.Artifact{ 163 Goos: "windows", 164 Goarch: "amd64", 165 Goamd64: "v1", 166 Name: "bin/mybin.exe", 167 Path: filepath.Join(dist, "windowsamd64", "bin", "mybin.exe"), 168 Type: artifact.Binary, 169 Extra: map[string]interface{}{ 170 artifact.ExtraBinary: "mybin", 171 artifact.ExtraExt: ".exe", 172 artifact.ExtraID: "default", 173 }, 174 } 175 linuxAmd64Build := &artifact.Artifact{ 176 Goos: "linux", 177 Goarch: "amd64", 178 Goamd64: "v3", 179 Name: "bin/mybin", 180 Path: filepath.Join(dist, "linuxamd64v3", "bin", "mybin"), 181 Type: artifact.Binary, 182 Extra: map[string]interface{}{ 183 artifact.ExtraBinary: "mybin", 184 artifact.ExtraID: "default", 185 }, 186 } 187 ctx.Artifacts.Add(darwinBuild) 188 ctx.Artifacts.Add(darwinUniversalBinary) 189 ctx.Artifacts.Add(linux386Build) 190 ctx.Artifacts.Add(linuxArmBuild) 191 ctx.Artifacts.Add(linuxMipsBuild) 192 ctx.Artifacts.Add(windowsBuild) 193 ctx.Artifacts.Add(linuxAmd64Build) 194 ctx.Version = "0.0.1" 195 ctx.Git.CurrentTag = "v0.0.1" 196 ctx.Config.Archives[0].Format = format 197 require.NoError(t, Pipe{}.Run(ctx)) 198 archives := ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableArchive)).List() 199 200 for _, arch := range archives { 201 expectBin := "bin/mybin" 202 if arch.Goos == "windows" { 203 expectBin += ".exe" 204 } 205 require.Equal(t, "myid", arch.ID(), "all archives must have the archive ID set") 206 require.Equal(t, []string{expectBin}, artifact.ExtraOr(*arch, artifact.ExtraBinaries, []string{})) 207 require.Equal(t, "", artifact.ExtraOr(*arch, artifact.ExtraBinary, "")) 208 } 209 require.Len(t, archives, 7) 210 // TODO: should verify the artifact fields here too 211 212 expectBin := "bin/mybin" 213 if dets.Strip { 214 expectBin = "mybin" 215 } 216 217 if format == "tar.gz" { 218 // Check archive contents 219 for name, os := range map[string]string{ 220 "foobar_0.0.1_darwin_amd64.tar.gz": "darwin", 221 "foobar_0.0.1_darwin_all.tar.gz": "darwin", 222 "foobar_0.0.1_linux_386.tar.gz": "linux", 223 "foobar_0.0.1_linux_armv7.tar.gz": "linux", 224 "foobar_0.0.1_linux_mips_softfloat.tar.gz": "linux", 225 "foobar_0.0.1_linux_amd64v3.tar.gz": "linux", 226 } { 227 require.Equal( 228 t, 229 []string{ 230 fmt.Sprintf("README.%s.md", os), 231 "foo/bar/foobar/blah.txt", 232 expectBin, 233 }, 234 tarFiles(t, filepath.Join(dist, name)), 235 ) 236 } 237 } 238 if format == "zip" { 239 require.Equal( 240 t, 241 []string{ 242 "README.windows.md", 243 "foo/bar/foobar/blah.txt", 244 expectBin + ".exe", 245 }, 246 zipFiles(t, filepath.Join(dist, "foobar_0.0.1_windows_amd64.zip")), 247 ) 248 } 249 }) 250 } 251 } 252 253 func TestRunPipeDifferentBinaryCount(t *testing.T) { 254 folder := testlib.Mktmp(t) 255 dist := filepath.Join(folder, "dist") 256 require.NoError(t, os.Mkdir(dist, 0o755)) 257 for _, arch := range []string{"darwinamd64", "linuxamd64"} { 258 createFakeBinary(t, dist, arch, "bin/mybin") 259 } 260 createFakeBinary(t, dist, "darwinamd64", "bin/foobar") 261 ctx := context.New(config.Project{ 262 Dist: dist, 263 ProjectName: "foobar", 264 Archives: []config.Archive{ 265 { 266 ID: "myid", 267 Format: "tar.gz", 268 Builds: []string{"default", "foobar"}, 269 NameTemplate: defaultNameTemplate, 270 }, 271 }, 272 }) 273 darwinBuild := &artifact.Artifact{ 274 Goos: "darwin", 275 Goarch: "amd64", 276 Name: "bin/mybin", 277 Path: filepath.Join(dist, "darwinamd64", "bin", "mybin"), 278 Type: artifact.Binary, 279 Extra: map[string]interface{}{ 280 artifact.ExtraBinary: "bin/mybin", 281 artifact.ExtraID: "default", 282 }, 283 } 284 darwinBuild2 := &artifact.Artifact{ 285 Goos: "darwin", 286 Goarch: "amd64", 287 Name: "bin/foobar", 288 Path: filepath.Join(dist, "darwinamd64", "bin", "foobar"), 289 Type: artifact.Binary, 290 Extra: map[string]interface{}{ 291 artifact.ExtraBinary: "bin/foobar", 292 artifact.ExtraID: "foobar", 293 }, 294 } 295 linuxArmBuild := &artifact.Artifact{ 296 Goos: "linux", 297 Goarch: "amd64", 298 Name: "bin/mybin", 299 Path: filepath.Join(dist, "linuxamd64", "bin", "mybin"), 300 Type: artifact.Binary, 301 Extra: map[string]interface{}{ 302 artifact.ExtraBinary: "bin/mybin", 303 artifact.ExtraID: "default", 304 }, 305 } 306 307 ctx.Artifacts.Add(darwinBuild) 308 ctx.Artifacts.Add(darwinBuild2) 309 ctx.Artifacts.Add(linuxArmBuild) 310 ctx.Version = "0.0.1" 311 ctx.Git.CurrentTag = "v0.0.1" 312 313 t.Run("check enabled", func(t *testing.T) { 314 ctx.Config.Archives[0].AllowDifferentBinaryCount = false 315 require.EqualError(t, Pipe{}.Run(ctx), "invalid archive: 0: "+ErrArchiveDifferentBinaryCount.Error()) 316 }) 317 318 t.Run("check disabled", func(t *testing.T) { 319 ctx.Config.Archives[0].AllowDifferentBinaryCount = true 320 require.NoError(t, Pipe{}.Run(ctx)) 321 }) 322 } 323 324 func TestRunPipeNoBinaries(t *testing.T) { 325 folder := testlib.Mktmp(t) 326 dist := filepath.Join(folder, "dist") 327 require.NoError(t, os.Mkdir(dist, 0o755)) 328 ctx := context.New(config.Project{ 329 Dist: dist, 330 ProjectName: "foobar", 331 Archives: []config.Archive{{ 332 Builds: []string{"not-default"}, 333 }}, 334 }) 335 ctx.Version = "0.0.1" 336 ctx.Git.CurrentTag = "v0.0.1" 337 ctx.Artifacts.Add(&artifact.Artifact{ 338 Goos: "linux", 339 Goarch: "amd64", 340 Name: "bin/mybin", 341 Path: filepath.Join(dist, "linuxamd64", "bin", "mybin"), 342 Type: artifact.Binary, 343 Extra: map[string]interface{}{ 344 artifact.ExtraBinary: "bin/mybin", 345 artifact.ExtraID: "default", 346 }, 347 }) 348 require.NoError(t, Pipe{}.Run(ctx)) 349 } 350 351 func zipFiles(t *testing.T, path string) []string { 352 t.Helper() 353 f, err := os.Open(path) 354 require.NoError(t, err) 355 info, err := f.Stat() 356 require.NoError(t, err) 357 r, err := zip.NewReader(f, info.Size()) 358 require.NoError(t, err) 359 paths := make([]string, len(r.File)) 360 for i, zf := range r.File { 361 paths[i] = zf.Name 362 } 363 return paths 364 } 365 366 func tarFiles(t *testing.T, path string) []string { 367 t.Helper() 368 f, err := os.Open(path) 369 require.NoError(t, err) 370 defer f.Close() 371 gr, err := gzip.NewReader(f) 372 require.NoError(t, err) 373 defer gr.Close() 374 r := tar.NewReader(gr) 375 var paths []string 376 for { 377 next, err := r.Next() 378 if err == io.EOF { 379 break 380 } 381 require.NoError(t, err) 382 paths = append(paths, next.Name) 383 } 384 return paths 385 } 386 387 func TestRunPipeBinary(t *testing.T) { 388 folder := testlib.Mktmp(t) 389 dist := filepath.Join(folder, "dist") 390 require.NoError(t, os.Mkdir(dist, 0o755)) 391 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 392 require.NoError(t, os.Mkdir(filepath.Join(dist, "windowsamd64"), 0o755)) 393 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 394 require.NoError(t, err) 395 require.NoError(t, f.Close()) 396 f, err = os.Create(filepath.Join(dist, "windowsamd64", "mybin.exe")) 397 require.NoError(t, err) 398 require.NoError(t, f.Close()) 399 f, err = os.Create(filepath.Join(dist, "windowsamd64", "myotherbin")) 400 require.NoError(t, err) 401 require.NoError(t, f.Close()) 402 f, err = os.Create(filepath.Join(folder, "README.md")) 403 require.NoError(t, err) 404 require.NoError(t, f.Close()) 405 ctx := context.New( 406 config.Project{ 407 Dist: dist, 408 Archives: []config.Archive{ 409 { 410 Format: "binary", 411 NameTemplate: defaultBinaryNameTemplate, 412 Builds: []string{"default", "default2"}, 413 }, 414 }, 415 }, 416 ) 417 ctx.Version = "0.0.1" 418 ctx.Git.CurrentTag = "v0.0.1" 419 ctx.Artifacts.Add(&artifact.Artifact{ 420 Goos: "darwin", 421 Goarch: "amd64", 422 Name: "mybin", 423 Path: filepath.Join(dist, "darwinamd64", "mybin"), 424 Type: artifact.Binary, 425 Extra: map[string]interface{}{ 426 artifact.ExtraBinary: "mybin", 427 artifact.ExtraID: "default", 428 }, 429 }) 430 ctx.Artifacts.Add(&artifact.Artifact{ 431 Goos: "darwin", 432 Goarch: "all", 433 Name: "myunibin", 434 Path: filepath.Join(dist, "darwinamd64", "mybin"), 435 Type: artifact.UniversalBinary, 436 Extra: map[string]interface{}{ 437 artifact.ExtraBinary: "myunibin", 438 artifact.ExtraID: "default", 439 artifact.ExtraReplaces: true, 440 }, 441 }) 442 ctx.Artifacts.Add(&artifact.Artifact{ 443 Goos: "windows", 444 Goarch: "amd64", 445 Name: "mybin.exe", 446 Path: filepath.Join(dist, "windowsamd64", "mybin.exe"), 447 Type: artifact.Binary, 448 Extra: map[string]interface{}{ 449 artifact.ExtraBinary: "mybin", 450 artifact.ExtraExt: ".exe", 451 artifact.ExtraID: "default", 452 }, 453 }) 454 ctx.Artifacts.Add(&artifact.Artifact{ 455 Goos: "windows", 456 Goarch: "amd64", 457 Name: "myotherbin.exe", 458 Path: filepath.Join(dist, "windowsamd64", "myotherbin.exe"), 459 Type: artifact.Binary, 460 Extra: map[string]interface{}{ 461 artifact.ExtraBinary: "myotherbin", 462 artifact.ExtraExt: ".exe", 463 artifact.ExtraID: "default2", 464 }, 465 }) 466 467 require.NoError(t, Pipe{}.Run(ctx)) 468 binaries := ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableBinary)) 469 require.Len(t, binaries.List(), 4) 470 darwinThin := binaries.Filter(artifact.And( 471 artifact.ByGoos("darwin"), 472 artifact.ByGoarch("amd64"), 473 )).List()[0] 474 darwinUniversal := binaries.Filter(artifact.And( 475 artifact.ByGoos("darwin"), 476 artifact.ByGoarch("all"), 477 )).List()[0] 478 require.True(t, artifact.ExtraOr(*darwinUniversal, artifact.ExtraReplaces, false)) 479 windows := binaries.Filter(artifact.ByGoos("windows")).List()[0] 480 windows2 := binaries.Filter(artifact.ByGoos("windows")).List()[1] 481 require.Equal(t, "mybin_0.0.1_darwin_amd64", darwinThin.Name) 482 require.Equal(t, "mybin", artifact.ExtraOr(*darwinThin, artifact.ExtraBinary, "")) 483 require.Equal(t, "myunibin_0.0.1_darwin_all", darwinUniversal.Name) 484 require.Equal(t, "myunibin", artifact.ExtraOr(*darwinUniversal, artifact.ExtraBinary, "")) 485 require.Equal(t, "mybin_0.0.1_windows_amd64.exe", windows.Name) 486 require.Equal(t, "mybin.exe", artifact.ExtraOr(*windows, artifact.ExtraBinary, "")) 487 require.Equal(t, "myotherbin_0.0.1_windows_amd64.exe", windows2.Name) 488 require.Equal(t, "myotherbin.exe", artifact.ExtraOr(*windows2, artifact.ExtraBinary, "")) 489 } 490 491 func TestRunPipeDistRemoved(t *testing.T) { 492 ctx := context.New( 493 config.Project{ 494 Dist: "/tmp/path/to/nope", 495 Archives: []config.Archive{ 496 { 497 NameTemplate: "nope", 498 Format: "zip", 499 Builds: []string{"default"}, 500 }, 501 }, 502 }, 503 ) 504 ctx.Git.CurrentTag = "v0.0.1" 505 ctx.Artifacts.Add(&artifact.Artifact{ 506 Goos: "windows", 507 Goarch: "amd64", 508 Name: "mybin.exe", 509 Path: filepath.Join("/tmp/path/to/nope", "windowsamd64", "mybin.exe"), 510 Type: artifact.Binary, 511 Extra: map[string]interface{}{ 512 artifact.ExtraBinary: "mybin", 513 artifact.ExtraExt: ".exe", 514 artifact.ExtraID: "default", 515 }, 516 }) 517 // not checking on error msg because it may change depending on OS/version 518 require.Error(t, Pipe{}.Run(ctx)) 519 } 520 521 func TestRunPipeInvalidGlob(t *testing.T) { 522 folder := testlib.Mktmp(t) 523 dist := filepath.Join(folder, "dist") 524 require.NoError(t, os.Mkdir(dist, 0o755)) 525 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 526 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 527 require.NoError(t, err) 528 require.NoError(t, f.Close()) 529 ctx := context.New( 530 config.Project{ 531 Dist: dist, 532 Archives: []config.Archive{ 533 { 534 Builds: []string{"default"}, 535 NameTemplate: "foo", 536 Format: "zip", 537 Files: []config.File{ 538 {Source: "[x-]"}, 539 }, 540 }, 541 }, 542 }, 543 ) 544 ctx.Git.CurrentTag = "v0.0.1" 545 ctx.Artifacts.Add(&artifact.Artifact{ 546 Goos: "darwin", 547 Goarch: "amd64", 548 Name: "mybin", 549 Path: filepath.Join("dist", "darwinamd64", "mybin"), 550 Type: artifact.Binary, 551 Extra: map[string]interface{}{ 552 artifact.ExtraBinary: "mybin", 553 artifact.ExtraID: "default", 554 }, 555 }) 556 require.EqualError(t, Pipe{}.Run(ctx), `failed to find files to archive: globbing failed for pattern [x-]: compile glob pattern: unexpected end of input`) 557 } 558 559 func TestRunPipeInvalidNameTemplate(t *testing.T) { 560 folder := testlib.Mktmp(t) 561 dist := filepath.Join(folder, "dist") 562 require.NoError(t, os.Mkdir(dist, 0o755)) 563 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 564 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 565 require.NoError(t, err) 566 require.NoError(t, f.Close()) 567 ctx := context.New( 568 config.Project{ 569 Dist: dist, 570 Archives: []config.Archive{ 571 { 572 Builds: []string{"default"}, 573 NameTemplate: "foo{{ .fff }", 574 Format: "zip", 575 }, 576 }, 577 }, 578 ) 579 ctx.Git.CurrentTag = "v0.0.1" 580 ctx.Artifacts.Add(&artifact.Artifact{ 581 Goos: "darwin", 582 Goarch: "amd64", 583 Name: "mybin", 584 Path: filepath.Join("dist", "darwinamd64", "mybin"), 585 Type: artifact.Binary, 586 Extra: map[string]interface{}{ 587 artifact.ExtraBinary: "mybin", 588 artifact.ExtraID: "default", 589 }, 590 }) 591 testlib.RequireTemplateError(t, Pipe{}.Run(ctx)) 592 } 593 594 func TestRunPipeInvalidFilesNameTemplate(t *testing.T) { 595 folder := testlib.Mktmp(t) 596 dist := filepath.Join(folder, "dist") 597 require.NoError(t, os.Mkdir(dist, 0o755)) 598 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 599 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 600 require.NoError(t, err) 601 require.NoError(t, f.Close()) 602 ctx := context.New( 603 config.Project{ 604 Dist: dist, 605 Archives: []config.Archive{ 606 { 607 Builds: []string{"default"}, 608 NameTemplate: "foo", 609 Format: "zip", 610 Files: []config.File{ 611 {Source: "{{.asdsd}"}, 612 }, 613 }, 614 }, 615 }, 616 ) 617 ctx.Git.CurrentTag = "v0.0.1" 618 ctx.Artifacts.Add(&artifact.Artifact{ 619 Goos: "darwin", 620 Goarch: "amd64", 621 Name: "mybin", 622 Path: filepath.Join("dist", "darwinamd64", "mybin"), 623 Type: artifact.Binary, 624 Extra: map[string]interface{}{ 625 artifact.ExtraBinary: "mybin", 626 artifact.ExtraID: "default", 627 }, 628 }) 629 testlib.RequireTemplateError(t, Pipe{}.Run(ctx)) 630 } 631 632 func TestRunPipeInvalidWrapInDirectoryTemplate(t *testing.T) { 633 folder := testlib.Mktmp(t) 634 dist := filepath.Join(folder, "dist") 635 require.NoError(t, os.Mkdir(dist, 0o755)) 636 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 637 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 638 require.NoError(t, err) 639 require.NoError(t, f.Close()) 640 ctx := context.New( 641 config.Project{ 642 Dist: dist, 643 Archives: []config.Archive{ 644 { 645 Builds: []string{"default"}, 646 NameTemplate: "foo", 647 WrapInDirectory: "foo{{ .fff }", 648 Format: "zip", 649 }, 650 }, 651 }, 652 ) 653 ctx.Git.CurrentTag = "v0.0.1" 654 ctx.Artifacts.Add(&artifact.Artifact{ 655 Goos: "darwin", 656 Goarch: "amd64", 657 Name: "mybin", 658 Path: filepath.Join("dist", "darwinamd64", "mybin"), 659 Type: artifact.Binary, 660 Extra: map[string]interface{}{ 661 artifact.ExtraBinary: "mybin", 662 artifact.ExtraID: "default", 663 }, 664 }) 665 require.EqualError(t, Pipe{}.Run(ctx), `template: tmpl:1: unexpected "}" in operand`) 666 } 667 668 func TestRunPipeWrap(t *testing.T) { 669 folder := testlib.Mktmp(t) 670 dist := filepath.Join(folder, "dist") 671 require.NoError(t, os.Mkdir(dist, 0o755)) 672 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 673 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 674 require.NoError(t, err) 675 require.NoError(t, f.Close()) 676 f, err = os.Create(filepath.Join(folder, "README.md")) 677 require.NoError(t, err) 678 require.NoError(t, f.Close()) 679 ctx := context.New( 680 config.Project{ 681 Dist: dist, 682 Archives: []config.Archive{ 683 { 684 Builds: []string{"default"}, 685 NameTemplate: "foo", 686 WrapInDirectory: "foo_{{ .Os }}", 687 Format: "tar.gz", 688 Replacements: map[string]string{ 689 "darwin": "macOS", 690 }, 691 Files: []config.File{ 692 {Source: "README.*"}, 693 }, 694 }, 695 }, 696 }, 697 ) 698 ctx.Git.CurrentTag = "v0.0.1" 699 ctx.Artifacts.Add(&artifact.Artifact{ 700 Goos: "darwin", 701 Goarch: "amd64", 702 Name: "mybin", 703 Path: filepath.Join("dist", "darwinamd64", "mybin"), 704 Type: artifact.Binary, 705 Extra: map[string]interface{}{ 706 artifact.ExtraBinary: "mybin", 707 artifact.ExtraID: "default", 708 }, 709 }) 710 require.NoError(t, Pipe{}.Run(ctx)) 711 712 archives := ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableArchive)).List() 713 require.Len(t, archives, 1) 714 require.Equal(t, "foo_macOS", artifact.ExtraOr(*archives[0], artifact.ExtraWrappedIn, "")) 715 716 // Check archive contents 717 f, err = os.Open(filepath.Join(dist, "foo.tar.gz")) 718 require.NoError(t, err) 719 defer func() { require.NoError(t, f.Close()) }() 720 gr, err := gzip.NewReader(f) 721 require.NoError(t, err) 722 defer func() { require.NoError(t, gr.Close()) }() 723 r := tar.NewReader(gr) 724 for _, n := range []string{"README.md", "mybin"} { 725 h, err := r.Next() 726 if err == io.EOF { 727 break 728 } 729 require.NoError(t, err) 730 require.Equal(t, filepath.Join("foo_macOS", n), h.Name) 731 } 732 } 733 734 func TestDefault(t *testing.T) { 735 ctx := &context.Context{ 736 Config: config.Project{ 737 Archives: []config.Archive{}, 738 }, 739 } 740 require.NoError(t, Pipe{}.Default(ctx)) 741 require.NotEmpty(t, ctx.Config.Archives[0].NameTemplate) 742 require.Equal(t, "tar.gz", ctx.Config.Archives[0].Format) 743 require.NotEmpty(t, ctx.Config.Archives[0].Files) 744 } 745 746 func TestDefaultSet(t *testing.T) { 747 ctx := &context.Context{ 748 Config: config.Project{ 749 Archives: []config.Archive{ 750 { 751 Builds: []string{"default"}, 752 NameTemplate: "foo", 753 Format: "zip", 754 Files: []config.File{ 755 {Source: "foo"}, 756 }, 757 }, 758 }, 759 }, 760 } 761 require.NoError(t, Pipe{}.Default(ctx)) 762 require.Equal(t, "foo", ctx.Config.Archives[0].NameTemplate) 763 require.Equal(t, "zip", ctx.Config.Archives[0].Format) 764 require.Equal(t, config.File{Source: "foo"}, ctx.Config.Archives[0].Files[0]) 765 } 766 767 func TestDefaultFormatBinary(t *testing.T) { 768 ctx := &context.Context{ 769 Config: config.Project{ 770 Archives: []config.Archive{ 771 { 772 Format: "binary", 773 }, 774 }, 775 }, 776 } 777 require.NoError(t, Pipe{}.Default(ctx)) 778 require.Equal(t, defaultBinaryNameTemplate, ctx.Config.Archives[0].NameTemplate) 779 } 780 781 func TestFormatFor(t *testing.T) { 782 ctx := &context.Context{ 783 Config: config.Project{ 784 Archives: []config.Archive{ 785 { 786 Builds: []string{"default"}, 787 Format: "tar.gz", 788 FormatOverrides: []config.FormatOverride{ 789 { 790 Goos: "windows", 791 Format: "zip", 792 }, 793 }, 794 }, 795 }, 796 }, 797 } 798 require.Equal(t, "zip", packageFormat(ctx.Config.Archives[0], "windows")) 799 require.Equal(t, "tar.gz", packageFormat(ctx.Config.Archives[0], "linux")) 800 } 801 802 func TestBinaryOverride(t *testing.T) { 803 folder := testlib.Mktmp(t) 804 dist := filepath.Join(folder, "dist") 805 require.NoError(t, os.Mkdir(dist, 0o755)) 806 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 807 require.NoError(t, os.Mkdir(filepath.Join(dist, "windowsamd64"), 0o755)) 808 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 809 require.NoError(t, err) 810 require.NoError(t, f.Close()) 811 f, err = os.Create(filepath.Join(dist, "windowsamd64", "mybin.exe")) 812 require.NoError(t, err) 813 require.NoError(t, f.Close()) 814 f, err = os.Create(filepath.Join(folder, "README.md")) 815 require.NoError(t, err) 816 require.NoError(t, f.Close()) 817 for _, format := range []string{"tar.gz", "zip"} { 818 t.Run("Archive format "+format, func(t *testing.T) { 819 ctx := context.New( 820 config.Project{ 821 Dist: dist, 822 ProjectName: "foobar", 823 Archives: []config.Archive{ 824 { 825 Builds: []string{"default"}, 826 NameTemplate: defaultNameTemplate, 827 Files: []config.File{ 828 {Source: "README.*"}, 829 }, 830 FormatOverrides: []config.FormatOverride{ 831 { 832 Goos: "windows", 833 Format: "binary", 834 }, 835 }, 836 }, 837 }, 838 }, 839 ) 840 ctx.Git.CurrentTag = "v0.0.1" 841 ctx.Artifacts.Add(&artifact.Artifact{ 842 Goos: "darwin", 843 Goarch: "amd64", 844 Name: "mybin", 845 Path: filepath.Join(dist, "darwinamd64", "mybin"), 846 Type: artifact.Binary, 847 Extra: map[string]interface{}{ 848 artifact.ExtraBinary: "mybin", 849 artifact.ExtraID: "default", 850 }, 851 }) 852 ctx.Artifacts.Add(&artifact.Artifact{ 853 Goos: "windows", 854 Goarch: "amd64", 855 Name: "mybin.exe", 856 Path: filepath.Join(dist, "windowsamd64", "mybin.exe"), 857 Type: artifact.Binary, 858 Extra: map[string]interface{}{ 859 artifact.ExtraBinary: "mybin", 860 artifact.ExtraExt: ".exe", 861 artifact.ExtraID: "default", 862 }, 863 }) 864 ctx.Version = "0.0.1" 865 ctx.Config.Archives[0].Format = format 866 867 require.NoError(t, Pipe{}.Run(ctx)) 868 archives := ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableArchive)) 869 darwin := archives.Filter(artifact.ByGoos("darwin")).List()[0] 870 require.Equal(t, "foobar_0.0.1_darwin_amd64."+format, darwin.Name) 871 require.Equal(t, format, darwin.Format()) 872 require.Empty(t, artifact.ExtraOr(*darwin, artifact.ExtraWrappedIn, "")) 873 874 archives = ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableBinary)) 875 windows := archives.Filter(artifact.ByGoos("windows")).List()[0] 876 require.Equal(t, "foobar_0.0.1_windows_amd64.exe", windows.Name) 877 require.Empty(t, artifact.ExtraOr(*windows, artifact.ExtraWrappedIn, "")) 878 require.Equal(t, "mybin.exe", artifact.ExtraOr(*windows, artifact.ExtraBinary, "")) 879 }) 880 } 881 } 882 883 func TestRunPipeSameArchiveFilename(t *testing.T) { 884 folder := testlib.Mktmp(t) 885 dist := filepath.Join(folder, "dist") 886 require.NoError(t, os.Mkdir(dist, 0o755)) 887 require.NoError(t, os.Mkdir(filepath.Join(dist, "darwinamd64"), 0o755)) 888 require.NoError(t, os.Mkdir(filepath.Join(dist, "windowsamd64"), 0o755)) 889 f, err := os.Create(filepath.Join(dist, "darwinamd64", "mybin")) 890 require.NoError(t, err) 891 require.NoError(t, f.Close()) 892 f, err = os.Create(filepath.Join(dist, "windowsamd64", "mybin.exe")) 893 require.NoError(t, err) 894 require.NoError(t, f.Close()) 895 ctx := context.New( 896 config.Project{ 897 Dist: dist, 898 ProjectName: "foobar", 899 Archives: []config.Archive{ 900 { 901 Builds: []string{"default"}, 902 NameTemplate: "same-filename", 903 Files: []config.File{ 904 {Source: "README.*"}, 905 {Source: "./foo/**/*"}, 906 }, 907 Format: "tar.gz", 908 }, 909 }, 910 }, 911 ) 912 ctx.Artifacts.Add(&artifact.Artifact{ 913 Goos: "darwin", 914 Goarch: "amd64", 915 Name: "mybin", 916 Path: filepath.Join(dist, "darwinamd64", "mybin"), 917 Type: artifact.Binary, 918 Extra: map[string]interface{}{ 919 artifact.ExtraBinary: "mybin", 920 artifact.ExtraID: "default", 921 }, 922 }) 923 ctx.Artifacts.Add(&artifact.Artifact{ 924 Goos: "windows", 925 Goarch: "amd64", 926 Name: "mybin.exe", 927 Path: filepath.Join(dist, "windowsamd64", "mybin.exe"), 928 Type: artifact.Binary, 929 Extra: map[string]interface{}{ 930 artifact.ExtraBinary: "mybin", 931 artifact.ExtraExt: ".exe", 932 artifact.ExtraID: "default", 933 }, 934 }) 935 ctx.Version = "0.0.1" 936 ctx.Git.CurrentTag = "v0.0.1" 937 err = Pipe{}.Run(ctx) 938 require.Error(t, err) 939 require.Contains(t, err.Error(), "same-filename.tar.gz already exists. Check your archive name template") 940 } 941 942 func TestDuplicateFilesInsideArchive(t *testing.T) { 943 folder := t.TempDir() 944 945 f, err := os.CreateTemp(folder, "") 946 require.NoError(t, err) 947 t.Cleanup(func() { 948 require.NoError(t, f.Close()) 949 }) 950 951 ff, err := os.CreateTemp(folder, "") 952 require.NoError(t, err) 953 require.NoError(t, ff.Close()) 954 a, err := archive.New(f, "tar.gz") 955 require.NoError(t, err) 956 a = NewEnhancedArchive(a, "") 957 t.Cleanup(func() { 958 require.NoError(t, a.Close()) 959 }) 960 961 require.NoError(t, a.Add(config.File{ 962 Source: ff.Name(), 963 Destination: "foo", 964 })) 965 require.EqualError(t, a.Add(config.File{ 966 Source: ff.Name(), 967 Destination: "foo", 968 }), "file foo already exists in the archive") 969 } 970 971 func TestWrapInDirectory(t *testing.T) { 972 t.Run("false", func(t *testing.T) { 973 require.Equal(t, "", wrapFolder(config.Archive{ 974 WrapInDirectory: "false", 975 })) 976 }) 977 t.Run("true", func(t *testing.T) { 978 require.Equal(t, "foo", wrapFolder(config.Archive{ 979 WrapInDirectory: "true", 980 NameTemplate: "foo", 981 })) 982 }) 983 t.Run("custom", func(t *testing.T) { 984 require.Equal(t, "foobar", wrapFolder(config.Archive{ 985 WrapInDirectory: "foobar", 986 })) 987 }) 988 } 989 990 func TestSeveralArchivesWithTheSameID(t *testing.T) { 991 ctx := &context.Context{ 992 Config: config.Project{ 993 Archives: []config.Archive{ 994 { 995 ID: "a", 996 }, 997 { 998 ID: "a", 999 }, 1000 }, 1001 }, 1002 } 1003 require.EqualError(t, Pipe{}.Default(ctx), "found 2 archives with the ID 'a', please fix your config") 1004 } 1005 1006 func TestArchive_globbing(t *testing.T) { 1007 assertGlob := func(t *testing.T, files []config.File, expected []string) { 1008 t.Helper() 1009 bin, err := os.CreateTemp(t.TempDir(), "binary") 1010 require.NoError(t, err) 1011 dist := t.TempDir() 1012 ctx := context.New(config.Project{ 1013 Dist: dist, 1014 Archives: []config.Archive{ 1015 { 1016 Builds: []string{"default"}, 1017 Format: "tar.gz", 1018 NameTemplate: "foo", 1019 Files: files, 1020 }, 1021 }, 1022 }) 1023 1024 ctx.Artifacts.Add(&artifact.Artifact{ 1025 Goos: "darwin", 1026 Goarch: "amd64", 1027 Name: "foobin", 1028 Path: bin.Name(), 1029 Type: artifact.Binary, 1030 Extra: map[string]interface{}{ 1031 artifact.ExtraID: "default", 1032 }, 1033 }) 1034 1035 require.NoError(t, Pipe{}.Run(ctx)) 1036 require.Equal(t, append(expected, "foobin"), tarFiles(t, filepath.Join(dist, "foo.tar.gz"))) 1037 } 1038 1039 t.Run("exact src file", func(t *testing.T) { 1040 assertGlob(t, []config.File{{Source: "testdata/a/a.txt"}}, []string{"testdata/a/a.txt"}) 1041 }) 1042 1043 t.Run("exact src file with dst", func(t *testing.T) { 1044 assertGlob(t, []config.File{ 1045 { 1046 Source: "testdata/a/a.txt", 1047 Destination: "foo/", 1048 }, 1049 }, []string{"foo/testdata/a/a.txt"}) 1050 }) 1051 1052 t.Run("glob src", func(t *testing.T) { 1053 assertGlob(t, []config.File{ 1054 {Source: "testdata/**/*.txt"}, 1055 }, []string{ 1056 "testdata/a/a.txt", 1057 "testdata/a/b/a.txt", 1058 "testdata/a/b/c/d.txt", 1059 }) 1060 }) 1061 1062 t.Run("glob src with dst", func(t *testing.T) { 1063 assertGlob(t, []config.File{ 1064 { 1065 Source: "testdata/**/*.txt", 1066 Destination: "var/yada", 1067 }, 1068 }, []string{ 1069 "var/yada/testdata/a/a.txt", 1070 "var/yada/testdata/a/b/a.txt", 1071 "var/yada/testdata/a/b/c/d.txt", 1072 }) 1073 }) 1074 1075 t.Run("glob src with dst stripping parent", func(t *testing.T) { 1076 assertGlob(t, []config.File{ 1077 { 1078 Source: "testdata/**/*.txt", 1079 Destination: "var/yada", 1080 StripParent: true, 1081 }, 1082 }, []string{ 1083 "var/yada/a.txt", 1084 "var/yada/d.txt", 1085 }) 1086 }) 1087 } 1088 1089 func TestInvalidFormat(t *testing.T) { 1090 ctx := context.New(config.Project{ 1091 Dist: t.TempDir(), 1092 Archives: []config.Archive{ 1093 { 1094 ID: "foo", 1095 NameTemplate: "foo", 1096 Meta: true, 1097 Format: "7z", 1098 }, 1099 }, 1100 }) 1101 require.EqualError(t, Pipe{}.Run(ctx), "invalid archive format: 7z") 1102 }