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