commands/release/upload/upload.go (124 lines of code) (raw):
package upload
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
"github.com/MakeNowJust/heredoc/v2"
"github.com/spf13/cobra"
gitlab "gitlab.com/gitlab-org/api/client-go"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/commands/release/releaseutils"
"gitlab.com/gitlab-org/cli/commands/release/releaseutils/upload"
"gitlab.com/gitlab-org/cli/internal/config"
"gitlab.com/gitlab-org/cli/internal/glrepo"
"gitlab.com/gitlab-org/cli/pkg/iostreams"
)
type UploadOpts struct {
TagName string
AssetLinksAsJson string
AssetLinks []*upload.ReleaseAsset
AssetFiles []*upload.ReleaseFile
IO *iostreams.IOStreams
HTTPClient func() (*gitlab.Client, error)
BaseRepo func() (glrepo.Interface, error)
Config func() (config.Config, error)
}
func NewCmdUpload(f *cmdutils.Factory) *cobra.Command {
opts := &UploadOpts{
IO: f.IO,
Config: f.Config,
}
cmd := &cobra.Command{
Use: "upload <tag> [<files>...]",
Short: "Upload release asset files or links to a GitLab release.",
Long: heredoc.Doc(`Upload release assets to a GitLab release.
Define the display name by appending '#' after the filename.
The link type comes after the display name, like this: 'myfile.tar.gz#My display name#package'
`),
Args: func() cobra.PositionalArgs {
return func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return &cmdutils.FlagError{Err: errors.New("no tag name provided.")}
}
if len(args) < 2 && opts.AssetLinksAsJson == "" {
return cmdutils.FlagError{Err: errors.New("no files specified.")}
}
return nil
}
}(),
Example: heredoc.Doc(`
# Upload a release asset with a display name. 'Type' defaults to 'other'.
$ glab release upload v1.0.1 '/path/to/asset.zip#My display label'
# Upload a release asset with a display name and type.
$ glab release upload v1.0.1 '/path/to/asset.png#My display label#image'
# Upload all assets in a specified folder. 'Type' defaults to 'other'.
$ glab release upload v1.0.1 ./dist/*
# Upload all tarballs in a specified folder. 'Type' defaults to 'other'.
$ glab release upload v1.0.1 ./dist/*.tar.gz
# Upload release assets links specified as JSON string
$ glab release upload v1.0.1 --assets-links='
[
{
"name": "Asset1",
"url":"https://<domain>/some/location/1",
"link_type": "other",
"direct_asset_path": "path/to/file"
}
]'
`),
RunE: func(cmd *cobra.Command, args []string) error {
var err error
opts.HTTPClient = f.HttpClient
opts.BaseRepo = f.BaseRepo
opts.TagName = args[0]
opts.AssetFiles, err = releaseutils.AssetsFromArgs(args[1:])
if err != nil {
return err
}
if opts.AssetFiles == nil && opts.AssetLinksAsJson == "" {
return cmdutils.FlagError{Err: errors.New("no files specified.")}
}
if opts.AssetLinksAsJson != "" {
err := json.Unmarshal([]byte(opts.AssetLinksAsJson), &opts.AssetLinks)
if err != nil {
return fmt.Errorf("failed to parse JSON string: %w", err)
}
}
return uploadRun(opts)
},
}
cmd.Flags().StringVarP(&opts.AssetLinksAsJson, "assets-links", "a", "", "`JSON` string representation of assets links, like: `--assets-links='[{\"name\": \"Asset1\", \"url\":\"https://<domain>/some/location/1\", \"link_type\": \"other\", \"direct_asset_path\": \"path/to/file\"}]'.`")
return cmd
}
func uploadRun(opts *UploadOpts) error {
start := time.Now()
client, err := opts.HTTPClient()
if err != nil {
return err
}
repo, err := opts.BaseRepo()
if err != nil {
return err
}
color := opts.IO.Color()
var resp *gitlab.Response
opts.IO.Logf("%s Validating tag %s=%s %s=%s\n",
color.ProgressIcon(),
color.Blue("repo"), repo.FullName(),
color.Blue("tag"), opts.TagName)
release, resp, err := client.Releases.GetRelease(repo.FullName(), opts.TagName)
if err != nil {
if resp != nil && (resp.StatusCode == http.StatusNotFound || resp.StatusCode == http.StatusForbidden) {
return cmdutils.WrapError(err, "release does not exist. Create a new release with `glab release create "+opts.TagName+"`.")
}
return cmdutils.WrapError(err, "failed to fetch release.")
}
// upload files and create asset links
err = releaseutils.CreateReleaseAssets(opts.IO, client, opts.AssetFiles, opts.AssetLinks, repo.FullName(), release.TagName)
if err != nil {
return cmdutils.WrapError(err, "creating release assets failed.")
}
opts.IO.Logf(color.Bold("%s Upload succeeded after %0.2fs.\n"), color.GreenCheck(), time.Since(start).Seconds())
return nil
}