Merge branch 'main' into 'jmc-remove-stats'

# Conflicts:
#   api/project.go
This commit is contained in:
Jay McCure 2024-04-22 01:54:34 +00:00
commit 124b7a3621
77 changed files with 805 additions and 310 deletions

View File

@ -1,2 +1,2 @@
golang 1.21.5
golang 1.21.9
vale 3.0.7

View File

@ -8,7 +8,7 @@ var GetCommitStatuses = func(client *gitlab.Client, pid interface{}, sha string)
}
opt := &gitlab.GetCommitStatusesOptions{
All: gitlab.Bool(true),
All: gitlab.Ptr(true),
}
statuses, _, err := client.Commits.GetCommitStatuses(pid, sha, opt, nil)

View File

@ -225,7 +225,7 @@ var ListMRNotes = func(client *gitlab.Client, projectID interface{}, mrID int, o
return notes, nil
}
var RebaseMR = func(client *gitlab.Client, projectID interface{}, mrID int, opts gitlab.RequestOptionFunc) error {
var RebaseMR = func(client *gitlab.Client, projectID interface{}, mrID int, opts *gitlab.RebaseMergeRequestOptions) error {
if client == nil {
client = apiClient.Lab()
}

View File

@ -101,7 +101,7 @@ var ListProjectMilestones = func(client *gitlab.Client, projectID interface{}, o
}
var ProjectMilestoneByTitle = func(client *gitlab.Client, projectID interface{}, name string) (*gitlab.Milestone, error) {
opts := &gitlab.ListMilestonesOptions{Title: gitlab.String(name)}
opts := &gitlab.ListMilestonesOptions{Title: gitlab.Ptr(name)}
if client == nil {
client = apiClient.Lab()

View File

@ -127,8 +127,8 @@ var GetLastPipeline = func(client *gitlab.Client, repo string, ref string) (*git
}
l := &gitlab.ListProjectPipelinesOptions{
Ref: gitlab.String(ref),
Sort: gitlab.String("desc"),
Ref: gitlab.Ptr(ref),
Sort: gitlab.Ptr("desc"),
}
l.Page = 1
@ -257,8 +257,8 @@ var GetPipelineFromBranch = func(client *gitlab.Client, ref, repo string) ([]*gi
}
}
l := &gitlab.ListProjectPipelinesOptions{
Ref: gitlab.String(ref),
Sort: gitlab.String("desc"),
Ref: gitlab.Ptr(ref),
Sort: gitlab.Ptr("desc"),
}
l.Page = 1
l.PerPage = 1
@ -381,7 +381,7 @@ var PipelineJobsWithSha = func(client *gitlab.Client, pid interface{}, sha strin
client = apiClient.Lab()
}
pipelines, err := GetPipelines(client, &gitlab.ListProjectPipelinesOptions{
SHA: gitlab.String(sha),
SHA: gitlab.Ptr(sha),
}, pid)
if len(pipelines) == 0 || err != nil {
return nil, nil, err
@ -438,6 +438,14 @@ var CreatePipeline = func(client *gitlab.Client, projectID interface{}, opts *gi
return pipe, err
}
var RunPipelineTrigger = func(client *gitlab.Client, projectID interface{}, opts *gitlab.RunPipelineTriggerOptions) (*gitlab.Pipeline, error) {
if client == nil {
client = apiClient.Lab()
}
pipe, _, err := client.PipelineTriggers.RunPipelineTrigger(projectID, opts)
return pipe, err
}
var DownloadArtifactJob = func(client *gitlab.Client, repo string, ref string, opts *gitlab.DownloadArtifactsFileOptions) (*bytes.Reader, error) {
if client == nil {
client = apiClient.Lab()

View File

@ -7,9 +7,9 @@ var GetProject = func(client *gitlab.Client, projectID interface{}) (*gitlab.Pro
client = apiClient.Lab()
}
opts := &gitlab.GetProjectOptions{
Statistics: gitlab.Bool(false),
License: gitlab.Bool(true),
WithCustomAttributes: gitlab.Bool(true),
Statistics: gitlab.Ptr(false),
License: gitlab.Ptr(true),
WithCustomAttributes: gitlab.Ptr(true),
}
project, _, err := client.Projects.GetProject(projectID, opts)
if err != nil {

View File

@ -19,7 +19,7 @@ var CurrentUser = func(client *gitlab.Client) (*gitlab.User, error) {
}
var UserByName = func(client *gitlab.Client, name string) (*gitlab.User, error) {
opts := &gitlab.ListUsersOptions{Username: gitlab.String(name)}
opts := &gitlab.ListUsersOptions{Username: gitlab.Ptr(name)}
if client == nil {
client = apiClient.Lab()
@ -65,7 +65,7 @@ var CreatePersonalAccessTokenForCurrentUser = func(client *gitlab.Client, name s
}
expiresAtISO := gitlab.ISOTime(expiresAt)
options := &gitlab.CreatePersonalAccessTokenForCurrentUserOptions{
Name: gitlab.String(name),
Name: gitlab.Ptr(name),
Scopes: &scopes,
ExpiresAt: &expiresAtISO,
}

View File

@ -38,7 +38,7 @@ func NewCmdGenerate(f *cmdutils.Factory) *cobra.Command {
// Set the version
if s, _ := cmd.Flags().GetString("version"); s != "" {
opts.Version = gitlab.String(s)
opts.Version = gitlab.Ptr(s)
} else {
tags, err := git.ListTags()
if err != nil {
@ -53,12 +53,12 @@ func NewCmdGenerate(f *cmdutils.Factory) *cobra.Command {
if err != nil {
return fmt.Errorf("failed to determine version from git describe: %w..", err)
}
opts.Version = gitlab.String(version)
opts.Version = gitlab.Ptr(version)
}
// Set the config file
if s, _ := cmd.Flags().GetString("config-file"); s != "" {
opts.ConfigFile = gitlab.String(s)
opts.ConfigFile = gitlab.Ptr(s)
}
// Set the date
@ -74,17 +74,17 @@ func NewCmdGenerate(f *cmdutils.Factory) *cobra.Command {
// Set the "from" attribute
if s, _ := cmd.Flags().GetString("from"); s != "" {
opts.From = gitlab.String(s)
opts.From = gitlab.Ptr(s)
}
// Set the "to" attribute
if s, _ := cmd.Flags().GetString("to"); s != "" {
opts.To = gitlab.String(s)
opts.To = gitlab.Ptr(s)
}
// Set the trailer
if s, _ := cmd.Flags().GetString("trailer"); s != "" {
opts.Trailer = gitlab.String(s)
opts.Trailer = gitlab.Ptr(s)
}
project, err := repo.Project(apiClient)

View File

@ -14,6 +14,7 @@ import (
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/internal/config"
"gitlab.com/gitlab-org/cli/pkg/utils"
)
func ensurePathIsCreated(filename string) error {
@ -28,15 +29,6 @@ func ensurePathIsCreated(filename string) error {
return nil
}
func sanitizeAssetName(asset string) string {
if !strings.HasPrefix(asset, "/") {
// Prefix the asset with "/" ensures that filepath.Clean removes all `/..`
// See rule 4 of filepath.Clean for more information: https://pkg.go.dev/path/filepath#Clean
asset = "/" + asset
}
return filepath.Clean(asset)
}
func NewCmdRun(f *cmdutils.Factory) *cobra.Command {
jobArtifactCmd := &cobra.Command{
Use: "artifact <refName> <jobName> [flags]",
@ -83,7 +75,7 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command {
}
for _, v := range zipReader.File {
sanitizedAssetName := sanitizeAssetName(v.Name)
sanitizedAssetName := utils.SanitizePathName(v.Name)
destDir, err := filepath.Abs(path)
if err != nil {

View File

@ -10,9 +10,10 @@ import (
pipeListCmd "gitlab.com/gitlab-org/cli/commands/ci/list"
pipeRetryCmd "gitlab.com/gitlab-org/cli/commands/ci/retry"
pipeRunCmd "gitlab.com/gitlab-org/cli/commands/ci/run"
pipeRunTrigCmd "gitlab.com/gitlab-org/cli/commands/ci/run_trig"
pipeStatusCmd "gitlab.com/gitlab-org/cli/commands/ci/status"
ciTraceCmd "gitlab.com/gitlab-org/cli/commands/ci/trace"
pipeTriggerCmd "gitlab.com/gitlab-org/cli/commands/ci/trigger"
jobPlayCmd "gitlab.com/gitlab-org/cli/commands/ci/trigger"
ciViewCmd "gitlab.com/gitlab-org/cli/commands/ci/view"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
@ -38,7 +39,8 @@ func NewCmdCI(f *cmdutils.Factory) *cobra.Command {
ciCmd.AddCommand(pipeStatusCmd.NewCmdStatus(f))
ciCmd.AddCommand(pipeRetryCmd.NewCmdRetry(f))
ciCmd.AddCommand(pipeRunCmd.NewCmdRun(f))
ciCmd.AddCommand(pipeTriggerCmd.NewCmdTrigger(f))
ciCmd.AddCommand(jobPlayCmd.NewCmdTrigger(f))
ciCmd.AddCommand(pipeRunTrigCmd.NewCmdRunTrig(f))
ciCmd.AddCommand(jobArtifactCmd.NewCmdRun(f))
ciCmd.AddCommand(pipeGetCmd.NewCmdGet(f))
ciCmd.AddCommand(ciConfigCmd.NewCmdConfig(f))

View File

@ -9,6 +9,7 @@ import (
"sync"
"time"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/internal/glrepo"
"gitlab.com/gitlab-org/cli/pkg/git"
"gitlab.com/gitlab-org/cli/pkg/iostreams"
@ -179,6 +180,27 @@ func getPipelineId(inputs *JobInputs, opts *JobOptions) (int, error) {
return pipeline.ID, err
}
func GetDefaultBranch(f *cmdutils.Factory) string {
repo, err := f.BaseRepo()
if err != nil {
return "master"
}
remotes, err := f.Remotes()
if err != nil {
return "master"
}
repoRemote, err := remotes.FindByRepo(repo.RepoOwner(), repo.RepoName())
if err != nil {
return "master"
}
branch, _ := git.GetDefaultBranch(repoRemote.Name)
return branch
}
func getBranch(branch string, opts *JobOptions) (string, error) {
if branch != "" {
return branch, nil

View File

@ -135,15 +135,15 @@ func optsFromFlags(flags *pflag.FlagSet) *gitlab.ListProjectPipelinesOptions {
olderThanDuration, _ := flags.GetDuration(FlagOlderThan)
if source != "" {
opts.Source = gitlab.String(source)
opts.Source = gitlab.Ptr(source)
}
if status != "" {
opts.Status = gitlab.BuildState(gitlab.BuildStateValue(status))
opts.Status = gitlab.Ptr(gitlab.BuildStateValue(status))
}
if olderThanDuration != 0 {
opts.UpdatedBefore = gitlab.Time(time.Now().Add(-olderThanDuration))
opts.UpdatedBefore = gitlab.Ptr(time.Now().Add(-olderThanDuration))
}
return opts

View File

@ -338,7 +338,7 @@ func TestOptsFromFlags(t *testing.T) {
opts := optsFromFlags(flags)
assert.Nil(t, opts.Source)
assert.Equal(t, opts.Status, gitlab.BuildState("success"))
assert.Equal(t, opts.Status, gitlab.Ptr(gitlab.BuildStateValue("success")))
lowerTimeBoundary := time.Now().Add(-1 * 24 * time.Hour).Add(-5 * time.Second)
upperTimeBoundary := time.Now().Add(-1 * 24 * time.Hour).Add(5 * time.Second)

View File

@ -9,6 +9,7 @@ import (
"github.com/xanzy/go-gitlab"
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/commands/mr/mrutils"
"gitlab.com/gitlab-org/cli/pkg/git"
"gitlab.com/gitlab-org/cli/pkg/tableprinter"
@ -63,7 +64,24 @@ func NewCmdGet(f *cmdutils.Factory) *cobra.Command {
if err != nil {
return err
}
pipelineId = commit.LastPipeline.ID
// The latest commit on the branch won't work with a merged
// result pipeline
if commit.LastPipeline == nil {
mr, _, err := mrutils.MRFromArgs(f, args, "any")
if err != nil {
return err
}
if mr.HeadPipeline == nil {
return fmt.Errorf("no pipeline found. It might not exist yet. If this problem continues, check your pipeline configuration.")
} else {
pipelineId = mr.HeadPipeline.ID
}
} else {
pipelineId = commit.LastPipeline.ID
}
}
pipeline, err := api.GetPipeline(apiClient, pipelineId, nil, repo.FullName())

View File

@ -392,6 +392,88 @@ updated: 2023-10-10 00:00:00 +0000 UTC
# Variables:
No variables found in pipeline.
`,
},
{
name: "when there is a merged result pipeline and no commit pipeline",
args: "-b=main",
httpMocks: []httpMock{
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/123",
http.StatusOK,
`{
"id": 123,
"iid": 123,
"project_id": 5,
"status": "pending",
"source": "push",
"ref": "main",
"sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
"user": {
"username": "test"
},
"yaml_errors": "-",
"created_at": "2023-10-10T00:00:00Z",
"started_at": "2023-10-10T00:00:00Z",
"updated_at": "2023-10-10T00:00:00Z"
}`,
InlineBody,
},
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/pipelines/123/jobs?per_page=100",
http.StatusOK,
`[]`,
InlineBody,
},
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/merge_requests/1",
http.StatusOK,
`{
"head_pipeline": {
"id": 123
}
}`,
InlineBody,
},
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/merge_requests?per_page=30&source_branch=main",
http.StatusOK,
`[
{
"iid": 1
}
]`,
InlineBody,
},
{
http.MethodGet,
"/api/v4/projects/OWNER%2FREPO/repository/commits/main",
http.StatusOK,
`{
"last_pipeline": null
}`,
InlineBody,
},
},
expectedOut: `# Pipeline:
id: 123
status: pending
source: push
ref: main
sha: 0ff3ae198f8601a285adcf5c0fff204ee6fba5fd
tag: false
yaml Errors: -
user: test
created: 2023-10-10 00:00:00 +0000 UTC
started: 2023-10-10 00:00:00 +0000 UTC
updated: 2023-10-10 00:00:00 +0000 UTC
# Jobs:
`,
},
{

File diff suppressed because one or more lines are too long

View File

@ -47,14 +47,14 @@ func NewCmdList(f *cmdutils.Factory) *cobra.Command {
l.PerPage = 30
if m, _ := cmd.Flags().GetString("status"); m != "" {
l.Status = gitlab.BuildState(gitlab.BuildStateValue(m))
l.Status = gitlab.Ptr(gitlab.BuildStateValue(m))
titleQualifier = m
}
if m, _ := cmd.Flags().GetString("orderBy"); m != "" {
l.OrderBy = gitlab.String(m)
l.OrderBy = gitlab.Ptr(m)
}
if m, _ := cmd.Flags().GetString("sort"); m != "" {
l.Sort = gitlab.String(m)
l.Sort = gitlab.Ptr(m)
}
if p, _ := cmd.Flags().GetInt("page"); p != 0 {
l.Page = p

View File

@ -7,8 +7,8 @@ import (
"strings"
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/ci/ciutils"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/pkg/git"
"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"
@ -22,27 +22,6 @@ var (
var envVariables = []string{}
func getDefaultBranch(f *cmdutils.Factory) string {
repo, err := f.BaseRepo()
if err != nil {
return "master"
}
remotes, err := f.Remotes()
if err != nil {
return "master"
}
repoRemote, err := remotes.FindByRepo(repo.RepoOwner(), repo.RepoName())
if err != nil {
return "master"
}
branch, _ := git.GetDefaultBranch(repoRemote.Name)
return branch
}
func parseVarArg(s string) (*gitlab.PipelineVariableOptions, error) {
// From https://pkg.go.dev/strings#Split:
//
@ -161,13 +140,13 @@ func NewCmdRun(f *cmdutils.Factory) *cobra.Command {
return err
}
if branch != "" {
c.Ref = gitlab.String(branch)
c.Ref = gitlab.Ptr(branch)
} else if currentBranch, err := f.Branch(); err == nil {
c.Ref = gitlab.String(currentBranch)
c.Ref = gitlab.Ptr(currentBranch)
} else {
// `ci run` is running out of a git repo
fmt.Fprintln(f.IO.StdOut, "not in a git repository, using repository argument")
c.Ref = gitlab.String(getDefaultBranch(f))
c.Ref = gitlab.Ptr(ciutils.GetDefaultBranch(f))
}
pipe, err := api.CreatePipeline(apiClient, repo.FullName(), c)

View File

@ -0,0 +1,115 @@
package run_trig
import (
"errors"
"fmt"
"os"
"strings"
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/ci/ciutils"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"
"github.com/xanzy/go-gitlab"
)
var envVariables = []string{}
func parseVarArg(s string) (key string, val string, err error) {
// From https://pkg.go.dev/strings#Split:
//
// > If s does not contain sep and sep is not empty,
// > Split returns a slice of length 1 whose only element is s.
//
// Therefore, the function will always return a slice of min length 1.
v := strings.SplitN(s, ":", 2)
if len(v) == 1 {
return "", "", fmt.Errorf("invalid argument structure")
}
return v[0], v[1], nil
}
func NewCmdRunTrig(f *cmdutils.Factory) *cobra.Command {
pipelineRunCmd := &cobra.Command{
Use: "run-trig [flags]",
Short: `Run a CI/CD pipeline trigger`,
Aliases: []string{"run-trig"},
Example: heredoc.Doc(`
glab ci run-trig -t xxxx
glab ci run-trig -t xxxx -b main
glab ci run-trig -t xxxx -b main --variables key1:val1
glab ci run-trig -t xxxx -b main --variables key1:val1,key2:val2
glab ci run-trig -t xxxx -b main --variables key1:val1 --variables key2:val2
`),
Long: ``,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
var err error
apiClient, err := f.HttpClient()
if err != nil {
return err
}
repo, err := f.BaseRepo()
if err != nil {
return err
}
c := &gitlab.RunPipelineTriggerOptions{
Variables: make(map[string]string),
}
if customPipelineVars, _ := cmd.Flags().GetStringSlice("variables"); len(customPipelineVars) > 0 {
for _, v := range customPipelineVars {
key, val, err := parseVarArg(v)
if err != nil {
return fmt.Errorf("parsing pipeline variable expected format KEY:VALUE: %w", err)
}
c.Variables[key] = val
}
}
branch, err := cmd.Flags().GetString("branch")
if err != nil {
return err
}
if branch != "" {
c.Ref = gitlab.Ptr(branch)
} else if currentBranch, err := f.Branch(); err == nil {
c.Ref = gitlab.Ptr(currentBranch)
} else {
// `ci run-trig` is running out of a git repo
fmt.Fprintln(f.IO.StdOut, "not in a git repository, using repository argument")
c.Ref = gitlab.Ptr(ciutils.GetDefaultBranch(f))
}
token, err := cmd.Flags().GetString("token")
if err != nil {
return err
}
if token == "" {
token = os.Getenv("CI_JOB_TOKEN")
}
if token == "" {
return errors.New("--token parameter can be omitted only if CI_JOB_TOKEN environment variable is set")
}
c.Token = &token
pipe, err := api.RunPipelineTrigger(apiClient, repo.FullName(), c)
if err != nil {
return err
}
fmt.Fprintln(f.IO.StdOut, "Created pipeline (id:", pipe.ID, "), status:", pipe.Status, ", ref:", pipe.Ref, ", weburl: ", pipe.WebURL, ")")
return nil
},
}
pipelineRunCmd.Flags().StringP("token", "t", "", "Pipeline trigger token (can be omitted only if CI_JOB_TOKEN environment variable is set)")
pipelineRunCmd.Flags().StringP("branch", "b", "", "Create pipeline on branch/ref <string>")
pipelineRunCmd.Flags().StringSliceVarP(&envVariables, "variables", "", []string{}, "Pass variables to pipeline in format <key>:<value>")
return pipelineRunCmd
}

View File

@ -0,0 +1,116 @@
package run_trig
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"testing"
"gitlab.com/gitlab-org/cli/commands/cmdtest"
"github.com/stretchr/testify/assert"
"gitlab.com/gitlab-org/cli/pkg/httpmock"
"gitlab.com/gitlab-org/cli/test"
)
type ResponseJSON struct {
Token string `json:"token"`
Ref string `json:"ref"`
}
func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, error) {
ios, _, stdout, stderr := cmdtest.InitIOStreams(isTTY, "")
factory := cmdtest.InitFactory(ios, rt)
factory.Branch = func() (string, error) {
return "custom-branch-123", nil
}
_, _ = factory.HttpClient()
cmd := NewCmdRunTrig(factory)
return cmdtest.ExecuteCommand(cmd, cli, stdout, stderr)
}
func TestCIRun(t *testing.T) {
tests := []struct {
name string
cli string
ciJobToken string
expectedPOSTBody string
expectedOut string
}{
{
name: "when running `ci run-trig` without branch parameter, defaults to current branch",
cli: "-t foobar",
ciJobToken: "",
expectedPOSTBody: fmt.Sprintf(`"ref":"%s"`, "custom-branch-123"),
expectedOut: fmt.Sprintf("Created pipeline (id: 123 ), status: created , ref: %s , weburl: https://gitlab.com/OWNER/REPO/-/pipelines/123 )\n", "custom-branch-123"),
},
{
name: "when running `ci run-trig` with branch parameter, run CI at branch",
cli: "-t foobar -b ci-cd-improvement-399",
ciJobToken: "",
expectedPOSTBody: `"ref":"ci-cd-improvement-399"`,
expectedOut: "Created pipeline (id: 123 ), status: created , ref: ci-cd-improvement-399 , weburl: https://gitlab.com/OWNER/REPO/-/pipelines/123 )\n",
},
{
name: "when running `ci run-trig` without any parameter, takes trigger token from env variable",
cli: "",
ciJobToken: "foobar",
expectedPOSTBody: fmt.Sprintf(`"ref":"%s"`, "custom-branch-123"),
expectedOut: fmt.Sprintf("Created pipeline (id: 123 ), status: created , ref: %s , weburl: https://gitlab.com/OWNER/REPO/-/pipelines/123 )\n", "custom-branch-123"),
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
fakeHTTP := &httpmock.Mocker{
MatchURL: httpmock.PathAndQuerystring,
}
defer fakeHTTP.Verify(t)
initialEnvValue := os.Getenv("CI_JOB_TOKEN")
os.Setenv("CI_JOB_TOKEN", tc.ciJobToken)
defer os.Setenv("CI_JOB_TOKEN", initialEnvValue)
fakeHTTP.RegisterResponder(http.MethodPost, "/api/v4/projects/OWNER/REPO/trigger/pipeline",
func(req *http.Request) (*http.Response, error) {
rb, _ := io.ReadAll(req.Body)
var response ResponseJSON
err := json.Unmarshal(rb, &response)
if err != nil {
fmt.Printf("Error when parsing response body %s\n", rb)
}
if response.Token != "foobar" {
fmt.Printf("Invalid token %s\n", rb)
}
// ensure CLI runs CI on correct branch
assert.Contains(t, string(rb), tc.expectedPOSTBody)
resp, _ := httpmock.NewStringResponse(http.StatusOK, fmt.Sprintf(`{
"id": 123,
"iid": 123,
"project_id": 3,
"status": "created",
"ref": "%s",
"web_url": "https://gitlab.com/OWNER/REPO/-/pipelines/123"}`, response.Ref))(req)
return resp, nil
},
)
output, _ := runCommand(fakeHTTP, false, tc.cli)
out := output.String()
assert.Equal(t, tc.expectedOut, out)
assert.Empty(t, output.Stderr())
})
}
}

View File

@ -162,6 +162,9 @@ func InitFactory(ios *iostreams.IOStreams, rt http.RoundTripper) *cmdutils.Facto
BaseRepo: func() (glrepo.Interface, error) {
return glrepo.New("OWNER", "REPO"), nil
},
Branch: func() (string, error) {
return "main", nil
},
}
}

View File

@ -183,8 +183,8 @@ func MilestonesPrompt(response *int, apiClient *gitlab.Client, repoRemote *glrep
milestoneMap := map[string]int{}
lOpts := &api.ListMilestonesOptions{
IncludeParentMilestones: gitlab.Bool(true),
State: gitlab.String("active"),
IncludeParentMilestones: gitlab.Ptr(true),
State: gitlab.Ptr("active"),
PerPage: 100,
}
milestones, err := api.ListAllMilestones(apiClient, repoRemote.FullName(), lOpts)

View File

@ -19,13 +19,13 @@ func NewCmdConfig(f *cmdutils.Factory) *cobra.Command {
Current respected settings:
- token: Your GitLab access token, defaults to environment variables
- token: your GitLab access token, defaults to environment variables
- host: if unset, defaults to %[1]shttps://gitlab.com%[1]s
- browser: if unset, defaults to environment variables
- editor: if unset, defaults to environment variables
- visual: alternative for editor. If unset, defaults to environment variables
- glamour_style: Your desired Markdown renderer style. Options are dark, light, notty. Custom styles are allowed using [glamour](https://github.com/charmbracelet/glamour#styles)
- glab_pager: Your desired pager command to use (e.g. less -R)
- browser: if unset, default browser is used. Override with environment variable $BROWSER
- editor: if unset, default editor is used. Override with environment variable $EDITOR
- visual: takes precedence over editor. If unset, default editor is used. Override with environment variable $VISUAL
- glamour_style: your desired Markdown renderer style. Options are dark, light, notty. Custom styles are allowed using [glamour](https://github.com/charmbracelet/glamour#styles)
- glab_pager: your desired pager command to use (e.g. less -R)
- check_update: if true, notifies of any available updates to glab. Defaults to true
- display_hyperlinks: if true, and using a TTY, outputs hyperlinks for issues and MR lists. Defaults to false
`, "`"),

View File

@ -54,7 +54,7 @@ func NewCmdClose(f *cmdutils.Factory, issueType issuable.IssueType) *cobra.Comma
}
l := &gitlab.UpdateIssueOptions{}
l.StateEvent = gitlab.String("close")
l.StateEvent = gitlab.Ptr("close")
c := f.IO.Color()

View File

@ -53,6 +53,7 @@ type ListOptions struct {
ListType string
TitleQualifier string
OutputFormat string
Output string
IO *iostreams.IOStreams
BaseRepo func() (glrepo.Interface, error)
@ -138,10 +139,12 @@ func NewCmdList(f *cmdutils.Factory, runE func(opts *ListOptions) error, issueTy
issueListCmd.Flags().BoolVarP(&opts.All, "all", "A", false, fmt.Sprintf("Get all %ss", issueType))
issueListCmd.Flags().BoolVarP(&opts.Closed, "closed", "c", false, fmt.Sprintf("Get only closed %ss", issueType))
issueListCmd.Flags().BoolVarP(&opts.Confidential, "confidential", "C", false, fmt.Sprintf("Filter by confidential %ss", issueType))
issueListCmd.Flags().StringVarP(&opts.OutputFormat, "output", "F", "details", "One of 'details', 'ids', 'urls' or 'json'")
issueListCmd.Flags().StringVarP(&opts.OutputFormat, "output-format", "F", "details", "One of 'details', 'ids', 'urls'")
issueListCmd.Flags().StringVarP(&opts.Output, "output", "O", "text", "One of 'text' or 'json'")
issueListCmd.Flags().IntVarP(&opts.Page, "page", "p", 1, "Page number")
issueListCmd.Flags().IntVarP(&opts.PerPage, "per-page", "P", 30, "Number of items to list per page.")
issueListCmd.PersistentFlags().StringP("group", "g", "", "Select a group/subgroup. This option is ignored if a repo argument is set.")
issueListCmd.MarkFlagsMutuallyExclusive("output", "output-format")
if issueType == issuable.TypeIssue {
issueListCmd.Flags().StringVarP(&opts.IssueType, "issue-type", "t", "", "Filter issue by its type {issue|incident|test_case}")
@ -170,8 +173,8 @@ func listRun(opts *ListOptions) error {
}
listOpts := &gitlab.ListProjectIssuesOptions{
State: gitlab.String(opts.State),
In: gitlab.String(opts.In),
State: gitlab.Ptr(opts.State),
In: gitlab.Ptr(opts.In),
}
listOpts.Page = 1
listOpts.PerPage = 30
@ -184,7 +187,7 @@ func listRun(opts *ListOptions) error {
}
opts.Assignee = u.Username
}
listOpts.AssigneeUsername = gitlab.String(opts.Assignee)
listOpts.AssigneeUsername = gitlab.Ptr(opts.Assignee)
}
if len(opts.NotAssignee) != 0 {
u, err := api.UsersByNames(apiClient, opts.NotAssignee)
@ -198,7 +201,7 @@ func listRun(opts *ListOptions) error {
if err != nil {
return err
}
listOpts.AuthorID = gitlab.Int(u.ID)
listOpts.AuthorID = gitlab.Ptr(u.ID)
}
if len(opts.NotAuthor) != 0 {
u, err := api.UsersByNames(apiClient, opts.NotAuthor)
@ -208,23 +211,23 @@ func listRun(opts *ListOptions) error {
listOpts.NotAuthorID = cmdutils.IDsFromUsers(u)
}
if opts.Search != "" {
listOpts.Search = gitlab.String(opts.Search)
listOpts.Search = gitlab.Ptr(opts.Search)
opts.ListType = "search"
}
if len(opts.Labels) != 0 {
listOpts.Labels = (*gitlab.Labels)(&opts.Labels)
listOpts.Labels = (*gitlab.LabelOptions)(&opts.Labels)
opts.ListType = "search"
}
if len(opts.NotLabels) != 0 {
listOpts.NotLabels = (*gitlab.Labels)(&opts.NotLabels)
listOpts.NotLabels = (*gitlab.LabelOptions)(&opts.NotLabels)
opts.ListType = "search"
}
if opts.Milestone != "" {
listOpts.Milestone = gitlab.String(opts.Milestone)
listOpts.Milestone = gitlab.Ptr(opts.Milestone)
opts.ListType = "search"
}
if opts.Confidential {
listOpts.Confidential = gitlab.Bool(opts.Confidential)
listOpts.Confidential = gitlab.Ptr(opts.Confidential)
opts.ListType = "search"
}
if opts.Page != 0 {
@ -238,7 +241,7 @@ func listRun(opts *ListOptions) error {
issueType := "issue"
if opts.IssueType != "" {
listOpts.IssueType = gitlab.String(opts.IssueType)
listOpts.IssueType = gitlab.Ptr(opts.IssueType)
opts.ListType = "search"
issueType = opts.IssueType
}
@ -263,7 +266,7 @@ func listRun(opts *ListOptions) error {
title.ListActionType = opts.ListType
title.CurrentPageTotal = len(issues)
if opts.OutputFormat == "json" {
if opts.Output == "json" {
issueListJSON, _ := json.Marshal(issues)
fmt.Fprintln(opts.IO.StdOut, string(issueListJSON))
return nil

View File

@ -359,7 +359,7 @@ func TestIssueListJSON(t *testing.T) {
fakeHTTP.RegisterResponder(http.MethodGet, "/projects/OWNER/REPO/issues",
httpmock.NewFileResponse(http.StatusOK, "./testdata/issueListFull.json"))
output, err := runCommand("issue", fakeHTTP, true, "-F json", nil, "")
output, err := runCommand("issue", fakeHTTP, true, "--output json", nil, "")
if err != nil {
t.Errorf("error running command `issue list -F json`: %v", err)
}
@ -378,3 +378,10 @@ func TestIssueListJSON(t *testing.T) {
assert.JSONEq(t, expectedOut, output.String())
assert.Empty(t, output.Stderr())
}
func TestIssueListMutualOutputFlags(t *testing.T) {
_, err := runCommand("issue", nil, true, "--output json --output-format ids", nil, "")
assert.NotNil(t, err)
assert.EqualError(t, err, "if any flags in the group [output output-format] are set none of the others can be; [output output-format] were all set")
}

View File

@ -16,7 +16,7 @@
"label_details": null,
"subscribed": false,
"closed_by": null,
"labels":"",
"labels":[],
"milestone": null,
"assignees":
[],

View File

@ -64,7 +64,7 @@ func NewCmdReopen(f *cmdutils.Factory, issueType issuable.IssueType) *cobra.Comm
}
l := &gitlab.UpdateIssueOptions{}
l.StateEvent = gitlab.String("reopen")
l.StateEvent = gitlab.Ptr("reopen")
for _, issue := range issues {
valid, msg := issuable.ValidateIncidentCmd(issueType, "reopen", issue)

View File

@ -95,7 +95,7 @@ func NewCmdView(f *cmdutils.Factory, issueType issuable.IssueType) *cobra.Comman
if opts.ShowComments {
l := &gitlab.ListIssueNotesOptions{
Sort: gitlab.String("asc"),
Sort: gitlab.Ptr("asc"),
}
if opts.CommentPageNumber != 0 {
l.Page = opts.CommentPageNumber

View File

@ -46,7 +46,7 @@ func NewCmdCreate(f *cmdutils.Factory) *cobra.Command {
}
opts := &gitlab.CreateIssueBoardOptions{
Name: gitlab.String(boardName),
Name: gitlab.Ptr(boardName),
}
fmt.Fprintln(out, "- Creating board")

View File

@ -205,7 +205,7 @@ func (opts *issueBoardViewOptions) getListProjectIssueOptions() *gitlab.ListProj
}
if len(opts.labels) != 0 {
labels := gitlab.Labels(opts.labels)
labels := gitlab.LabelOptions(opts.labels)
reqOpts.Labels = &labels
}
@ -230,7 +230,7 @@ func (opts *issueBoardViewOptions) getListGroupIssueOptions() *gitlab.ListGroupI
}
if len(opts.labels) != 0 {
labels := gitlab.Labels(opts.labels)
labels := gitlab.LabelOptions(opts.labels)
reqOpts.Labels = &labels
}

View File

@ -43,7 +43,7 @@ func Test_issueBoardViewOptions_getListProjectIssueOptions(t *testing.T) {
WithLabelDetails: &withLabelDetails,
AssigneeUsername: &user,
Milestone: &milestone,
Labels: &gitlab.Labels{"a", "b", "c"},
Labels: &gitlab.LabelOptions{"a", "b", "c"},
State: &state,
},
},
@ -98,7 +98,7 @@ func Test_issueBoardViewOptions_getListGroupIssueOptions(t *testing.T) {
WithLabelDetails: &withLabelDetails,
AssigneeUsername: &user,
Milestone: &milestone,
Labels: &gitlab.Labels{"a", "b", "c"},
Labels: &gitlab.LabelOptions{"a", "b", "c"},
State: &state,
},
},

View File

@ -342,20 +342,20 @@ func createRun(opts *CreateOpts) error {
}
if action == cmdutils.SubmitAction {
issueCreateOpts.Title = gitlab.String(opts.Title)
issueCreateOpts.Labels = (*gitlab.Labels)(&opts.Labels)
issueCreateOpts.Title = gitlab.Ptr(opts.Title)
issueCreateOpts.Labels = (*gitlab.LabelOptions)(&opts.Labels)
issueCreateOpts.Description = &opts.Description
if opts.IsConfidential {
issueCreateOpts.Confidential = gitlab.Bool(opts.IsConfidential)
issueCreateOpts.Confidential = gitlab.Ptr(opts.IsConfidential)
}
if opts.Weight != 0 {
issueCreateOpts.Weight = gitlab.Int(opts.Weight)
issueCreateOpts.Weight = gitlab.Ptr(opts.Weight)
}
if opts.LinkedMR != 0 {
issueCreateOpts.MergeRequestToResolveDiscussionsOf = gitlab.Int(opts.LinkedMR)
issueCreateOpts.MergeRequestToResolveDiscussionsOf = gitlab.Ptr(opts.LinkedMR)
}
if opts.Milestone != 0 {
issueCreateOpts.MilestoneID = gitlab.Int(opts.Milestone)
issueCreateOpts.MilestoneID = gitlab.Ptr(opts.Milestone)
}
if len(opts.Assignees) > 0 {
users, err := api.UsersByNames(apiClient, opts.Assignees)
@ -386,8 +386,8 @@ func postCreateActions(apiClient *gitlab.Client, issue *gitlab.Issue, opts *Crea
for _, targetIssueIID := range opts.LinkedIssues {
fmt.Fprintln(opts.IO.StdErr, "- Linking to issue ", targetIssueIID)
issue, _, err = api.LinkIssues(apiClient, repo.FullName(), issue.IID, &gitlab.CreateIssueLinkOptions{
TargetIssueIID: gitlab.String(strconv.Itoa(targetIssueIID)),
LinkType: gitlab.String(opts.IssueLinkType),
TargetIssueIID: gitlab.Ptr(strconv.Itoa(targetIssueIID)),
LinkType: gitlab.Ptr(opts.IssueLinkType),
})
if err != nil {
return err
@ -397,7 +397,7 @@ func postCreateActions(apiClient *gitlab.Client, issue *gitlab.Issue, opts *Crea
if opts.TimeEstimate != "" {
fmt.Fprintln(opts.IO.StdErr, "- Adding time estimate ", opts.TimeEstimate)
_, err := api.SetIssueTimeEstimate(apiClient, repo.FullName(), issue.IID, &gitlab.SetTimeEstimateOptions{
Duration: gitlab.String(opts.TimeEstimate),
Duration: gitlab.Ptr(opts.TimeEstimate),
})
if err != nil {
return err
@ -406,7 +406,7 @@ func postCreateActions(apiClient *gitlab.Client, issue *gitlab.Issue, opts *Crea
if opts.TimeSpent != "" {
fmt.Fprintln(opts.IO.StdErr, "- Adding time spent ", opts.TimeSpent)
_, err := api.AddIssueTimeSpent(apiClient, repo.FullName(), issue.IID, &gitlab.AddSpentTimeOptions{
Duration: gitlab.String(opts.TimeSpent),
Duration: gitlab.Ptr(opts.TimeSpent),
})
if err != nil {
return err

View File

@ -45,7 +45,7 @@ func Test_IssueCreate_Integration(t *testing.T) {
ID: 1,
IID: 1,
Title: *opts.Title,
Labels: *opts.Labels,
Labels: gitlab.Labels(*opts.Labels),
State: "opened",
Description: *opts.Description,
Weight: *opts.Weight,

View File

@ -70,15 +70,15 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
if m, _ := cmd.Flags().GetString("title"); m != "" {
actions = append(actions, fmt.Sprintf("updated title to %q", m))
l.Title = gitlab.String(m)
l.Title = gitlab.Ptr(m)
}
if m, _ := cmd.Flags().GetBool("lock-discussion"); m {
actions = append(actions, "locked discussion")
l.DiscussionLocked = gitlab.Bool(m)
l.DiscussionLocked = gitlab.Ptr(m)
}
if m, _ := cmd.Flags().GetBool("unlock-discussion"); m {
actions = append(actions, "unlocked dicussion")
l.DiscussionLocked = gitlab.Bool(false)
l.DiscussionLocked = gitlab.Ptr(false)
}
if m, _ := cmd.Flags().GetString("description"); m != "" {
@ -102,30 +102,30 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
return err
}
l.Description = gitlab.String("")
l.Description = gitlab.Ptr("")
err = cmdutils.EditorPrompt(l.Description, "Description", issue.Description, editor)
if err != nil {
return err
}
} else {
l.Description = gitlab.String(m)
l.Description = gitlab.Ptr(m)
}
}
if m, _ := cmd.Flags().GetStringSlice("label"); len(m) != 0 {
actions = append(actions, fmt.Sprintf("added labels %s", strings.Join(m, " ")))
l.AddLabels = (*gitlab.Labels)(&m)
l.AddLabels = (*gitlab.LabelOptions)(&m)
}
if m, _ := cmd.Flags().GetStringSlice("unlabel"); len(m) != 0 {
actions = append(actions, fmt.Sprintf("removed labels %s", strings.Join(m, " ")))
l.RemoveLabels = (*gitlab.Labels)(&m)
l.RemoveLabels = (*gitlab.LabelOptions)(&m)
}
if m, _ := cmd.Flags().GetBool("public"); m {
actions = append(actions, "made public")
l.Confidential = gitlab.Bool(false)
l.Confidential = gitlab.Ptr(false)
}
if m, _ := cmd.Flags().GetBool("confidential"); m {
actions = append(actions, "made confidential")
l.Confidential = gitlab.Bool(true)
l.Confidential = gitlab.Ptr(true)
}
if ok := cmd.Flags().Changed("milestone"); ok {
if m, _ := cmd.Flags().GetString("milestone"); m != "" || m == "0" {
@ -134,11 +134,11 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
return err
}
actions = append(actions, fmt.Sprintf("added milestone %q", m))
l.MilestoneID = gitlab.Int(mID)
l.MilestoneID = gitlab.Ptr(mID)
} else {
// Unassign the Milestone
actions = append(actions, "unassigned milestone")
l.MilestoneID = gitlab.Int(0)
l.MilestoneID = gitlab.Ptr(0)
}
}
if cmd.Flags().Changed("unassign") {

View File

@ -52,7 +52,7 @@ func TestNewCmdUpdate_Integration(t *testing.T) {
testIssue.Description = *opts.Description
}
if opts.AddLabels != nil {
testIssue.Labels = *opts.AddLabels
testIssue.Labels = gitlab.Labels(*opts.AddLabels)
}
return testIssue, nil
}

View File

@ -39,14 +39,14 @@ func NewCmdCreate(f *cmdutils.Factory) *cobra.Command {
l := &gitlab.CreateLabelOptions{}
if s, _ := cmd.Flags().GetString("name"); s != "" {
l.Name = gitlab.String(s)
l.Name = gitlab.Ptr(s)
}
if s, _ := cmd.Flags().GetString("color"); s != "" {
l.Color = gitlab.String(s)
l.Color = gitlab.Ptr(s)
}
if s, _ := cmd.Flags().GetString("description"); s != "" {
l.Description = gitlab.String(s)
l.Description = gitlab.Ptr(s)
}
label, err := api.CreateLabel(apiClient, repo.FullName(), l)
if err != nil {

View File

@ -43,7 +43,7 @@ func NewCmdList(f *cmdutils.Factory) *cobra.Command {
l := &gitlab.ListLabelsOptions{}
l.WithCounts = gitlab.Bool(true)
l.WithCounts = gitlab.Ptr(true)
if p, _ := cmd.Flags().GetInt("page"); p != 0 {
l.Page = p

View File

@ -48,7 +48,7 @@ func NewCmdApprove(f *cmdutils.Factory) *cobra.Command {
opts := &gitlab.ApproveMergeRequestOptions{}
if s, _ := cmd.Flags().GetString("sha"); s != "" {
opts.SHA = gitlab.String(s)
opts.SHA = gitlab.Ptr(s)
}
fmt.Fprintf(f.IO.StdOut, "- Approving Merge Request !%d\n", mr.IID)

View File

@ -6,6 +6,7 @@ import (
"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"
"github.com/xanzy/go-gitlab"
"gitlab.com/gitlab-org/cli/api"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/commands/mr/mrutils"
@ -67,12 +68,24 @@ func NewCmdCheckout(f *cmdutils.Factory) *cobra.Command {
mrCheckoutCfg.branch = mr.SourceBranch
}
mrProject, err := api.GetProject(apiClient, mr.SourceProjectID)
var mrRef string
var mrProject *gitlab.Project
mrProject, err = api.GetProject(apiClient, mr.SourceProjectID)
if err != nil {
return err
// If we don't have access to the source project, let's try the target project
mrProject, err = api.GetProject(apiClient, mr.TargetProjectID)
if err != nil {
return err
} else {
// We found the target project, let's find the ref another way
mrRef = fmt.Sprintf("refs/merge-requests/%d/head", mr.IID)
}
} else {
mrRef = fmt.Sprintf("refs/heads/%s", mr.SourceBranch)
}
mrRef := fmt.Sprintf("refs/heads/%s", mr.SourceBranch)
fetchRefSpec := fmt.Sprintf("%s:%s", mrRef, mrCheckoutCfg.branch)
if err := git.RunCmd([]string{"fetch", mrProject.SSHURLToRepo, fetchRefSpec}); err != nil {
return err

View File

@ -122,6 +122,64 @@ func TestMrCheckout(t *testing.T) {
"git checkout feat-new-mr",
},
},
{
name: "when a valid MR comes from a forked private project",
commandArgs: "123",
branch: "main",
httpMocks: []httpMock{
{
http.MethodGet,
"/api/v4/projects/OWNER/REPO/merge_requests/123",
http.StatusOK,
`{
"id": 123,
"iid": 123,
"project_id": 3,
"source_project_id": 3,
"target_project_id": 4,
"title": "test mr title",
"description": "test mr description",
"allow_collaboration": false,
"state": "opened",
"source_branch":"feat-new-mr"
}`,
},
{
http.MethodGet,
"/api/v4/projects/4",
http.StatusOK,
`{
"id": 4,
"ssh_url_to_repo": "git@gitlab.com:OWNER/REPO.git"
}`,
},
{
http.MethodGet,
"/api/v4/projects/3",
http.StatusNotFound,
`{
"message":"404 Project Not Found"
}`,
},
},
shelloutStubs: []string{
"HEAD branch: master\n",
"\n",
"\n",
heredoc.Doc(`
deadbeef HEAD
deadb00f refs/remotes/upstream/feat-new-mr
deadbeef refs/remotes/origin/feat-new-mr
`),
},
expectedShellouts: []string{
"git fetch git@gitlab.com:OWNER/REPO.git refs/merge-requests/123/head:feat-new-mr",
"git config branch.feat-new-mr.remote git@gitlab.com:OWNER/REPO.git",
"git config branch.feat-new-mr.merge refs/merge-requests/123/head",
"git checkout feat-new-mr",
},
},
{
name: "when a valid MR is checked out using MR id and specifying branch",
commandArgs: "123 --branch foo",

View File

@ -39,7 +39,7 @@ func NewCmdClose(f *cmdutils.Factory) *cobra.Command {
}
l := &gitlab.UpdateMergeRequestOptions{}
l.StateEvent = gitlab.String("close")
l.StateEvent = gitlab.Ptr("close")
for _, mr := range mrs {
if err = mrutils.MRCheckErrors(mr, mrutils.MRCheckErrOptions{
Closed: true,

View File

@ -324,7 +324,7 @@ func createRun(opts *CreateOpts) error {
}
if opts.CopyIssueLabels {
mrCreateOpts.Labels = &issue.Labels
mrCreateOpts.Labels = (*gitlab.LabelOptions)(&issue.Labels)
}
opts.Description += fmt.Sprintf("\n\nCloses #%d", issue.IID)
@ -475,15 +475,15 @@ func createRun(opts *CreateOpts) error {
mrCreateOpts.TargetBranch = &opts.TargetBranch
if opts.AllowCollaboration {
mrCreateOpts.AllowCollaboration = gitlab.Bool(true)
mrCreateOpts.AllowCollaboration = gitlab.Ptr(true)
}
if opts.RemoveSourceBranch {
mrCreateOpts.RemoveSourceBranch = gitlab.Bool(true)
mrCreateOpts.RemoveSourceBranch = gitlab.Ptr(true)
}
if opts.SquashBeforeMerge {
mrCreateOpts.Squash = gitlab.Bool(true)
mrCreateOpts.Squash = gitlab.Ptr(true)
}
if opts.TargetProject != nil {
@ -576,7 +576,7 @@ func createRun(opts *CreateOpts) error {
// This check protects against possibly dereferencing a nil pointer.
if mrCreateOpts.Labels == nil {
mrCreateOpts.Labels = &gitlab.Labels{}
mrCreateOpts.Labels = &gitlab.LabelOptions{}
}
// These actions need to be done here, after the `Add metadata` prompt because
// they are metadata that can be modified by the prompt
@ -599,7 +599,7 @@ func createRun(opts *CreateOpts) error {
}
if opts.Milestone != 0 {
mrCreateOpts.MilestoneID = gitlab.Int(opts.Milestone)
mrCreateOpts.MilestoneID = gitlab.Ptr(opts.Milestone)
}
if action == cmdutils.CancelAction {

View File

@ -92,7 +92,7 @@ func diffRun(opts *DiffOptions) error {
diffOut := &bytes.Buffer{}
for _, diff := range diffs {
// the diffs are not included in the GetMergeRequestDiffVersions so we query for each diff version
diffVersion, _, err := apiClient.MergeRequests.GetSingleMergeRequestDiffVersion(baseRepo.FullName(), mr.IID, diff.ID)
diffVersion, _, err := apiClient.MergeRequests.GetSingleMergeRequestDiffVersion(baseRepo.FullName(), mr.IID, diff.ID, &gitlab.GetSingleMergeRequestDiffVersionOptions{})
if err != nil {
return fmt.Errorf("could not find merge request diff: %w", err)
}

View File

@ -67,8 +67,8 @@ func NewCmdFor(f *cmdutils.Factory) *cobra.Command {
sourceBranch := fmt.Sprintf("%d-%s", issue.IID, utils.ReplaceNonAlphaNumericChars(strings.ToLower(issue.Title), "-"))
lb := &gitlab.CreateBranchOptions{
Branch: gitlab.String(sourceBranch),
Ref: gitlab.String(targetBranch),
Branch: gitlab.Ptr(sourceBranch),
Ref: gitlab.Ptr(targetBranch),
}
_, err = api.CreateBranch(apiClient, repo.FullName(), lb)
@ -77,8 +77,8 @@ func NewCmdFor(f *cmdutils.Factory) *cobra.Command {
numberedBranch := fmt.Sprintf("%d-%s-%d", issue.IID, strings.ReplaceAll(strings.ToLower(issue.Title), " ", "-"), branchCount)
lb = &gitlab.CreateBranchOptions{
Branch: gitlab.String(numberedBranch),
Ref: gitlab.String(targetBranch),
Branch: gitlab.Ptr(numberedBranch),
Ref: gitlab.Ptr(targetBranch),
}
sourceBranch = numberedBranch
_, branchErr = api.CreateBranch(apiClient, repo.FullName(), lb)
@ -102,22 +102,22 @@ func NewCmdFor(f *cmdutils.Factory) *cobra.Command {
mergeLabel, _ := cmd.Flags().GetString("label")
l := &gitlab.CreateMergeRequestOptions{}
l.Title = gitlab.String(mergeTitle)
l.Description = gitlab.String(fmt.Sprintf("Closes #%d", issue.IID))
l.Labels = &gitlab.Labels{mergeLabel}
l.SourceBranch = gitlab.String(sourceBranch)
l.TargetBranch = gitlab.String(targetBranch)
l.Title = gitlab.Ptr(mergeTitle)
l.Description = gitlab.Ptr(fmt.Sprintf("Closes #%d", issue.IID))
l.Labels = &gitlab.LabelOptions{mergeLabel}
l.SourceBranch = gitlab.Ptr(sourceBranch)
l.TargetBranch = gitlab.Ptr(targetBranch)
if milestone, _ := cmd.Flags().GetInt("milestone"); milestone != -1 {
l.MilestoneID = gitlab.Int(milestone)
l.MilestoneID = gitlab.Ptr(milestone)
}
if allowCol, _ := cmd.Flags().GetBool("allow-collaboration"); allowCol {
l.AllowCollaboration = gitlab.Bool(true)
l.AllowCollaboration = gitlab.Ptr(true)
}
if removeSource, _ := cmd.Flags().GetBool("remove-source-branch"); removeSource {
l.RemoveSourceBranch = gitlab.Bool(true)
l.RemoveSourceBranch = gitlab.Ptr(true)
}
if withLables, _ := cmd.Flags().GetBool("with-labels"); withLables {
l.Labels = &issue.Labels
l.Labels = (*gitlab.LabelOptions)(&issue.Labels)
}
if a, _ := cmd.Flags().GetString("assignee"); a != "" {

View File

@ -166,7 +166,7 @@ func listRun(opts *ListOptions) error {
}
l := &gitlab.ListProjectMergeRequestsOptions{
State: gitlab.String(opts.State),
State: gitlab.Ptr(opts.State),
}
jsonOutput := opts.OutputFormat == "json"
if jsonOutput {
@ -182,31 +182,31 @@ func listRun(opts *ListOptions) error {
if err != nil {
return err
}
l.AuthorID = gitlab.Int(u.ID)
l.AuthorID = gitlab.Ptr(u.ID)
opts.ListType = "search"
}
if opts.SourceBranch != "" {
l.SourceBranch = gitlab.String(opts.SourceBranch)
l.SourceBranch = gitlab.Ptr(opts.SourceBranch)
opts.ListType = "search"
}
if opts.TargetBranch != "" {
l.TargetBranch = gitlab.String(opts.TargetBranch)
l.TargetBranch = gitlab.Ptr(opts.TargetBranch)
opts.ListType = "search"
}
if opts.Search != "" {
l.Search = gitlab.String(opts.Search)
l.Search = gitlab.Ptr(opts.Search)
opts.ListType = "search"
}
if len(opts.Labels) > 0 {
l.Labels = (*gitlab.Labels)(&opts.Labels)
l.Labels = (*gitlab.LabelOptions)(&opts.Labels)
opts.ListType = "search"
}
if len(opts.NotLabels) > 0 {
l.NotLabels = (*gitlab.Labels)(&opts.NotLabels)
l.NotLabels = (*gitlab.LabelOptions)(&opts.NotLabels)
opts.ListType = "search"
}
if opts.Milestone != "" {
l.Milestone = gitlab.String(opts.Milestone)
l.Milestone = gitlab.Ptr(opts.Milestone)
opts.ListType = "search"
}
if opts.Page != 0 {
@ -216,12 +216,12 @@ func listRun(opts *ListOptions) error {
l.PerPage = opts.PerPage
}
if opts.Draft {
l.WIP = gitlab.String("yes")
l.WIP = gitlab.Ptr("yes")
opts.ListType = "search"
}
if opts.Mine {
l.Scope = gitlab.String("assigned_to_me")
l.Scope = gitlab.Ptr("assigned_to_me")
opts.ListType = "search"
}

View File

@ -47,7 +47,7 @@
[],
"source_project_id": 29316529,
"target_project_id": 29316529,
"labels": "",
"labels": [],
"label_details": null,
"description": "Closes #1",
"draft": true,
@ -142,7 +142,7 @@
[],
"source_project_id": 29316529,
"target_project_id": 29316529,
"labels": "",
"labels": [],
"label_details": null,
"description": "",
"draft": false,

View File

@ -151,16 +151,16 @@ func NewCmdMerge(f *cmdutils.Factory) *cobra.Command {
mergeOpts := &gitlab.AcceptMergeRequestOptions{}
if opts.MergeCommitMessage != "" {
mergeOpts.MergeCommitMessage = gitlab.String(opts.MergeCommitMessage)
mergeOpts.MergeCommitMessage = gitlab.Ptr(opts.MergeCommitMessage)
}
if opts.SquashMessage != "" {
mergeOpts.SquashCommitMessage = gitlab.String(opts.SquashMessage)
mergeOpts.SquashCommitMessage = gitlab.Ptr(opts.SquashMessage)
}
if opts.SquashBeforeMerge {
mergeOpts.Squash = gitlab.Bool(true)
mergeOpts.Squash = gitlab.Ptr(true)
}
if opts.RemoveSourceBranch {
mergeOpts.ShouldRemoveSourceBranch = gitlab.Bool(true)
mergeOpts.ShouldRemoveSourceBranch = gitlab.Ptr(true)
}
if opts.SetAutoMerge && mr.Pipeline != nil {
if mr.Pipeline.Status == "canceled" || mr.Pipeline.Status == "failed" {
@ -168,10 +168,10 @@ func NewCmdMerge(f *cmdutils.Factory) *cobra.Command {
fmt.Fprintln(f.IO.StdOut, c.FailedIcon(), "Cannot perform merge action")
return cmdutils.SilentError
}
mergeOpts.MergeWhenPipelineSucceeds = gitlab.Bool(true)
mergeOpts.MergeWhenPipelineSucceeds = gitlab.Ptr(true)
}
if opts.SHA != "" {
mergeOpts.SHA = gitlab.String(opts.SHA)
mergeOpts.SHA = gitlab.Ptr(opts.SHA)
}
if opts.RebaseBeforeMerge {
@ -211,7 +211,6 @@ func NewCmdMerge(f *cmdutils.Factory) *cobra.Command {
}
return err
}, retry.Attempts(3), retry.Delay(time.Second*6))
if err != nil {
return err
}

View File

@ -234,14 +234,14 @@ var getMRForBranch = func(apiClient *gitlab.Client, baseRepo glrepo.Interface, a
}
opts := gitlab.ListProjectMergeRequestsOptions{
SourceBranch: gitlab.String(currentBranch),
SourceBranch: gitlab.Ptr(currentBranch),
}
// Set the state value if it is not empty, if it is empty then it will look at all possible
// values, 'any' is also a descriptive keyword used in the source code that is equivalent to
// passing nothing on
if state != "" && state != "any" {
opts.State = gitlab.String(state)
opts.State = gitlab.Ptr(state)
}
mrs, err := api.ListMRs(apiClient, baseRepo.FullName(), &opts)
@ -291,7 +291,7 @@ var getMRForBranch = func(apiClient *gitlab.Client, baseRepo glrepo.Interface, a
return mrMap[pickedMR], nil
}
func RebaseMR(ios *iostreams.IOStreams, apiClient *gitlab.Client, repo glrepo.Interface, mr *gitlab.MergeRequest, rebaseOpts gitlab.RequestOptionFunc) error {
func RebaseMR(ios *iostreams.IOStreams, apiClient *gitlab.Client, repo glrepo.Interface, mr *gitlab.MergeRequest, rebaseOpts *gitlab.RebaseMergeRequestOptions) error {
ios.StartSpinner("Sending rebase request...")
err := api.RebaseMR(apiClient, repo.FullName(), mr.IID, rebaseOpts)
if err != nil {
@ -300,7 +300,7 @@ func RebaseMR(ios *iostreams.IOStreams, apiClient *gitlab.Client, repo glrepo.In
ios.StopSpinner("")
opts := &gitlab.GetMergeRequestsOptions{}
opts.IncludeRebaseInProgress = gitlab.Bool(true)
opts.IncludeRebaseInProgress = gitlab.Ptr(true)
ios.StartSpinner("Checking rebase status...")
errorMSG := ""
i := 0

View File

@ -1,13 +1,11 @@
package rebase
import (
"strconv"
"github.com/MakeNowJust/heredoc"
"github.com/xanzy/go-gitlab"
"gitlab.com/gitlab-org/cli/commands/cmdutils"
"gitlab.com/gitlab-org/cli/commands/mr/mrutils"
"github.com/hashicorp/go-retryablehttp"
"github.com/spf13/cobra"
)
@ -44,18 +42,10 @@ func NewCmdRebase(f *cmdutils.Factory) *cobra.Command {
return err
}
requestOptionFunc := func(req *retryablehttp.Request) error {
if opts.SkipCI {
q := req.URL.Query()
q.Add("skip_ci", strconv.FormatBool(opts.SkipCI))
req.URL.RawQuery = q.Encode()
}
return nil
}
if err = mrutils.RebaseMR(f.IO, apiClient, repo, mr, requestOptionFunc); err != nil {
if err = mrutils.RebaseMR(f.IO, apiClient, repo, mr,
&gitlab.RebaseMergeRequestOptions{
SkipCI: gitlab.Ptr(opts.SkipCI),
}); err != nil {
return err
}

View File

@ -97,7 +97,7 @@ func TestMrRebase(t *testing.T) {
},
{
http.MethodPut,
"/api/v4/projects/OWNER/REPO/merge_requests/123/rebase?skip_ci=true",
"/api/v4/projects/OWNER/REPO/merge_requests/123/rebase",
http.StatusAccepted,
`{ "rebase_in_progress": true }`,
},

View File

@ -36,7 +36,7 @@ func NewCmdReopen(f *cmdutils.Factory) *cobra.Command {
}
l := &gitlab.UpdateMergeRequestOptions{}
l.StateEvent = gitlab.String("reopen")
l.StateEvent = gitlab.Ptr("reopen")
for _, mr := range mrs {
if err = mrutils.MRCheckErrors(mr, mrutils.MRCheckErrOptions{
Opened: true,

View File

@ -116,14 +116,14 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
mergeTitle = strings.TrimSpace(mergeTitle)
}
l.Title = gitlab.String(mergeTitle)
l.Title = gitlab.Ptr(mergeTitle)
if m, _ := cmd.Flags().GetBool("lock-discussion"); m {
actions = append(actions, "locked discussion")
l.DiscussionLocked = gitlab.Bool(m)
l.DiscussionLocked = gitlab.Ptr(m)
}
if m, _ := cmd.Flags().GetBool("unlock-discussion"); m {
actions = append(actions, "unlocked discussion")
l.DiscussionLocked = gitlab.Bool(false)
l.DiscussionLocked = gitlab.Ptr(false)
}
if m, _ := cmd.Flags().GetString("description"); m != "" {
@ -142,27 +142,27 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
return err
}
l.Description = gitlab.String("")
l.Description = gitlab.Ptr("")
err = cmdutils.EditorPrompt(l.Description, "Description", mr.Description, editor)
if err != nil {
return err
}
} else {
l.Description = gitlab.String(m)
l.Description = gitlab.Ptr(m)
}
}
if m, _ := cmd.Flags().GetStringSlice("label"); len(m) != 0 {
actions = append(actions, fmt.Sprintf("added labels %s", strings.Join(m, " ")))
l.AddLabels = (*gitlab.Labels)(&m)
l.AddLabels = (*gitlab.LabelOptions)(&m)
}
if m, _ := cmd.Flags().GetStringSlice("unlabel"); len(m) != 0 {
actions = append(actions, fmt.Sprintf("removed labels %s", strings.Join(m, " ")))
l.RemoveLabels = (*gitlab.Labels)(&m)
l.RemoveLabels = (*gitlab.LabelOptions)(&m)
}
if m, _ := cmd.Flags().GetString("target-branch"); m != "" {
actions = append(actions, fmt.Sprintf("set target branch to %q", m))
l.TargetBranch = gitlab.String(m)
l.TargetBranch = gitlab.Ptr(m)
}
if ok := cmd.Flags().Changed("milestone"); ok {
if m, _ := cmd.Flags().GetString("milestone"); m != "" || m == "0" {
@ -171,11 +171,11 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
return err
}
actions = append(actions, fmt.Sprintf("added milestone %q", m))
l.MilestoneID = gitlab.Int(mID)
l.MilestoneID = gitlab.Ptr(mID)
} else {
// Unassign the Milestone
actions = append(actions, "unassigned milestone")
l.MilestoneID = gitlab.Int(0)
l.MilestoneID = gitlab.Ptr(0)
}
}
if cmd.Flags().Changed("unassign") {
@ -218,7 +218,7 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
actions = append(actions, "enabled removal of source branch on merge")
}
l.RemoveSourceBranch = gitlab.Bool(!mr.ForceRemoveSourceBranch)
l.RemoveSourceBranch = gitlab.Ptr(!mr.ForceRemoveSourceBranch)
}
if squashBeforeMerge, _ := cmd.Flags().GetBool("squash-before-merge"); squashBeforeMerge {
@ -229,7 +229,7 @@ func NewCmdUpdate(f *cmdutils.Factory) *cobra.Command {
actions = append(actions, "enabled squashing of commits before merge")
}
l.Squash = gitlab.Bool(!mr.Squash)
l.Squash = gitlab.Ptr(!mr.Squash)
}
fmt.Fprintf(f.IO.StdOut, "- Updating merge request !%d\n", mr.IID)

View File

@ -52,9 +52,9 @@ func NewCmdView(f *cmdutils.Factory) *cobra.Command {
}
mr, baseRepo, err := mrutils.MRFromArgsWithOpts(f, args, &gitlab.GetMergeRequestsOptions{
IncludeDivergedCommitsCount: gitlab.Bool(true),
RenderHTML: gitlab.Bool(true),
IncludeRebaseInProgress: gitlab.Bool(true),
IncludeDivergedCommitsCount: gitlab.Ptr(true),
RenderHTML: gitlab.Ptr(true),
IncludeRebaseInProgress: gitlab.Ptr(true),
}, "any")
if err != nil {
return err
@ -85,7 +85,7 @@ func NewCmdView(f *cmdutils.Factory) *cobra.Command {
if opts.ShowComments {
l := &gitlab.ListMergeRequestNotesOptions{
Sort: gitlab.String("asc"),
Sort: gitlab.Ptr("asc"),
}
l.Page = opts.CommentPageNumber
l.PerPage = opts.CommentLimit

View File

@ -66,9 +66,9 @@ func NewCmdArchive(f *cmdutils.Factory) *cobra.Command {
}
l := &gitlab.ArchiveOptions{}
l.Format = gitlab.String(format)
l.Format = gitlab.Ptr(format)
if sha, _ := cmd.Flags().GetString("sha"); sha != "" {
l.SHA = gitlab.String(sha)
l.SHA = gitlab.Ptr(sha)
}
ext := *l.Format
archiveName := strings.ReplaceAll(repo.FullName(), "/", "-") + "." + ext

View File

@ -186,26 +186,26 @@ func groupClone(opts *CloneOptions, ctxOpts *ContextOpts) error {
c := opts.IO.Color()
ListGroupProjectOpts := &gitlab.ListGroupProjectsOptions{}
if opts.WithShared {
ListGroupProjectOpts.WithShared = gitlab.Bool(true)
ListGroupProjectOpts.WithShared = gitlab.Ptr(true)
}
if opts.WithMREnabled {
ListGroupProjectOpts.WithMergeRequestsEnabled = gitlab.Bool(true)
ListGroupProjectOpts.WithMergeRequestsEnabled = gitlab.Ptr(true)
}
if opts.WithIssuesEnabled {
ListGroupProjectOpts.WithIssuesEnabled = gitlab.Bool(true)
ListGroupProjectOpts.WithIssuesEnabled = gitlab.Ptr(true)
}
if opts.Owned {
ListGroupProjectOpts.Owned = gitlab.Bool(true)
ListGroupProjectOpts.Owned = gitlab.Ptr(true)
}
if opts.ArchivedSet {
ListGroupProjectOpts.Archived = gitlab.Bool(opts.Archived)
ListGroupProjectOpts.Archived = gitlab.Ptr(opts.Archived)
}
if opts.IncludeSubgroups {
includeSubGroups := true
ListGroupProjectOpts.IncludeSubGroups = &includeSubGroups
}
if opts.Visibility != "" {
ListGroupProjectOpts.Visibility = gitlab.Visibility(gitlab.VisibilityValue(opts.Visibility))
ListGroupProjectOpts.Visibility = gitlab.Ptr(gitlab.VisibilityValue(opts.Visibility))
}
ListGroupProjectOpts.PerPage = 100

View File

@ -77,10 +77,10 @@ func runE(opts *Options) error {
}
l := &gitlab.ListContributorsOptions{
OrderBy: gitlab.String(opts.OrderBy),
OrderBy: gitlab.Ptr(opts.OrderBy),
}
if opts.Sort != "" {
l.Sort = gitlab.String(opts.Sort)
l.Sort = gitlab.Ptr(opts.Sort)
}
l.PerPage = opts.PerPage
l.Page = opts.Page

View File

@ -152,12 +152,12 @@ func runCreateProject(cmd *cobra.Command, args []string, f *cmdutils.Factory) er
readme, _ := cmd.Flags().GetBool("readme")
opts := &gitlab.CreateProjectOptions{
Name: gitlab.String(name),
Path: gitlab.String(projectPath),
Description: gitlab.String(description),
DefaultBranch: gitlab.String(defaultBranch),
Name: gitlab.Ptr(name),
Path: gitlab.Ptr(projectPath),
Description: gitlab.Ptr(description),
DefaultBranch: gitlab.Ptr(defaultBranch),
TagList: &tags,
InitializeWithReadme: gitlab.Bool(readme),
InitializeWithReadme: gitlab.Ptr(readme),
}
if visiblity != "" {

View File

@ -137,10 +137,10 @@ func forkRun(opts *ForkOptions) error {
forkOpts := &gitlab.ForkProjectOptions{}
if opts.Name != "" {
forkOpts.Name = gitlab.String(opts.Name)
forkOpts.Name = gitlab.Ptr(opts.Name)
}
if opts.Path != "" {
forkOpts.Path = gitlab.String(opts.Path)
forkOpts.Path = gitlab.Ptr(opts.Path)
}
forkedProject, err := api.ForkProject(opts.LabClient, opts.RepoToFork.FullName(), forkOpts)

View File

@ -106,31 +106,31 @@ func runE(opts *Options) error {
func listAllProjects(apiClient *gitlab.Client, opts Options) ([]*gitlab.Project, *gitlab.Response, error) {
l := &gitlab.ListProjectsOptions{
OrderBy: gitlab.String(opts.OrderBy),
OrderBy: gitlab.Ptr(opts.OrderBy),
}
// Other filters only valid if FilterAll not true
if !opts.FilterAll {
if !opts.FilterStarred && !opts.FilterMember {
// if no other filters are passed, default to Owned filter
l.Owned = gitlab.Bool(true)
l.Owned = gitlab.Ptr(true)
}
if opts.FilterOwned {
l.Owned = gitlab.Bool(opts.FilterOwned)
l.Owned = gitlab.Ptr(opts.FilterOwned)
}
if opts.FilterStarred {
l.Starred = gitlab.Bool(opts.FilterStarred)
l.Starred = gitlab.Ptr(opts.FilterStarred)
}
if opts.FilterMember {
l.Membership = gitlab.Bool(opts.FilterMember)
l.Membership = gitlab.Ptr(opts.FilterMember)
}
}
if opts.Sort != "" {
l.Sort = gitlab.String(opts.Sort)
l.Sort = gitlab.Ptr(opts.Sort)
}
l.PerPage = opts.PerPage
@ -157,27 +157,27 @@ func listAllProjectsForGroup(apiClient *gitlab.Client, opts Options) ([]*gitlab.
}
l := &gitlab.ListGroupProjectsOptions{
OrderBy: gitlab.String(opts.OrderBy),
OrderBy: gitlab.Ptr(opts.OrderBy),
}
// Other filters only valid if FilterAll not true
if !opts.FilterAll {
if !opts.FilterStarred && !opts.FilterMember {
// if no other filters are passed, default to Owned filter
l.Owned = gitlab.Bool(true)
l.Owned = gitlab.Ptr(true)
}
if opts.FilterOwned {
l.Owned = gitlab.Bool(opts.FilterOwned)
l.Owned = gitlab.Ptr(opts.FilterOwned)
}
if opts.FilterStarred {
l.Starred = gitlab.Bool(opts.FilterStarred)
l.Starred = gitlab.Ptr(opts.FilterStarred)
}
}
if opts.Sort != "" {
l.Sort = gitlab.String(opts.Sort)
l.Sort = gitlab.Ptr(opts.Sort)
}
l.PerPage = opts.PerPage

View File

@ -217,7 +217,6 @@ func printProjectContentTTY(opts *ViewOptions, project *gitlab.Project, readme *
fullName := project.NameWithNamespace
if project.Description != "" {
description, err = utils.RenderMarkdownWithoutIndentations(project.Description, opts.GlamourStyle)
if err != nil {
description = project.Description
}
@ -227,7 +226,6 @@ func printProjectContentTTY(opts *ViewOptions, project *gitlab.Project, readme *
if readme != nil {
readmeContent, err = utils.RenderMarkdown(readme.Content, opts.GlamourStyle)
if err != nil {
readmeContent = readme.Content
}

View File

@ -338,7 +338,6 @@ func createRun(opts *CreateOpts) error {
}
release, _, err = client.Releases.CreateRelease(repo.FullName(), createOpts)
if err != nil {
return releaseFailedErr(err, start)
}

View File

@ -81,7 +81,6 @@ func (c *Context) UploadFiles(projectID, tagName string) error {
FilePath: &filename,
LinkType: file.Type,
})
if err != nil {
return err
}

View File

@ -98,9 +98,9 @@ func runCreate(client *gitlab.Client, repo glrepo.Interface, opts *CreateOpts) e
snippet, err := api.CreateProjectSnippet(client, repo.FullName(), &gitlab.CreateProjectSnippetOptions{
Title: &opts.Title,
Description: &opts.Description,
Content: gitlab.String(string(content)),
Content: gitlab.Ptr(string(content)),
FileName: &opts.DisplayFilename,
Visibility: gitlab.Visibility(gitlab.VisibilityValue(opts.Visibility)),
Visibility: gitlab.Ptr(gitlab.VisibilityValue(opts.Visibility)),
})
if err != nil {
return fmt.Errorf("failed to create snippet. %w", err)

View File

@ -107,13 +107,13 @@ func setRun(opts *SetOpts) error {
if opts.Group != "" {
// creating group-level variable
createVarOpts := &gitlab.CreateGroupVariableOptions{
Key: gitlab.String(opts.Key),
Value: gitlab.String(opts.Value),
EnvironmentScope: gitlab.String(opts.Scope),
Masked: gitlab.Bool(opts.Masked),
Protected: gitlab.Bool(opts.Protected),
VariableType: gitlab.VariableType(gitlab.VariableTypeValue(opts.Type)),
Raw: gitlab.Bool(opts.Raw),
Key: gitlab.Ptr(opts.Key),
Value: gitlab.Ptr(opts.Value),
EnvironmentScope: gitlab.Ptr(opts.Scope),
Masked: gitlab.Ptr(opts.Masked),
Protected: gitlab.Ptr(opts.Protected),
VariableType: gitlab.Ptr(gitlab.VariableTypeValue(opts.Type)),
Raw: gitlab.Ptr(opts.Raw),
}
_, err = api.CreateGroupVariable(httpClient, opts.Group, createVarOpts)
if err != nil {
@ -130,13 +130,13 @@ func setRun(opts *SetOpts) error {
return err
}
createVarOpts := &gitlab.CreateProjectVariableOptions{
Key: gitlab.String(opts.Key),
Value: gitlab.String(opts.Value),
EnvironmentScope: gitlab.String(opts.Scope),
Masked: gitlab.Bool(opts.Masked),
Protected: gitlab.Bool(opts.Protected),
VariableType: gitlab.VariableType(gitlab.VariableTypeValue(opts.Type)),
Raw: gitlab.Bool(opts.Raw),
Key: gitlab.Ptr(opts.Key),
Value: gitlab.Ptr(opts.Value),
EnvironmentScope: gitlab.Ptr(opts.Scope),
Masked: gitlab.Ptr(opts.Masked),
Protected: gitlab.Ptr(opts.Protected),
VariableType: gitlab.Ptr(gitlab.VariableTypeValue(opts.Type)),
Raw: gitlab.Ptr(opts.Raw),
}
_, err = api.CreateProjectVariable(httpClient, baseRepo.FullName(), createVarOpts)
if err != nil {

View File

@ -111,12 +111,12 @@ func updateRun(opts *UpdateOpts) error {
if opts.Group != "" {
// update group-level variable
updateGroupVarOpts := &gitlab.UpdateGroupVariableOptions{
Value: gitlab.String(opts.Value),
VariableType: gitlab.VariableType(gitlab.VariableTypeValue(opts.Type)),
Masked: gitlab.Bool(opts.Masked),
Protected: gitlab.Bool(opts.Protected),
Raw: gitlab.Bool(opts.Raw),
EnvironmentScope: gitlab.String(opts.Scope),
Value: gitlab.Ptr(opts.Value),
VariableType: gitlab.Ptr(gitlab.VariableTypeValue(opts.Type)),
Masked: gitlab.Ptr(opts.Masked),
Protected: gitlab.Ptr(opts.Protected),
Raw: gitlab.Ptr(opts.Raw),
EnvironmentScope: gitlab.Ptr(opts.Scope),
}
_, err = api.UpdateGroupVariable(httpClient, opts.Group, opts.Key, updateGroupVarOpts)
@ -135,12 +135,12 @@ func updateRun(opts *UpdateOpts) error {
}
updateProjectVarOpts := &gitlab.UpdateProjectVariableOptions{
Value: gitlab.String(opts.Value),
VariableType: gitlab.VariableType(gitlab.VariableTypeValue(opts.Type)),
Masked: gitlab.Bool(opts.Masked),
Protected: gitlab.Bool(opts.Protected),
Raw: gitlab.Bool(opts.Raw),
EnvironmentScope: gitlab.String(opts.Scope),
Value: gitlab.Ptr(opts.Value),
VariableType: gitlab.Ptr(gitlab.VariableTypeValue(opts.Type)),
Masked: gitlab.Ptr(opts.Masked),
Protected: gitlab.Ptr(opts.Protected),
Raw: gitlab.Ptr(opts.Raw),
EnvironmentScope: gitlab.Ptr(opts.Scope),
}
_, err = api.UpdateProjectVariable(httpClient, baseRepo.FullName(), opts.Key, updateProjectVarOpts)

View File

@ -43,6 +43,7 @@ pipeline
- [`list`](list.md)
- [`retry`](retry.md)
- [`run`](run.md)
- [`run-trig`](run-trig.md)
- [`status`](status.md)
- [`trace`](trace.md)
- [`trigger`](trigger.md)

View File

@ -0,0 +1,50 @@
---
stage: Create
group: Code Review
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
<!--
This documentation is auto generated by a script.
Please do not edit this file directly. Run `make gen-docs` instead.
-->
# `glab ci run-trig`
Run a CI/CD pipeline trigger
```plaintext
glab ci run-trig [flags]
```
## Aliases
```plaintext
run-trig
```
## Examples
```plaintext
glab ci run-trig -t xxxx
glab ci run-trig -t xxxx -b main
glab ci run-trig -t xxxx -b main --variables key1:val1
glab ci run-trig -t xxxx -b main --variables key1:val1,key2:val2
glab ci run-trig -t xxxx -b main --variables key1:val1 --variables key2:val2
```
## Options
```plaintext
-b, --branch string Create pipeline on branch/ref <string>
-t, --token string Pipeline trigger token (can be omitted only if CI_JOB_TOKEN environment variable is set)
--variables strings Pass variables to pipeline in format <key>:<value>
```
## Options inherited from parent commands
```plaintext
--help Show help for command
-R, --repo OWNER/REPO Select another repository using the OWNER/REPO or `GROUP/NAMESPACE/REPO` format or full URL or git URL
```

View File

@ -19,13 +19,13 @@ Get and set key/value strings.
Current respected settings:
- token: Your GitLab access token, defaults to environment variables
- token: your GitLab access token, defaults to environment variables
- host: if unset, defaults to `https://gitlab.com`
- browser: if unset, defaults to environment variables
- editor: if unset, defaults to environment variables
- visual: alternative for editor. If unset, defaults to environment variables
- glamour_style: Your desired Markdown renderer style. Options are dark, light, notty. Custom styles are allowed using [glamour](https://github.com/charmbracelet/glamour#styles)
- glab_pager: Your desired pager command to use (e.g. less -R)
- browser: if unset, default browser is used. Override with environment variable $BROWSER
- editor: if unset, default editor is used. Override with environment variable $EDITOR
- visual: takes precedence over editor. If unset, default editor is used. Override with environment variable $VISUAL
- glamour_style: your desired Markdown renderer style. Options are dark, light, notty. Custom styles are allowed using [glamour](https://github.com/charmbracelet/glamour#styles)
- glab_pager: your desired pager command to use (e.g. less -R)
- check_update: if true, notifies of any available updates to glab. Defaults to true
- display_hyperlinks: if true, and using a TTY, outputs hyperlinks for issues and MR lists. Defaults to false

View File

@ -48,7 +48,8 @@ glab incident list --milestone release-2.0.0 --opened
--not-assignee strings Filter incident by not being assigneed to <username>
--not-author strings Filter by not being by author(s) <username>
--not-label strings Filter incident by lack of label <name>
-F, --output string One of 'details', 'ids', 'urls' or 'json' (default "details")
-O, --output string One of 'text' or 'json' (default "text")
-F, --output-format string One of 'details', 'ids', 'urls' (default "details")
-p, --page int Page number (default 1)
-P, --per-page int Number of items to list per page. (default 30)
-R, --repo OWNER/REPO Select another repository using the OWNER/REPO or `GROUP/NAMESPACE/REPO` format or full URL or git URL

View File

@ -49,7 +49,8 @@ glab issue list --milestone release-2.0.0 --opened
--not-assignee strings Filter issue by not being assigneed to <username>
--not-author strings Filter by not being by author(s) <username>
--not-label strings Filter issue by lack of label <name>
-F, --output string One of 'details', 'ids', 'urls' or 'json' (default "details")
-O, --output string One of 'text' or 'json' (default "text")
-F, --output-format string One of 'details', 'ids', 'urls' (default "details")
-p, --page int Page number (default 1)
-P, --per-page int Number of items to list per page. (default 30)
-R, --repo OWNER/REPO Select another repository using the OWNER/REPO or `GROUP/NAMESPACE/REPO` format or full URL or git URL

20
go.mod
View File

@ -15,7 +15,7 @@ require (
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/gosuri/uilive v0.0.4
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.2
github.com/hashicorp/go-retryablehttp v0.7.5
github.com/hashicorp/go-version v1.6.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/lunixbochs/vtclean v1.0.0
@ -34,11 +34,11 @@ require (
github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.3
github.com/tidwall/pretty v1.2.1
github.com/xanzy/go-gitlab v0.93.0
github.com/xanzy/go-gitlab v0.103.0
github.com/zalando/go-keyring v0.2.3
golang.org/x/sync v0.2.0
golang.org/x/term v0.13.0
golang.org/x/text v0.13.0
golang.org/x/term v0.18.0
golang.org/x/text v0.14.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.27.2
k8s.io/client-go v0.27.2
@ -59,7 +59,7 @@ require (
github.com/go-logr/logr v1.2.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
@ -86,12 +86,10 @@ require (
github.com/subosito/gotenv v1.4.2 // indirect
github.com/yuin/goldmark v1.5.4 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.30.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.19.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/time v0.5.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect

45
go.sum
View File

@ -142,9 +142,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
@ -158,7 +157,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
@ -204,8 +202,8 @@ github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXc
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -335,8 +333,8 @@ github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/xanzy/go-gitlab v0.93.0 h1:/Fy4akqKIQasZgQ2xj2xJBrEZ+iCW+iC+9qLEt19tgo=
github.com/xanzy/go-gitlab v0.93.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
github.com/xanzy/go-gitlab v0.103.0 h1:J9pTQoq0GsEFqzd6srCM1QfdfKAxSNz6mT6ntrpNF2w=
github.com/xanzy/go-gitlab v0.103.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -431,8 +429,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -442,8 +440,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -501,14 +499,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -518,13 +516,13 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -604,7 +602,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -668,10 +665,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -51,7 +51,6 @@ func (a *AliasConfig) Write() error {
return err
}
err = WriteConfigFile(aliasesConfigFile(), yamlNormalize(aliasesBytes))
if err != nil {
return fmt.Errorf("failed to write config: %w", err)
}

View File

@ -67,7 +67,6 @@ func (a *LocalConfig) Write() error {
return err
}
err = WriteConfigFile(LocalConfigFile(), yamlNormalize(localConfigBytes))
if err != nil {
return fmt.Errorf("failed to write config: %w", err)
}

View File

@ -3,6 +3,7 @@ package utils
import (
"fmt"
"net/url"
"path/filepath"
"strings"
"time"
@ -22,6 +23,15 @@ func OpenInBrowser(url, browserType string) error {
return run.PrepareCmd(browseCmd).Run()
}
func SanitizePathName(path string) string {
if !strings.HasPrefix(path, "/") {
// Prefix the path with "/" ensures that filepath.Clean removes all `/..`
// See rule 4 of filepath.Clean for more information: https://pkg.go.dev/path/filepath#Clean
path = "/" + path
}
return filepath.Clean(path)
}
func RenderMarkdown(text, glamourStyle string) (string, error) {
opts := MarkdownRenderOpts{
glamour.WithStylePath(getStyle(glamourStyle)),

View File

@ -110,6 +110,44 @@ func Test_PresentInIntSlice(t *testing.T) {
}
}
func Test_SanitizePathName(t *testing.T) {
tests := []struct {
name string
filename string
want string
}{
{
name: "A regular filename",
filename: "cli-v1.22.0.json",
want: "/cli-v1.22.0.json",
},
{
name: "A regular filename in a directory",
filename: "cli/cli-v1.22.0.json",
want: "/cli/cli-v1.22.0.json",
},
{
name: "A filename with directory traversal",
filename: "cli-v1.../../22.0.zip",
want: "/22.0.zip",
},
{
name: "A particularly nasty filename",
filename: "..././..././..././etc/password_file",
want: "/.../.../.../etc/password_file",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
filePathWanted := SanitizePathName(tt.filename)
if filePathWanted != tt.want {
t.Errorf("SanitizePathName() got = %s, want = %s", filePathWanted, tt.want)
}
})
}
}
func Test_CommonElementsInStringSlice(t *testing.T) {
testCases := []struct {
name string