Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions pkg/github/__toolsnaps__/issue_write.snap
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@
"additionalProperties": false,
"properties": {
"delete": {
"description": "Set to true to clear this field's current value on the issue. Cannot be combined with 'value' or 'field_option_name'.",
"enum": [
true
],
"description": "Set to true to clear this field's current value on the issue. Cannot be combined with 'value' or 'field_option_name'. Omit this property, or set it to false, to leave the field's current value unchanged.",
"type": "boolean"
},
"field_name": {
Expand Down
5 changes: 3 additions & 2 deletions pkg/github/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -2287,9 +2287,10 @@ Options are:
},
"delete": {
Type: "boolean",
Enum: []any{true},
Description: "Set to true to clear this field's current value on the " +
"issue. Cannot be combined with 'value' or 'field_option_name'.",
"issue. Cannot be combined with 'value' or 'field_option_name'. " +
"Omit this property, or set it to false, to leave the field's " +
"current value unchanged.",
},
},
Required: []string{"field_name"},
Expand Down
57 changes: 57 additions & 0 deletions pkg/github/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2098,6 +2098,63 @@ func Test_issueWriteHasNonFormParams(t *testing.T) {
}
}

// Test_optionalIssueWriteFields covers parsing of issue_write's issue_fields
// items. The delete:false cases matter because the schema deliberately does not
// constrain 'delete' to a single value: clients that populate every property of
// a schema need a way to say "not deleting", and false must be a no-op that
// falls through to the normal value path.
func Test_optionalIssueWriteFields(t *testing.T) {
t.Parallel()

tests := []struct {
name string
item map[string]any
want issueWriteFieldInput
wantErr string
}{
{
name: "delete false alongside a value sets the value",
item: map[string]any{"field_name": "Start date", "value": "2026-08-14", "delete": false, "field_option_name": ""},
want: issueWriteFieldInput{FieldName: "Start date", Value: "2026-08-14"},
},
{
name: "delete true alone clears the field",
item: map[string]any{"field_name": "Start date", "delete": true},
want: issueWriteFieldInput{FieldName: "Start date", Delete: true},
},
{
name: "delete omitted with field_option_name",
item: map[string]any{"field_name": "Priority", "field_option_name": "High"},
want: issueWriteFieldInput{FieldName: "Priority", FieldOptionName: "High"},
},
{
name: "delete true with a value is rejected",
item: map[string]any{"field_name": "Start date", "value": "2026-08-14", "delete": true},
wantErr: "cannot specify 'delete' together with 'value' or 'field_option_name'",
},
{
name: "delete false with nothing to set is rejected",
item: map[string]any{"field_name": "Start date", "delete": false},
wantErr: "must specify either value or field_option_name",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := optionalIssueWriteFields(map[string]any{"issue_fields": []any{tc.item}})
if tc.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tc.wantErr)
return
}
require.NoError(t, err)
require.Len(t, got, 1)
assert.Equal(t, tc.want, got[0])
})
}
}

// Test_issueWriteSchemaClassification fails when a schema property is added
// without classifying it as either form-resendable (issueWriteFormParams) or
// known-non-form (knownNonForm below). Without this guard, an unclassified
Expand Down