diff --git a/cli/exec/flags.go b/cli/exec/flags.go index dd65b6af1..eabce0470 100644 --- a/cli/exec/flags.go +++ b/cli/exec/flags.go @@ -204,6 +204,10 @@ var flags = []cli.Flag{ EnvVars: []string{"CI_PIPELINE_TARGET"}, Name: "pipeline-target", }, + &cli.StringFlag{ + EnvVars: []string{"CI_PIPELINE_TASK"}, + Name: "pipeline-task", + }, &cli.StringFlag{ EnvVars: []string{"CI_COMMIT_SHA"}, Name: "commit-sha", diff --git a/cli/exec/metadata.go b/cli/exec/metadata.go index c72aeaffa..0cb471683 100644 --- a/cli/exec/metadata.go +++ b/cli/exec/metadata.go @@ -61,6 +61,7 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) metadata.Metadata { Event: c.String("pipeline-event"), ForgeURL: c.String("pipeline-url"), Target: c.String("pipeline-target"), + Task: c.String("pipeline-task"), Commit: metadata.Commit{ Sha: c.String("commit-sha"), Ref: c.String("commit-ref"), diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 13ee5951a..cac9c766b 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -4023,6 +4023,9 @@ const docTemplate = `{ "created_at": { "type": "integer" }, + "deploy_task": { + "type": "string" + }, "deploy_to": { "type": "string" }, diff --git a/docs/docs/20-usage/50-environment.md b/docs/docs/20-usage/50-environment.md index bf2a9da85..299bb8f53 100644 --- a/docs/docs/20-usage/50-environment.md +++ b/docs/docs/20-usage/50-environment.md @@ -85,6 +85,7 @@ This is the reference list of all environment variables available to your pipeli | `CI_PIPELINE_URL` | link to the web UI for the pipeline | | `CI_PIPELINE_FORGE_URL` | link to the forge's web UI for the commit(s) or tag that triggered the pipeline | | `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (i.e. production) | +| `CI_PIPELINE_DEPLOY_TASK` | pipeline deploy task for `deployment` events (i.e. migration) | | `CI_PIPELINE_STATUS` | pipeline status (success, failure) | | `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp | | `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp | @@ -118,6 +119,7 @@ This is the reference list of all environment variables available to your pipeli | `CI_PREV_PIPELINE_URL` | previous pipeline link in CI | | `CI_PREV_PIPELINE_FORGE_URL` | previous pipeline link to event in forge | | `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) | +| `CI_PREV_PIPELINE_DEPLOY_TASK` | previous pipeline deploy task for `deployment` events (ie migration) | | `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) | | `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp | | `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp | diff --git a/pipeline/frontend/metadata/environment.go b/pipeline/frontend/metadata/environment.go index d32378d02..7068aba01 100644 --- a/pipeline/frontend/metadata/environment.go +++ b/pipeline/frontend/metadata/environment.go @@ -77,6 +77,7 @@ func (m *Metadata) Environ() map[string]string { "CI_PIPELINE_URL": m.getPipelineWebURL(m.Curr, 0), "CI_PIPELINE_FORGE_URL": m.Curr.ForgeURL, "CI_PIPELINE_DEPLOY_TARGET": m.Curr.Target, + "CI_PIPELINE_DEPLOY_TASK": m.Curr.Task, "CI_PIPELINE_STATUS": m.Curr.Status, "CI_PIPELINE_CREATED": strconv.FormatInt(m.Curr.Created, 10), "CI_PIPELINE_STARTED": strconv.FormatInt(m.Curr.Started, 10), @@ -108,6 +109,7 @@ func (m *Metadata) Environ() map[string]string { "CI_PREV_PIPELINE_URL": m.getPipelineWebURL(m.Prev, 0), "CI_PREV_PIPELINE_FORGE_URL": m.Prev.ForgeURL, "CI_PREV_PIPELINE_DEPLOY_TARGET": m.Prev.Target, + "CI_PREV_PIPELINE_DEPLOY_TASK": m.Prev.Task, "CI_PREV_PIPELINE_STATUS": m.Prev.Status, "CI_PREV_PIPELINE_CREATED": strconv.FormatInt(m.Prev.Created, 10), "CI_PREV_PIPELINE_STARTED": strconv.FormatInt(m.Prev.Started, 10), diff --git a/pipeline/frontend/metadata/types.go b/pipeline/frontend/metadata/types.go index c75f321e6..932bb0a63 100644 --- a/pipeline/frontend/metadata/types.go +++ b/pipeline/frontend/metadata/types.go @@ -53,6 +53,7 @@ type ( Event string `json:"event,omitempty"` ForgeURL string `json:"forge_url,omitempty"` Target string `json:"target,omitempty"` + Task string `json:"task,omitempty"` Trusted bool `json:"trusted,omitempty"` Commit Commit `json:"commit,omitempty"` Parent int64 `json:"parent,omitempty"` diff --git a/server/api/pipeline.go b/server/api/pipeline.go index d8bc8fb67..b3471918c 100644 --- a/server/api/pipeline.go +++ b/server/api/pipeline.go @@ -547,6 +547,9 @@ func PostPipeline(c *gin.Context) { // make Deploy overridable + // make Deploy task overridable + pl.DeployTask = c.DefaultQuery("deploy_task", pl.DeployTask) + // make Event overridable to deploy // TODO refactor to use own proper API for deploy if event, ok := c.GetQuery("event"); ok { diff --git a/server/forge/github/convert_test.go b/server/forge/github/convert_test.go index 0d74417ea..985a3cd33 100644 --- a/server/forge/github/convert_test.go +++ b/server/forge/github/convert_test.go @@ -224,6 +224,7 @@ func Test_helper(t *testing.T) { from := &github.DeploymentEvent{Deployment: &github.Deployment{}, Sender: &github.User{}} from.Deployment.Description = github.String(":shipit:") from.Deployment.Environment = github.String("production") + from.Deployment.Task = github.String("deploy") from.Deployment.ID = github.Int64(42) from.Deployment.Ref = github.String("main") from.Deployment.SHA = github.String("f72fc19") diff --git a/server/forge/github/parse.go b/server/forge/github/parse.go index 2a14a5a91..580d38e12 100644 --- a/server/forge/github/parse.go +++ b/server/forge/github/parse.go @@ -120,16 +120,17 @@ func parsePushHook(hook *github.PushEvent) (*model.Repo, *model.Pipeline) { // If the commit type is unsupported nil values are returned. func parseDeployHook(hook *github.DeploymentEvent) (*model.Repo, *model.Pipeline) { pipeline := &model.Pipeline{ - Event: model.EventDeploy, - Commit: hook.GetDeployment().GetSHA(), - ForgeURL: hook.GetDeployment().GetURL(), - Message: hook.GetDeployment().GetDescription(), - Ref: hook.GetDeployment().GetRef(), - Branch: hook.GetDeployment().GetRef(), - Deploy: hook.GetDeployment().GetEnvironment(), - Avatar: hook.GetSender().GetAvatarURL(), - Author: hook.GetSender().GetLogin(), - Sender: hook.GetSender().GetLogin(), + Event: model.EventDeploy, + Commit: hook.GetDeployment().GetSHA(), + ForgeURL: hook.GetDeployment().GetURL(), + Message: hook.GetDeployment().GetDescription(), + Ref: hook.GetDeployment().GetRef(), + Branch: hook.GetDeployment().GetRef(), + Deploy: hook.GetDeployment().GetEnvironment(), + Avatar: hook.GetSender().GetAvatarURL(), + Author: hook.GetSender().GetLogin(), + Sender: hook.GetSender().GetLogin(), + DeployTask: hook.GetDeployment().GetTask(), } // if the ref is a sha or short sha we need to manually construct the ref. if strings.HasPrefix(pipeline.Commit, pipeline.Ref) || pipeline.Commit == pipeline.Ref { diff --git a/server/forge/github/parse_test.go b/server/forge/github/parse_test.go index bbd4fb57f..ff28df811 100644 --- a/server/forge/github/parse_test.go +++ b/server/forge/github/parse_test.go @@ -119,6 +119,8 @@ func Test_parser(t *testing.T) { g.Assert(b).IsNotNil() g.Assert(p).IsNil() g.Assert(b.Event).Equal(model.EventDeploy) + g.Assert(b.Deploy).Equal("production") + g.Assert(b.DeployTask).Equal("deploy") }) }) diff --git a/server/model/pipeline.go b/server/model/pipeline.go index 9454b40e5..5d9606792 100644 --- a/server/model/pipeline.go +++ b/server/model/pipeline.go @@ -33,6 +33,7 @@ type Pipeline struct { Started int64 `json:"started_at" xorm:"pipeline_started"` Finished int64 `json:"finished_at" xorm:"pipeline_finished"` Deploy string `json:"deploy_to" xorm:"pipeline_deploy"` + DeployTask string `json:"deploy_task" xorm:"pipeline_deploy_task"` Commit string `json:"commit" xorm:"pipeline_commit"` Branch string `json:"branch" xorm:"pipeline_branch"` Ref string `json:"ref" xorm:"pipeline_ref"` diff --git a/server/pipeline/stepbuilder/metadata_test.go b/server/pipeline/stepbuilder/metadata_test.go index 62e8b50d5..a0d451425 100644 --- a/server/pipeline/stepbuilder/metadata_test.go +++ b/server/pipeline/stepbuilder/metadata_test.go @@ -47,11 +47,11 @@ func TestMetadataFromStruct(t *testing.T) { "CI_COMMIT_AUTHOR": "", "CI_COMMIT_AUTHOR_AVATAR": "", "CI_COMMIT_AUTHOR_EMAIL": "", "CI_COMMIT_BRANCH": "", "CI_COMMIT_MESSAGE": "", "CI_COMMIT_PULL_REQUEST": "", "CI_COMMIT_PULL_REQUEST_LABELS": "", "CI_COMMIT_REF": "", "CI_COMMIT_REFSPEC": "", "CI_COMMIT_SHA": "", "CI_COMMIT_SOURCE_BRANCH": "", "CI_COMMIT_TAG": "", "CI_COMMIT_TARGET_BRANCH": "", "CI_COMMIT_URL": "", "CI_FORGE_TYPE": "", "CI_FORGE_URL": "", - "CI_PIPELINE_CREATED": "0", "CI_PIPELINE_DEPLOY_TARGET": "", "CI_PIPELINE_EVENT": "", "CI_PIPELINE_FINISHED": "0", "CI_PIPELINE_FILES": "[]", "CI_PIPELINE_NUMBER": "0", + "CI_PIPELINE_CREATED": "0", "CI_PIPELINE_DEPLOY_TARGET": "", "CI_PIPELINE_DEPLOY_TASK": "", "CI_PIPELINE_EVENT": "", "CI_PIPELINE_FINISHED": "0", "CI_PIPELINE_FILES": "[]", "CI_PIPELINE_NUMBER": "0", "CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_STATUS": "", "CI_PIPELINE_URL": "/repos/0/pipeline/0", "CI_PIPELINE_FORGE_URL": "", "CI_PREV_COMMIT_AUTHOR": "", "CI_PREV_COMMIT_AUTHOR_AVATAR": "", "CI_PREV_COMMIT_AUTHOR_EMAIL": "", "CI_PREV_COMMIT_BRANCH": "", "CI_PREV_COMMIT_MESSAGE": "", "CI_PREV_COMMIT_REF": "", "CI_PREV_COMMIT_REFSPEC": "", "CI_PREV_COMMIT_SHA": "", "CI_PREV_COMMIT_URL": "", "CI_PREV_PIPELINE_CREATED": "0", - "CI_PREV_PIPELINE_DEPLOY_TARGET": "", "CI_PREV_PIPELINE_EVENT": "", "CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "0", "CI_PREV_PIPELINE_PARENT": "0", + "CI_PREV_PIPELINE_DEPLOY_TARGET": "", "CI_PREV_PIPELINE_DEPLOY_TASK": "", "CI_PREV_PIPELINE_EVENT": "", "CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "0", "CI_PREV_PIPELINE_PARENT": "0", "CI_PREV_PIPELINE_STARTED": "0", "CI_PREV_PIPELINE_STATUS": "", "CI_PREV_PIPELINE_URL": "/repos/0/pipeline/0", "CI_PREV_PIPELINE_FORGE_URL": "", "CI_REPO": "", "CI_REPO_CLONE_URL": "", "CI_REPO_CLONE_SSH_URL": "", "CI_REPO_DEFAULT_BRANCH": "", "CI_REPO_REMOTE_ID": "", "CI_REPO_NAME": "", "CI_REPO_OWNER": "", "CI_REPO_PRIVATE": "false", "CI_REPO_SCM": "git", "CI_REPO_TRUSTED": "false", "CI_REPO_URL": "", "CI_STEP_FINISHED": "", "CI_STEP_NAME": "", "CI_STEP_NUMBER": "0", "CI_STEP_STARTED": "", "CI_STEP_STATUS": "", "CI_STEP_URL": "/repos/0/pipeline/0", "CI_SYSTEM_HOST": "", "CI_SYSTEM_NAME": "woodpecker", @@ -82,11 +82,11 @@ func TestMetadataFromStruct(t *testing.T) { "CI_COMMIT_AUTHOR": "", "CI_COMMIT_AUTHOR_AVATAR": "", "CI_COMMIT_AUTHOR_EMAIL": "", "CI_COMMIT_BRANCH": "", "CI_COMMIT_MESSAGE": "", "CI_COMMIT_PULL_REQUEST": "", "CI_COMMIT_PULL_REQUEST_LABELS": "", "CI_COMMIT_REF": "", "CI_COMMIT_REFSPEC": "", "CI_COMMIT_SHA": "", "CI_COMMIT_SOURCE_BRANCH": "", "CI_COMMIT_TAG": "", "CI_COMMIT_TARGET_BRANCH": "", "CI_COMMIT_URL": "", "CI_FORGE_TYPE": "gitea", "CI_FORGE_URL": "https://gitea.com", - "CI_PIPELINE_CREATED": "0", "CI_PIPELINE_DEPLOY_TARGET": "", "CI_PIPELINE_EVENT": "", "CI_PIPELINE_FINISHED": "0", "CI_PIPELINE_FILES": `["test.go","markdown file.md"]`, + "CI_PIPELINE_CREATED": "0", "CI_PIPELINE_DEPLOY_TARGET": "", "CI_PIPELINE_DEPLOY_TASK": "", "CI_PIPELINE_EVENT": "", "CI_PIPELINE_FINISHED": "0", "CI_PIPELINE_FILES": `["test.go","markdown file.md"]`, "CI_PIPELINE_NUMBER": "3", "CI_PIPELINE_PARENT": "0", "CI_PIPELINE_STARTED": "0", "CI_PIPELINE_STATUS": "", "CI_PIPELINE_URL": "https://example.com/repos/0/pipeline/3", "CI_PIPELINE_FORGE_URL": "", "CI_PREV_COMMIT_AUTHOR": "", "CI_PREV_COMMIT_AUTHOR_AVATAR": "", "CI_PREV_COMMIT_AUTHOR_EMAIL": "", "CI_PREV_COMMIT_BRANCH": "", "CI_PREV_COMMIT_MESSAGE": "", "CI_PREV_COMMIT_REF": "", "CI_PREV_COMMIT_REFSPEC": "", "CI_PREV_COMMIT_SHA": "", "CI_PREV_COMMIT_URL": "", "CI_PREV_PIPELINE_CREATED": "0", - "CI_PREV_PIPELINE_DEPLOY_TARGET": "", "CI_PREV_PIPELINE_EVENT": "", "CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "2", "CI_PREV_PIPELINE_PARENT": "0", + "CI_PREV_PIPELINE_DEPLOY_TARGET": "", "CI_PREV_PIPELINE_DEPLOY_TASK": "", "CI_PREV_PIPELINE_EVENT": "", "CI_PREV_PIPELINE_FINISHED": "0", "CI_PREV_PIPELINE_NUMBER": "2", "CI_PREV_PIPELINE_PARENT": "0", "CI_PREV_PIPELINE_STARTED": "0", "CI_PREV_PIPELINE_STATUS": "", "CI_PREV_PIPELINE_URL": "https://example.com/repos/0/pipeline/2", "CI_PREV_PIPELINE_FORGE_URL": "", "CI_REPO": "testUser/testRepo", "CI_REPO_CLONE_URL": "https://gitea.com/testUser/testRepo.git", "CI_REPO_CLONE_SSH_URL": "git@gitea.com:testUser/testRepo.git", "CI_REPO_DEFAULT_BRANCH": "main", "CI_REPO_NAME": "testRepo", "CI_REPO_OWNER": "testUser", "CI_REPO_PRIVATE": "true", "CI_REPO_REMOTE_ID": "", "CI_REPO_SCM": "git", "CI_REPO_TRUSTED": "false", "CI_REPO_URL": "https://gitea.com/testUser/testRepo", "CI_STEP_FINISHED": "", diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json index 83e98c2d8..ed881f88f 100644 --- a/web/src/assets/locales/en.json +++ b/web/src/assets/locales/en.json @@ -48,6 +48,7 @@ "deploy_pipeline": { "title": "Trigger deployment event for current pipeline #{pipelineId}", "enter_target": "Target deployment environment", + "enter_task": "Deployment task", "trigger": "Deploy", "variables": { "delete": "Delete variable", diff --git a/web/src/components/layout/popups/DeployPipelinePopup.vue b/web/src/components/layout/popups/DeployPipelinePopup.vue index 57b88cd9d..9a4eefea7 100644 --- a/web/src/components/layout/popups/DeployPipelinePopup.vue +++ b/web/src/components/layout/popups/DeployPipelinePopup.vue @@ -8,6 +8,9 @@ + + + {{ $t('repo.deploy_pipeline.variables.desc') }}
@@ -69,9 +72,10 @@ const repo = inject('repo'); const router = useRouter(); -const payload = ref<{ id: string; environment: string; variables: { name: string; value: string }[] }>({ +const payload = ref<{ id: string; environment: string; task: string; variables: { name: string; value: string }[] }>({ id: '', environment: '', + task: '', variables: [ { name: '', diff --git a/web/src/lib/api/index.ts b/web/src/lib/api/index.ts index 6c994ed7b..13fdde5cc 100644 --- a/web/src/lib/api/index.ts +++ b/web/src/lib/api/index.ts @@ -31,6 +31,7 @@ type PipelineOptions = { type DeploymentOptions = { id: string; environment: string; + task: string; variables: Record; }; @@ -89,12 +90,13 @@ export default class WoodpeckerClient extends ApiClient { } // Deploy triggers a deployment for an existing pipeline using the - // specified target environment. + // specified target environment and task. deployPipeline(repoId: number, pipelineNumber: string, options: DeploymentOptions): Promise { const vars = { ...options.variables, event: 'deployment', deploy_to: options.environment, + deploy_task: options.task, }; const query = encodeQueryString(vars); return this._post(`/api/repos/${repoId}/pipelines/${pipelineNumber}?${query}`) as Promise;