mirror of https://gitlab.com/gitlab-org/cli.git
Merge branch '682' into 'main'
feat(ci): add ci trigger (#682) Closes #682 See merge request https://gitlab.com/gitlab-org/cli/-/merge_requests/1374 Merged-by: Shekhar Patnaik <spatnaik@gitlab.com> Approved-by: Amy Qualls <aqualls@gitlab.com> Approved-by: Gary Holtz <gholtz@gitlab.com> Approved-by: Shekhar Patnaik <spatnaik@gitlab.com> Co-authored-by: Andreas Weber <weber.andreas@gmail.com> Co-authored-by: Amy Qualls <aqualls@gitlab.com>
This commit is contained in:
commit
dd611918d7
|
@ -11,6 +11,7 @@ import (
|
|||
pipeRunCmd "gitlab.com/gitlab-org/cli/commands/ci/run"
|
||||
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"
|
||||
ciViewCmd "gitlab.com/gitlab-org/cli/commands/ci/view"
|
||||
"gitlab.com/gitlab-org/cli/commands/cmdutils"
|
||||
|
||||
|
@ -36,6 +37,7 @@ 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(jobArtifactCmd.NewCmdRun(f))
|
||||
ciCmd.AddCommand(pipeGetCmd.NewCmdGet(f))
|
||||
return ciCmd
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package trigger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitlab.com/gitlab-org/cli/api"
|
||||
"gitlab.com/gitlab-org/cli/commands/cmdutils"
|
||||
"gitlab.com/gitlab-org/cli/pkg/git"
|
||||
"gitlab.com/gitlab-org/cli/pkg/utils"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
func NewCmdTrigger(f *cmdutils.Factory) *cobra.Command {
|
||||
pipelineTriggerCmd := &cobra.Command{
|
||||
Use: "trigger <job-id>",
|
||||
Short: `Trigger a manual CI/CD job.`,
|
||||
Aliases: []string{},
|
||||
Example: heredoc.Doc(`
|
||||
$ glab ci trigger 224356863
|
||||
#=> trigger manual job with id 224356863
|
||||
|
||||
$ glab ci trigger lint
|
||||
#=> trigger manual job with name lint
|
||||
`),
|
||||
Long: ``,
|
||||
Args: cobra.ExactArgs(1),
|
||||
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
|
||||
}
|
||||
|
||||
jobID := utils.StringToInt(args[0])
|
||||
|
||||
if jobID < 1 {
|
||||
jobName := args[0]
|
||||
|
||||
pipelineId, err := cmd.Flags().GetInt("pipeline-id")
|
||||
if err != nil || pipelineId == 0 {
|
||||
branch, _ := cmd.Flags().GetString("branch")
|
||||
if branch == "" {
|
||||
branch, err = git.CurrentBranch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
commit, err := api.GetCommit(apiClient, repo.FullName(), branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pipelineId = commit.LastPipeline.ID
|
||||
}
|
||||
|
||||
jobs, _, err := apiClient.Jobs.ListPipelineJobs(repo.FullName(), pipelineId, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, job := range jobs {
|
||||
if job.Name == jobName {
|
||||
jobID = job.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
if jobID < 1 {
|
||||
fmt.Fprintln(f.IO.StdErr, "invalid job id:", args[0])
|
||||
return cmdutils.SilentError
|
||||
}
|
||||
}
|
||||
|
||||
job, err := api.PlayPipelineJob(apiClient, jobID, repo.FullName())
|
||||
if err != nil {
|
||||
return cmdutils.WrapError(err, fmt.Sprintf("Could not trigger job with ID: %d", jobID))
|
||||
}
|
||||
fmt.Fprintln(f.IO.StdOut, "Triggered job (ID:", job.ID, "), status:", job.Status, ", ref:", job.Ref, ", weburl: ", job.WebURL, ")")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
pipelineTriggerCmd.Flags().StringP("branch", "b", "", "The branch to search for the job. (Default: current branch)")
|
||||
pipelineTriggerCmd.Flags().IntP("pipeline-id", "p", 0, "The pipeline ID to search for the job.")
|
||||
return pipelineTriggerCmd
|
||||
}
|
||||
|
||||
type Jobs []*gitlab.Job
|
||||
|
||||
// FindByName returns the first Remote whose name matches the list
|
||||
func (jobs Jobs) FindByName(name string) (*gitlab.Job, error) {
|
||||
for _, job := range jobs {
|
||||
if job.Name == name {
|
||||
return job, nil
|
||||
}
|
||||
}
|
||||
return nil, cmdutils.SilentError
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
package trigger
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"gitlab.com/gitlab-org/cli/commands/cmdtest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gitlab.com/gitlab-org/cli/pkg/httpmock"
|
||||
"gitlab.com/gitlab-org/cli/test"
|
||||
)
|
||||
|
||||
func runCommand(rt http.RoundTripper, isTTY bool, args string) (*test.CmdOut, error) {
|
||||
ios, _, stdout, stderr := cmdtest.InitIOStreams(isTTY, "")
|
||||
|
||||
factory := cmdtest.InitFactory(ios, rt)
|
||||
|
||||
_, _ = factory.HttpClient()
|
||||
|
||||
cmd := NewCmdTrigger(factory)
|
||||
|
||||
return cmdtest.ExecuteCommand(cmd, args, stdout, stderr)
|
||||
}
|
||||
|
||||
func TestCiTrigger(t *testing.T) {
|
||||
type httpMock struct {
|
||||
method string
|
||||
path string
|
||||
status int
|
||||
body string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
httpMocks []httpMock
|
||||
expectedOut string
|
||||
}{
|
||||
{
|
||||
name: "when trigger with job-id is created",
|
||||
args: "1122",
|
||||
httpMocks: []httpMock{
|
||||
{
|
||||
http.MethodPost,
|
||||
"/api/v4/projects/OWNER/REPO/jobs/1122/play",
|
||||
http.StatusCreated,
|
||||
`{
|
||||
"id": 1123,
|
||||
"status": "pending",
|
||||
"stage": "build",
|
||||
"name": "build-job",
|
||||
"ref": "branch-name",
|
||||
"tag": false,
|
||||
"coverage": null,
|
||||
"allow_failure": false,
|
||||
"created_at": "2022-12-01T05:13:13.703Z",
|
||||
"web_url": "https://gitlab.com/OWNER/REPO/-/jobs/1123"
|
||||
}`,
|
||||
},
|
||||
},
|
||||
expectedOut: "Triggered job (ID: 1123 ), status: pending , ref: branch-name , weburl: https://gitlab.com/OWNER/REPO/-/jobs/1123 )\n",
|
||||
},
|
||||
{
|
||||
name: "when trigger with job-name is created",
|
||||
args: "lint -b main -p 123",
|
||||
httpMocks: []httpMock{
|
||||
{
|
||||
http.MethodPost,
|
||||
"/api/v4/projects/OWNER/REPO/jobs/1122/play",
|
||||
http.StatusCreated,
|
||||
`{
|
||||
"id": 1123,
|
||||
"status": "pending",
|
||||
"stage": "build",
|
||||
"name": "build-job",
|
||||
"ref": "branch-name",
|
||||
"tag": false,
|
||||
"coverage": null,
|
||||
"allow_failure": false,
|
||||
"created_at": "2022-12-01T05:13:13.703Z",
|
||||
"web_url": "https://gitlab.com/OWNER/REPO/-/jobs/1123"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
http.MethodGet,
|
||||
"/api/v4/projects/OWNER%2FREPO/pipelines/123/jobs",
|
||||
http.StatusOK,
|
||||
`[{
|
||||
"id": 1122,
|
||||
"name": "lint",
|
||||
"status": "failed"
|
||||
}, {
|
||||
"id": 1124,
|
||||
"name": "publish",
|
||||
"status": "failed"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
expectedOut: "Triggered job (ID: 1123 ), status: pending , ref: branch-name , weburl: https://gitlab.com/OWNER/REPO/-/jobs/1123 )\n",
|
||||
},
|
||||
{
|
||||
name: "when trigger with job-name and last pipeline is created",
|
||||
args: "lint -b main",
|
||||
httpMocks: []httpMock{
|
||||
{
|
||||
http.MethodPost,
|
||||
"/api/v4/projects/OWNER/REPO/jobs/1122/play",
|
||||
http.StatusCreated,
|
||||
`{
|
||||
"id": 1123,
|
||||
"status": "pending",
|
||||
"stage": "build",
|
||||
"name": "build-job",
|
||||
"ref": "branch-name",
|
||||
"tag": false,
|
||||
"coverage": null,
|
||||
"allow_failure": false,
|
||||
"created_at": "2022-12-01T05:13:13.703Z",
|
||||
"web_url": "https://gitlab.com/OWNER/REPO/-/jobs/1123"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
http.MethodGet,
|
||||
"/api/v4/projects/OWNER%2FREPO/repository/commits/main",
|
||||
http.StatusOK,
|
||||
`{
|
||||
"last_pipeline" : {
|
||||
"id": 123
|
||||
}
|
||||
}`,
|
||||
},
|
||||
{
|
||||
http.MethodGet,
|
||||
"/api/v4/projects/OWNER%2FREPO/pipelines/123/jobs",
|
||||
http.StatusOK,
|
||||
`[{
|
||||
"id": 1122,
|
||||
"name": "lint",
|
||||
"status": "failed"
|
||||
}, {
|
||||
"id": 1124,
|
||||
"name": "publish",
|
||||
"status": "failed"
|
||||
}]`,
|
||||
},
|
||||
},
|
||||
expectedOut: "Triggered job (ID: 1123 ), status: pending , ref: branch-name , weburl: https://gitlab.com/OWNER/REPO/-/jobs/1123 )\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
fakeHTTP := &httpmock.Mocker{
|
||||
MatchURL: httpmock.PathAndQuerystring,
|
||||
}
|
||||
defer fakeHTTP.Verify(t)
|
||||
|
||||
for _, mock := range tc.httpMocks {
|
||||
fakeHTTP.RegisterResponder(mock.method, mock.path, httpmock.NewStringResponse(mock.status, mock.body))
|
||||
}
|
||||
|
||||
output, err := runCommand(fakeHTTP, false, tc.args)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.Equal(t, tc.expectedOut, output.String())
|
||||
assert.Empty(t, output.Stderr())
|
||||
})
|
||||
}
|
||||
}
|
|
@ -44,4 +44,5 @@ pipeline
|
|||
- [`run`](run.md)
|
||||
- [`status`](status.md)
|
||||
- [`trace`](trace.md)
|
||||
- [`trigger`](trigger.md)
|
||||
- [`view`](view.md)
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
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 trigger`
|
||||
|
||||
Trigger a manual CI/CD job.
|
||||
|
||||
```plaintext
|
||||
glab ci trigger <job-id> [flags]
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```plaintext
|
||||
$ glab ci trigger 224356863
|
||||
#=> trigger manual job with id 224356863
|
||||
|
||||
$ glab ci trigger lint
|
||||
#=> trigger manual job with name lint
|
||||
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
```plaintext
|
||||
-b, --branch string The branch to search for the job. (Default: current branch)
|
||||
-p, --pipeline-id int The pipeline ID to search for the job.
|
||||
```
|
||||
|
||||
## 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
|
||||
```
|
Loading…
Reference in New Issue