From 4c0cef090d279bea5419fb5c530931a679bc8ced Mon Sep 17 00:00:00 2001 From: danebou Date: Fri, 26 Jul 2024 16:05:12 +0000 Subject: [PATCH] Release Asset Management (#619) Add release asset management. This includes a series of subcommands under `tea release assets`: - `tea release assets create [...]`: Upload one or more release attachments - `tea release assets delete [...]`: Delete one or more release attachments - `tea release assets list `: List Release Attachments Co-authored-by: Dane Bouchie Reviewed-on: https://gitea.com/gitea/tea/pulls/619 Co-authored-by: danebou Co-committed-by: danebou --- README.md | 19 +++---- cmd/attachments.go | 28 ++++++++++ cmd/attachments/create.go | 64 +++++++++++++++++++++++ cmd/attachments/delete.go | 100 ++++++++++++++++++++++++++++++++++++ cmd/attachments/list.go | 74 ++++++++++++++++++++++++++ cmd/releases.go | 1 + docs/CLI.md | 54 +++++++++++++++++++ modules/print/attachment.go | 25 +++++++++ 8 files changed, 356 insertions(+), 9 deletions(-) create mode 100644 cmd/attachments.go create mode 100644 cmd/attachments/create.go create mode 100644 cmd/attachments/delete.go create mode 100644 cmd/attachments/list.go create mode 100644 modules/print/attachment.go diff --git a/README.md b/README.md index 0fdc832..a69c627 100644 --- a/README.md +++ b/README.md @@ -29,15 +29,16 @@ COMMANDS help, h Shows a list of commands or help for one command ENTITIES: - issues, issue, i List, create and update issues - pulls, pull, pr Manage and checkout pull requests - labels, label Manage issue labels - milestones, milestone, ms List and create milestones - releases, release, r Manage releases - times, time, t Operate on tracked times of a repository's issues & pulls - organizations, organization, org List, create, delete organizations - repos, repo Show repository details - comment, c Add a comment to an issue / pr + issues, issue, i List, create and update issues + pulls, pull, pr Manage and checkout pull requests + labels, label Manage issue labels + milestones, milestone, ms List and create milestones + releases, release, r Manage releases + release assets, release asset, r a Manage release attachments + times, time, t Operate on tracked times of a repository's issues & pulls + organizations, organization, org List, create, delete organizations + repos, repo Show repository details + comment, c Add a comment to an issue / pr HELPERS: open, o Open something of the repository in web browser notifications, notification, n Show notifications diff --git a/cmd/attachments.go b/cmd/attachments.go new file mode 100644 index 0000000..0e2ff77 --- /dev/null +++ b/cmd/attachments.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "code.gitea.io/tea/cmd/attachments" + "code.gitea.io/tea/cmd/flags" + + "github.com/urfave/cli/v2" +) + +// CmdReleaseAttachments represents a release attachment (file attachment) +var CmdReleaseAttachments = cli.Command{ + Name: "assets", + Aliases: []string{"asset", "a"}, + Category: catEntities, + Usage: "Manage release assets", + Description: "Manage release assets", + ArgsUsage: " ", // command does not accept arguments + Action: attachments.RunReleaseAttachmentList, + Subcommands: []*cli.Command{ + &attachments.CmdReleaseAttachmentList, + &attachments.CmdReleaseAttachmentCreate, + &attachments.CmdReleaseAttachmentDelete, + }, + Flags: flags.AllDefaultFlags, +} diff --git a/cmd/attachments/create.go b/cmd/attachments/create.go new file mode 100644 index 0000000..84ec30a --- /dev/null +++ b/cmd/attachments/create.go @@ -0,0 +1,64 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package attachments + +import ( + "fmt" + "os" + "path/filepath" + + "code.gitea.io/tea/cmd/flags" + "code.gitea.io/tea/modules/context" + + "github.com/urfave/cli/v2" +) + +// CmdReleaseAttachmentCreate represents a sub command of Release Attachments to create a release attachment +var CmdReleaseAttachmentCreate = cli.Command{ + Name: "create", + Aliases: []string{"c"}, + Usage: "Create one or more release attachments", + Description: `Create one or more release attachments`, + ArgsUsage: " [...]", + Action: runReleaseAttachmentCreate, + Flags: flags.AllDefaultFlags, +} + +func runReleaseAttachmentCreate(cmd *cli.Context) error { + ctx := context.InitCommand(cmd) + ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) + client := ctx.Login.Client() + + if ctx.Args().Len() < 2 { + return fmt.Errorf("No release tag or assets specified.\nUsage:\t%s", ctx.Command.UsageText) + } + + tag := ctx.Args().First() + if len(tag) == 0 { + return fmt.Errorf("Release tag needed to create attachment") + } + + release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client) + if err != nil { + return err + } + + for _, asset := range ctx.Args().Slice()[1:] { + var file *os.File + if file, err = os.Open(asset); err != nil { + return err + } + + filePath := filepath.Base(asset) + + if _, _, err = ctx.Login.Client().CreateReleaseAttachment(ctx.Owner, ctx.Repo, release.ID, file, filePath); err != nil { + file.Close() + return err + } + + file.Close() + } + + return nil +} diff --git a/cmd/attachments/delete.go b/cmd/attachments/delete.go new file mode 100644 index 0000000..0287297 --- /dev/null +++ b/cmd/attachments/delete.go @@ -0,0 +1,100 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package attachments + +import ( + "fmt" + + "code.gitea.io/tea/cmd/flags" + "code.gitea.io/tea/modules/context" + + "code.gitea.io/sdk/gitea" + "github.com/urfave/cli/v2" +) + +// CmdReleaseAttachmentDelete represents a sub command of Release Attachments to delete a release attachment +var CmdReleaseAttachmentDelete = cli.Command{ + Name: "delete", + Aliases: []string{"rm"}, + Usage: "Delete one or more release attachments", + Description: `Delete one or more release attachments`, + ArgsUsage: " [...]", + Action: runReleaseAttachmentDelete, + Flags: append([]cli.Flag{ + &cli.BoolFlag{ + Name: "confirm", + Aliases: []string{"y"}, + Usage: "Confirm deletion (required)", + }, + }, flags.AllDefaultFlags...), +} + +func runReleaseAttachmentDelete(cmd *cli.Context) error { + ctx := context.InitCommand(cmd) + ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) + client := ctx.Login.Client() + + if ctx.Args().Len() < 2 { + return fmt.Errorf("No release tag or attachment names specified.\nUsage:\t%s", ctx.Command.UsageText) + } + + tag := ctx.Args().First() + if len(tag) == 0 { + return fmt.Errorf("Release tag needed to delete attachment") + } + + if !ctx.Bool("confirm") { + fmt.Println("Are you sure? Please confirm with -y or --confirm.") + return nil + } + + release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client) + if err != nil { + return err + } + + existing, _, err := client.ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{ + ListOptions: gitea.ListOptions{Page: -1}, + }) + if err != nil { + return err + } + + for _, name := range ctx.Args().Slice()[1:] { + var attachment *gitea.Attachment + for _, a := range existing { + if a.Name == name { + attachment = a + } + } + if attachment == nil { + return fmt.Errorf("Release does not have attachment named '%s'", name) + } + + _, err = client.DeleteReleaseAttachment(ctx.Owner, ctx.Repo, release.ID, attachment.ID) + if err != nil { + return err + } + } + + return nil +} + +func getReleaseAttachmentByName(owner, repo string, release int64, name string, client *gitea.Client) (*gitea.Attachment, error) { + al, _, err := client.ListReleaseAttachments(owner, repo, release, gitea.ListReleaseAttachmentsOptions{ + ListOptions: gitea.ListOptions{Page: -1}, + }) + if err != nil { + return nil, err + } + if len(al) == 0 { + return nil, fmt.Errorf("Release does not have any attachments") + } + for _, a := range al { + if a.Name == name { + return a, nil + } + } + return nil, fmt.Errorf("Attachment does not exist") +} diff --git a/cmd/attachments/list.go b/cmd/attachments/list.go new file mode 100644 index 0000000..8808763 --- /dev/null +++ b/cmd/attachments/list.go @@ -0,0 +1,74 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package attachments + +import ( + "fmt" + + "code.gitea.io/tea/cmd/flags" + "code.gitea.io/tea/modules/context" + "code.gitea.io/tea/modules/print" + + "code.gitea.io/sdk/gitea" + "github.com/urfave/cli/v2" +) + +// CmdReleaseAttachmentList represents a sub command of release attachment to list release attachments +var CmdReleaseAttachmentList = cli.Command{ + Name: "list", + Aliases: []string{"ls"}, + Usage: "List Release Attachments", + Description: "List Release Attachments", + ArgsUsage: "", // command does not accept arguments + Action: RunReleaseAttachmentList, + Flags: append([]cli.Flag{ + &flags.PaginationPageFlag, + &flags.PaginationLimitFlag, + }, flags.AllDefaultFlags...), +} + +// RunReleaseAttachmentList list release attachments +func RunReleaseAttachmentList(cmd *cli.Context) error { + ctx := context.InitCommand(cmd) + ctx.Ensure(context.CtxRequirement{RemoteRepo: true}) + client := ctx.Login.Client() + + tag := ctx.Args().First() + if len(tag) == 0 { + return fmt.Errorf("Release tag needed to list attachments") + } + + release, err := getReleaseByTag(ctx.Owner, ctx.Repo, tag, client) + if err != nil { + return err + } + + attachments, _, err := ctx.Login.Client().ListReleaseAttachments(ctx.Owner, ctx.Repo, release.ID, gitea.ListReleaseAttachmentsOptions{ + ListOptions: ctx.GetListOptions(), + }) + if err != nil { + return err + } + + print.ReleaseAttachmentsList(attachments, ctx.Output) + return nil +} + +func getReleaseByTag(owner, repo, tag string, client *gitea.Client) (*gitea.Release, error) { + rl, _, err := client.ListReleases(owner, repo, gitea.ListReleasesOptions{ + ListOptions: gitea.ListOptions{Page: -1}, + }) + if err != nil { + return nil, err + } + if len(rl) == 0 { + return nil, fmt.Errorf("Repo does not have any release") + } + for _, r := range rl { + if r.TagName == tag { + return r, nil + } + } + return nil, fmt.Errorf("Release tag does not exist") +} diff --git a/cmd/releases.go b/cmd/releases.go index f19fc08..f0190ed 100644 --- a/cmd/releases.go +++ b/cmd/releases.go @@ -25,6 +25,7 @@ var CmdReleases = cli.Command{ &releases.CmdReleaseCreate, &releases.CmdReleaseDelete, &releases.CmdReleaseEdit, + &CmdReleaseAttachments, }, Flags: flags.AllDefaultFlags, } diff --git a/docs/CLI.md b/docs/CLI.md index 81680c5..b0f88eb 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -789,6 +789,60 @@ Edit one or more releases **--title, -t**="": Change Title +### assets, asset, a + +Manage release assets + +**--login, -l**="": Use a different Gitea Login. Optional + +**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json) + +**--remote, -R**="": Discover Gitea login from remote. Optional + +**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional + +#### list, ls + +List Release Attachments + +**--limit, --lm**="": specify limit of items per page + +**--login, -l**="": Use a different Gitea Login. Optional + +**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json) + +**--page, -p**="": specify page, default is 1 + +**--remote, -R**="": Discover Gitea login from remote. Optional + +**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional + +#### create, c + +Create one or more release attachments + +**--login, -l**="": Use a different Gitea Login. Optional + +**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json) + +**--remote, -R**="": Discover Gitea login from remote. Optional + +**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional + +#### delete, rm + +Delete one or more release attachments + +**--confirm, -y**: Confirm deletion (required) + +**--login, -l**="": Use a different Gitea Login. Optional + +**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json) + +**--remote, -R**="": Discover Gitea login from remote. Optional + +**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional + ## times, time, t Operate on tracked times of a repository's issues & pulls diff --git a/modules/print/attachment.go b/modules/print/attachment.go new file mode 100644 index 0000000..91fe5f3 --- /dev/null +++ b/modules/print/attachment.go @@ -0,0 +1,25 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package print + +import ( + "code.gitea.io/sdk/gitea" +) + +// ReleaseAttachmentsList prints a listing of release attachments +func ReleaseAttachmentsList(attachments []*gitea.Attachment, output string) { + t := tableWithHeader( + "Name", + "Size", + ) + + for _, attachment := range attachments { + t.addRow( + attachment.Name, + formatSize(attachment.Size), + ) + } + + t.print(output) +}