fix(custom-fields): address code review findings
Generic: Repo Health / Access control (push) Has been cancelled
Generic: Repo Health / Site Health (push) Has been cancelled
Branch Policy Check / Verify merge target (pull_request) Has been cancelled
Universal: PR Check / Branch Policy (pull_request) Has been cancelled
Generic: Repo Health / Site Health (pull_request) Has been cancelled
Generic: Repo Health / Access control (pull_request) Has been cancelled
PR RC Release / Build RC Release (pull_request) Has been cancelled
Universal: PR Check / Validate PR (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled

- API: return 500 on GetCustomFieldsByOwner failure instead of silently
  swallowing the error
- resolveExtensionMetadata: add DownloadGating/KeyPrefix to metadata
  struct instead of mutating the caller's cfg pointer (side effect)
- resolveExtensionMetadata: add Description custom field mapping
- Composer: use meta.PHPMinimum instead of bypassing the cascade
- Web form: flash error on custom field save failure instead of silent log

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan Miller
2026-06-04 21:59:50 -05:00
parent b72f88e78b
commit cd4c701cb6
4 changed files with 30 additions and 14 deletions
+5 -1
View File
@@ -705,7 +705,11 @@ func CreateIssue(ctx *context.APIContext) {
// Save custom field values if provided (resolve field names to IDs).
if len(form.CustomFields) > 0 {
defs, defErr := issues_model.GetCustomFieldsByOwner(ctx, ctx.Repo.Repository.OwnerID, issues_model.CustomFieldScopeIssue)
if defErr == nil && len(defs) > 0 {
if defErr != nil {
ctx.APIErrorInternal(defErr)
return
}
if len(defs) > 0 {
vals := make(map[int64]string)
for _, def := range defs {
if v, ok := form.CustomFields[def.Name]; ok {
+1
View File
@@ -441,6 +441,7 @@ func saveCustomFieldsFromForm(ctx *context.Context, ownerID, issueID int64) {
if len(vals) > 0 {
if err := issues_model.SetCustomFieldValues(ctx, issueID, vals); err != nil {
log.Error("saveCustomFieldsFromForm: %v", err)
ctx.Flash.Error("Failed to save custom field values")
}
}
}
+2 -2
View File
@@ -87,8 +87,8 @@ func GenerateComposerJSON(ctx context.Context, repo *repo_model.Repository, lice
}
phpMin := ""
if cfg != nil && cfg.PHPMinimum != "" {
phpMin = ">=" + cfg.PHPMinimum
if meta.PHPMinimum != "" {
phpMin = ">=" + meta.PHPMinimum
}
streams := licenses.GetEffectiveStreams(ctx, repo.OwnerID, repo.ID)
+22 -11
View File
@@ -164,13 +164,15 @@ func NormalizeChannel(ch string) string {
// extensionMetadata holds resolved metadata for feed generation.
// Fields are resolved with priority: custom field → config table → default.
type extensionMetadata struct {
Element string
DisplayName string
ExtType string
TargetVersion string
PHPMinimum string
Description string
SupportURL string
Element string
DisplayName string
ExtType string
TargetVersion string
PHPMinimum string
Description string
SupportURL string
DownloadGating string
KeyPrefix string
}
// resolveExtensionMetadata loads extension metadata with cascading fallback:
@@ -206,6 +208,12 @@ func resolveExtensionMetadata(ctx context.Context, repo *repo_model.Repository,
if cfg.SupportURL != "" {
m.SupportURL = cfg.SupportURL
}
if cfg.DownloadGating != "" {
m.DownloadGating = cfg.DownloadGating
}
if cfg.KeyPrefix != "" {
m.KeyPrefix = cfg.KeyPrefix
}
}
// Override with custom field values (highest priority).
@@ -244,11 +252,14 @@ func resolveExtensionMetadata(ctx context.Context, repo *repo_model.Repository,
if v := named["Support URL"]; v != "" {
m.SupportURL = v
}
if v := named["Download Gating"]; v != "" && cfg != nil {
cfg.DownloadGating = v
if v := named["Description"]; v != "" {
m.Description = v
}
if v := named["Key Prefix"]; v != "" && cfg != nil {
cfg.KeyPrefix = v
if v := named["Download Gating"]; v != "" {
m.DownloadGating = v
}
if v := named["Key Prefix"]; v != "" {
m.KeyPrefix = v
}
return m