diff --git a/internal/cmd/epic/create/create.go b/internal/cmd/epic/create/create.go index 9fbe52c4..bacc0ee7 100644 --- a/internal/cmd/epic/create/create.go +++ b/internal/cmd/epic/create/create.go @@ -109,6 +109,7 @@ func create(cmd *cobra.Command, _ []string) { Components: params.Components, FixVersions: params.FixVersions, AffectsVersions: params.AffectsVersions, + DueDate: params.DueDate, CustomFields: params.CustomFields, EpicField: viper.GetString("epic.name"), } @@ -235,6 +236,10 @@ func parseFlags(flags query.FlagParser) *cmdcommon.CreateParams { affectsVersions, err := flags.GetStringArray("affects-version") cmdutil.ExitIfError(err) + dueDate, err := flags.GetString("due-date") + cmdutil.ExitIfError(err) + cmdutil.ExitIfError(cmdcommon.ValidateDueDate(dueDate)) + custom, err := flags.GetStringToString("custom") cmdutil.ExitIfError(err) @@ -258,6 +263,7 @@ func parseFlags(flags query.FlagParser) *cmdcommon.CreateParams { Components: components, FixVersions: fixVersions, AffectsVersions: affectsVersions, + DueDate: dueDate, CustomFields: custom, Template: template, NoInput: noInput, diff --git a/internal/cmd/issue/create/create.go b/internal/cmd/issue/create/create.go index 78e48662..ea7a3470 100644 --- a/internal/cmd/issue/create/create.go +++ b/internal/cmd/issue/create/create.go @@ -122,6 +122,7 @@ func create(cmd *cobra.Command, _ []string) { FixVersions: params.FixVersions, AffectsVersions: params.AffectsVersions, OriginalEstimate: params.OriginalEstimate, + DueDate: params.DueDate, CustomFields: params.CustomFields, EpicField: viper.GetString("epic.link"), } @@ -367,6 +368,10 @@ func parseFlags(flags query.FlagParser) *cmdcommon.CreateParams { originalEstimate, err := flags.GetString("original-estimate") cmdutil.ExitIfError(err) + dueDate, err := flags.GetString("due-date") + cmdutil.ExitIfError(err) + cmdutil.ExitIfError(cmdcommon.ValidateDueDate(dueDate)) + custom, err := flags.GetStringToString("custom") cmdutil.ExitIfError(err) @@ -392,6 +397,7 @@ func parseFlags(flags query.FlagParser) *cmdcommon.CreateParams { FixVersions: fixVersions, AffectsVersions: affectsVersions, OriginalEstimate: originalEstimate, + DueDate: dueDate, CustomFields: custom, Template: template, NoInput: noInput, diff --git a/internal/cmdcommon/create.go b/internal/cmdcommon/create.go index 7615ba70..9aba903a 100644 --- a/internal/cmdcommon/create.go +++ b/internal/cmdcommon/create.go @@ -1,7 +1,9 @@ package cmdcommon import ( + "fmt" "strings" + "time" "github.com/AlecAivazis/survey/v2" "github.com/spf13/cobra" @@ -36,6 +38,7 @@ type CreateParams struct { FixVersions []string AffectsVersions []string OriginalEstimate string + DueDate string CustomFields map[string]string Template string NoInput bool @@ -65,6 +68,7 @@ And, this field is mandatory when creating a sub-task.`) cmd.Flags().StringArray("fix-version", []string{}, "Release info (fixVersions)") cmd.Flags().StringArray("affects-version", []string{}, "Release info (affectsVersions)") cmd.Flags().StringP("original-estimate", "e", "", prefix+" Original estimate") + cmd.Flags().String("due-date", "", prefix+" due date (format: YYYY-MM-DD)") cmd.Flags().StringToString("custom", custom, "Set custom fields") cmd.Flags().StringP("template", "T", "", "Path to a file to read body/description from") cmd.Flags().Bool("web", false, "Open in web browser after successful creation") @@ -239,6 +243,17 @@ func GetConfiguredCustomFields() ([]jira.IssueTypeField, error) { return configuredFields, nil } +// ValidateDueDate validates that the due date is in YYYY-MM-DD format. +func ValidateDueDate(dueDate string) error { + if dueDate == "" { + return nil + } + if _, err := time.Parse("2006-01-02", dueDate); err != nil { + return fmt.Errorf("invalid due date %q: expected format YYYY-MM-DD", dueDate) + } + return nil +} + // ValidateCustomFields validates custom fields. // TODO: Fail with error instead of warning in future release. func ValidateCustomFields(fields map[string]string, configuredFields []jira.IssueTypeField) { diff --git a/pkg/jira/create.go b/pkg/jira/create.go index bec14918..c19b77bc 100644 --- a/pkg/jira/create.go +++ b/pkg/jira/create.go @@ -35,6 +35,7 @@ type CreateRequest struct { FixVersions []string AffectsVersions []string OriginalEstimate string + DueDate string // EpicField is the dynamic epic field name // that changes per jira installation. EpicField string @@ -132,6 +133,7 @@ func (*Client) getRequestData(req *CreateRequest) *createRequest { Name: req.Name, Summary: req.Summary, Labels: req.Labels, + DueDate: req.DueDate, epicField: req.EpicField, } @@ -221,7 +223,6 @@ func (*Client) getRequestData(req *CreateRequest) *createRequest { OriginalEstimate string `json:"originalEstimate,omitempty"` }{OriginalEstimate: req.OriginalEstimate} } - constructCustomFields(req.CustomFields, req.configuredCustomFields, &data) return &data @@ -313,6 +314,7 @@ type createFields struct { TimeTracking *struct { OriginalEstimate string `json:"originalEstimate,omitempty"` } `json:"timetracking,omitempty"` + DueDate string `json:"duedate,omitempty"` epicField string customFields customField } diff --git a/pkg/jira/create_test.go b/pkg/jira/create_test.go index fab756c4..8bdb7439 100644 --- a/pkg/jira/create_test.go +++ b/pkg/jira/create_test.go @@ -47,7 +47,7 @@ func TestCreate(t *testing.T) { expectedBody := `{"update":{},"fields":{"project":{"key":"TEST"},"issuetype":{"name":"Bug"},` + `"summary":"Test bug","description":"Test description","priority":{"name":"Normal"},"labels":["test","dev"],` + `"components":[{"name":"BE"},{"name":"FE"}],"fixVersions":[{"name":"v2.0"},{"name":"v2.1-hotfix"}],"versions":[{"name":"v3.0"},{"name":"v3.1-hotfix"}],` + - `"timetracking":{"originalEstimate":"2d"}}}` + `"timetracking":{"originalEstimate":"2d"},"duedate":"2006-01-02"}}` testServer := createTestServer{code: 201} server := testServer.serve(t, expectedBody) defer server.Close() @@ -65,6 +65,7 @@ func TestCreate(t *testing.T) { FixVersions: []string{"v2.0", "v2.1-hotfix"}, AffectsVersions: []string{"v3.0", "v3.1-hotfix"}, OriginalEstimate: "2d", + DueDate: "2006-01-02", } actual, err := client.CreateV2(&requestData) assert.NoError(t, err)