diff --git a/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.installer.yaml.golden b/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.installer.yaml.golden new file mode 100644 index 00000000000..2d18a34e258 --- /dev/null +++ b/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.installer.yaml.golden @@ -0,0 +1,24 @@ +# This file was generated by GoReleaser. DO NOT EDIT. +# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json +PackageIdentifier: goreleaser.foo +PackageVersion: 1.2.1 +InstallerLocale: en-US +InstallerType: portable +Commands: + - foo +ReleaseDate: "2023-06-12" +Installers: + - Architecture: x64 + InstallerUrl: https://dummyhost/download/v1.2.1/foo_windows_amd64v1.exe + InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + UpgradeBehavior: uninstallPrevious + - Architecture: x86 + InstallerUrl: https://dummyhost/download/v1.2.1/foo_windows_386.exe + InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + UpgradeBehavior: uninstallPrevious + - Architecture: arm64 + InstallerUrl: https://dummyhost/download/v1.2.1/foo_windows_arm64.exe + InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + UpgradeBehavior: uninstallPrevious +ManifestType: installer +ManifestVersion: 1.5.0 diff --git a/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.locale.en-US.yaml.golden new file mode 100644 index 00000000000..5254612dd91 --- /dev/null +++ b/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.locale.en-US.yaml.golden @@ -0,0 +1,12 @@ +# This file was generated by GoReleaser. DO NOT EDIT. +# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json +PackageIdentifier: goreleaser.foo +PackageVersion: 1.2.1 +PackageLocale: en-US +Publisher: goreleaser +PackageName: foo +License: MIT +ShortDescription: foo bar zaz +Moniker: foo +ManifestType: defaultLocale +ManifestVersion: 1.5.0 diff --git a/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.yaml.golden b/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.yaml.golden new file mode 100644 index 00000000000..afd8a8231a4 --- /dev/null +++ b/internal/pipe/winget/testdata/TestFormatBinary/TestFormatBinary.yaml.golden @@ -0,0 +1,7 @@ +# This file was generated by GoReleaser. DO NOT EDIT. +# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json +PackageIdentifier: goreleaser.foo +PackageVersion: 1.2.1 +DefaultLocale: en-US +ManifestType: version +ManifestVersion: 1.5.0 diff --git a/internal/pipe/winget/winget.go b/internal/pipe/winget/winget.go index 6fc1a76c4b0..a080e9f8399 100644 --- a/internal/pipe/winget/winget.go +++ b/internal/pipe/winget/winget.go @@ -28,6 +28,7 @@ var ( errSkipUpload = pipe.Skip("winget.skip_upload is set") errSkipUploadAuto = pipe.Skip("winget.skip_upload is set to 'auto', and current version is a pre-release") errMultipleArchives = pipe.Skip("found multiple archives for the same platform, please consider filtering by id") + errMixedFormats = pipe.Skip("found archives with multiple formats (.exe and .zip)") // copied from winget src packageIdentifierValid = regexp.MustCompile("^[^\\.\\s\\\\/:\\*\\?\"<>\\|\\x01-\\x1f]{1,32}(\\.[^\\.\\s\\\\/:\\*\\?\"<>\\|\\x01-\\x1f]{1,32}){1,7}$") @@ -165,8 +166,13 @@ func (p Pipe) doRun(ctx *context.Context, winget config.Winget, cl client.Releas filters := []artifact.Filter{ artifact.ByGoos("windows"), - artifact.ByFormats("zip"), - artifact.ByType(artifact.UploadableArchive), + artifact.Or( + artifact.And( + artifact.ByFormats("zip"), + artifact.ByType(artifact.UploadableArchive), + ), + artifact.ByType(artifact.UploadableBinary), + ), artifact.Or( artifact.ByGoarch("386"), artifact.ByGoarch("arm64"), @@ -231,32 +237,33 @@ func (p Pipe) doRun(ctx *context.Context, winget config.Winget, cl client.Releas }, } - var amd64Count, i386count int + var amd64Count, i386count, zipCount, binaryCount int for _, archive := range archives { sha256, err := archive.Checksum("sha256") if err != nil { return err } - var files []InstallerItemFile - folder := artifact.ExtraOr(*archive, artifact.ExtraWrappedIn, ".") - for _, bin := range artifact.ExtraOr(*archive, artifact.ExtraBinaries, []string{}) { - files = append(files, InstallerItemFile{ - RelativeFilePath: strings.ReplaceAll(filepath.Join(folder, bin), "/", "\\"), - PortableCommandAlias: strings.TrimSuffix(filepath.Base(bin), ".exe"), - }) - } url, err := tmpl.New(ctx).WithArtifact(archive).Apply(winget.URLTemplate) if err != nil { return err } - installer.Installers = append(installer.Installers, InstallerItem{ - Architecture: fromGoArch[archive.Goarch], - NestedInstallerType: "portable", - NestedInstallerFiles: files, - InstallerURL: url, - InstallerSha256: sha256, - UpgradeBehavior: "uninstallPrevious", - }) + item := InstallerItem{ + Architecture: fromGoArch[archive.Goarch], + InstallerURL: url, + InstallerSha256: sha256, + UpgradeBehavior: "uninstallPrevious", + } + if archive.Format() == "zip" { + zipCount++ + installer.InstallerType = "zip" + item.NestedInstallerType = "portable" + item.NestedInstallerFiles = installerItemFilesFor(*archive) + } else { + binaryCount++ + installer.InstallerType = "portable" + installer.Commands = []string{winget.Name} + } + installer.Installers = append(installer.Installers, item) switch archive.Goarch { case "386": i386count++ @@ -265,6 +272,10 @@ func (p Pipe) doRun(ctx *context.Context, winget config.Winget, cl client.Releas } } + if binaryCount > 0 && zipCount > 0 { + return errMixedFormats + } + if i386count > 1 || amd64Count > 1 { return errMultipleArchives } @@ -437,3 +448,15 @@ func repoFileID(tp artifact.Type) string { return "" } } + +func installerItemFilesFor(archive artifact.Artifact) []InstallerItemFile { + var files []InstallerItemFile + folder := artifact.ExtraOr(archive, artifact.ExtraWrappedIn, ".") + for _, bin := range artifact.ExtraOr(archive, artifact.ExtraBinaries, []string{}) { + files = append(files, InstallerItemFile{ + RelativeFilePath: strings.ReplaceAll(filepath.Join(folder, bin), "/", "\\"), + PortableCommandAlias: strings.TrimSuffix(filepath.Base(bin), ".exe"), + }) + } + return files +} diff --git a/internal/pipe/winget/winget_test.go b/internal/pipe/winget/winget_test.go index b9795910243..1e1ef2c5ef8 100644 --- a/internal/pipe/winget/winget_test.go +++ b/internal/pipe/winget/winget_test.go @@ -64,6 +64,21 @@ func TestRunPipe(t *testing.T) { }, }, }, + { + name: "mixed-formats", + expectRunErrorIs: errMixedFormats, + winget: config.Winget{ + Name: "mixed", + Publisher: "Foo", + License: "MIT", + ShortDescription: "foo bar zaz", + IDs: []string{"zaz", "bar"}, + Repository: config.RepoRef{ + Owner: "foo", + Name: "bar", + }, + }, + }, { name: "full", expectPath: "manifests/b/Beckersoft LTDA/foo/1.2.1", @@ -650,6 +665,7 @@ func TestRunPipe(t *testing.T) { goarch := "amd64" createFakeArtifact("partial", goos, goarch, "v1", "", nil) createFakeArtifact("foo", goos, goarch, "v1", "", nil) + createFakeArtifact("zaz", goos, goarch, "v1", "", nil) createFakeArtifact("wrapped-in-dir", goos, goarch, "v1", "", map[string]any{ artifact.ExtraWrappedIn: "foo", artifact.ExtraBinaries: []string{"bin/foo.exe"}, @@ -657,6 +673,17 @@ func TestRunPipe(t *testing.T) { goarch = "386" createFakeArtifact("foo", goos, goarch, "", "", nil) + ctx.Artifacts.Add(&artifact.Artifact{ + Name: "bar.exe", + Path: "doesnt-matter", + Goos: goos, + Goarch: goarch, + Type: artifact.UploadableBinary, + Extra: map[string]interface{}{ + artifact.ExtraID: "bar", + }, + }) + createFakeArtifact("bar", goos, goarch, "v1", "", nil) createFakeArtifact("wrapped-in-dir", goos, goarch, "", "", map[string]any{ artifact.ExtraWrappedIn: "foo", artifact.ExtraBinaries: []string{"bin/foo.exe"}, @@ -750,3 +777,70 @@ func TestDefault(t *testing.T) { require.NotEmpty(t, winget.CommitMessageTemplate) require.Equal(t, "foo", winget.Name) } + +func TestFormatBinary(t *testing.T) { + folder := t.TempDir() + ctx := testctx.NewWithCfg( + config.Project{ + Dist: folder, + ProjectName: "foo", + Winget: []config.Winget{{ + Name: "foo", + Publisher: "goreleaser", + License: "MIT", + ShortDescription: "foo bar zaz", + IDs: []string{"foo"}, + Repository: config.RepoRef{ + Owner: "foo", + Name: "bar", + }, + }}, + }, + testctx.WithVersion("1.2.1"), + testctx.WithCurrentTag("v1.2.1"), + testctx.WithSemver(1, 2, 1, "rc1"), + testctx.WithDate(time.Date(2023, 6, 12, 20, 32, 10, 12, time.Local)), + ) + ctx.ReleaseNotes = "the changelog for this release..." + createFakeArtifact := func(id, goos, goarch, goamd64 string) { + path := filepath.Join(folder, "dist/foo_"+goos+goarch+goamd64+".exe") + art := artifact.Artifact{ + Name: "foo_" + goos + "_" + goarch + goamd64 + ".exe", + Path: path, + Goos: goos, + Goarch: goarch, + Goamd64: goamd64, + Type: artifact.UploadableBinary, + Extra: map[string]interface{}{ + artifact.ExtraID: id, + }, + } + ctx.Artifacts.Add(&art) + require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755)) + f, err := os.Create(path) + require.NoError(t, err) + require.NoError(t, f.Close()) + } + + goos := "windows" + createFakeArtifact("foo", goos, "amd64", "v1") + createFakeArtifact("foo", goos, "386", "") + createFakeArtifact("foo", goos, "arm64", "") + + client := client.NewMock() + pipe := Pipe{} + + require.NoError(t, pipe.Default(ctx)) + require.NoError(t, pipe.runAll(ctx, client)) + for _, winget := range ctx.Artifacts.Filter(artifact.Or( + artifact.ByType(artifact.WingetInstaller), + artifact.ByType(artifact.WingetVersion), + artifact.ByType(artifact.WingetDefaultLocale), + )).List() { + bts, err := os.ReadFile(winget.Path) + require.NoError(t, err) + golden.RequireEqualExtSubfolder(t, bts, extFor(winget.Type)) + } + require.NoError(t, pipe.publishAll(ctx, client)) + require.True(t, client.CreatedFile) +}