From db7ba9182e0919dc9fef7fc73c69a081e800bcdb Mon Sep 17 00:00:00 2001 From: "m.huber" Date: Tue, 5 Aug 2025 03:11:09 +0200 Subject: [PATCH 1/3] Add `has_code` to repository REST API --- modules/structs/repo.go | 3 +++ routers/api/v1/repo/repo.go | 17 +++++++++++++++++ templates/swagger/v1_json.tmpl | 9 +++++++++ 3 files changed, 29 insertions(+) diff --git a/modules/structs/repo.go b/modules/structs/repo.go index f2e11b154268c..404718def0f81 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -84,6 +84,7 @@ type Repository struct { Updated time.Time `json:"updated_at"` ArchivedAt time.Time `json:"archived_at"` Permissions *Permission `json:"permissions,omitempty"` + HasCode bool `json:"has_code"` HasIssues bool `json:"has_issues"` InternalTracker *InternalTracker `json:"internal_tracker,omitempty"` ExternalTracker *ExternalTracker `json:"external_tracker,omitempty"` @@ -170,6 +171,8 @@ type EditRepoOption struct { Private *bool `json:"private,omitempty"` // either `true` to make this repository a template or `false` to make it a normal repository Template *bool `json:"template,omitempty"` + // either `true` to enable code for this repository or `false` to disable it. + HasCode *bool `json:"has_code,omitempty"` // either `true` to enable issues for this repository or `false` to disable them. HasIssues *bool `json:"has_issues,omitempty"` // set this structure to configure internal issue tracker diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 4b88ed0b78199..cd4faa4e7715e 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -879,6 +879,23 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { } } + currHasCode := repo.UnitEnabled(ctx, unit_model.TypeCode) + newHasCode := currHasCode + if opts.HasCode != nil { + newHasCode = *opts.HasCode + } + if currHasCode || newHasCode { + if newHasCode && !unit_model.TypeCode.UnitGlobalDisabled() { + units = append(units, repo_model.RepoUnit{ + RepoID: repo.ID, + Type: unit_model.TypeCode, + Config: &repo_model.UnitConfig{}, + }) + } else if !newHasCode && !unit_model.TypeCode.UnitGlobalDisabled() { + deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode) + } + } + currHasPullRequests := repo.UnitEnabled(ctx, unit_model.TypePullRequests) newHasPullRequests := currHasPullRequests if opts.HasPullRequests != nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 35c743dcd4a24..56c294380d97f 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -24328,6 +24328,11 @@ "external_wiki": { "$ref": "#/definitions/ExternalWiki" }, + "has_code": { + "description": "either `true` to enable code for this repository or `false` to disable it.", + "type": "boolean", + "x-go-name": "HasCode" + }, "has_actions": { "description": "either `true` to enable actions unit, or `false` to disable them.", "type": "boolean", @@ -27371,6 +27376,10 @@ "type": "string", "x-go-name": "FullName" }, + "has_code": { + "type": "boolean", + "x-go-name": "HasCode" + }, "has_actions": { "type": "boolean", "x-go-name": "HasActions" From dbb148566997793aeed579883c5258de93edb4d7 Mon Sep 17 00:00:00 2001 From: "m.huber" Date: Tue, 5 Aug 2025 16:24:11 +0200 Subject: [PATCH 2/3] swagger generate --- templates/swagger/v1_json.tmpl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 56c294380d97f..749d86901de93 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -24328,16 +24328,16 @@ "external_wiki": { "$ref": "#/definitions/ExternalWiki" }, - "has_code": { - "description": "either `true` to enable code for this repository or `false` to disable it.", - "type": "boolean", - "x-go-name": "HasCode" - }, "has_actions": { "description": "either `true` to enable actions unit, or `false` to disable them.", "type": "boolean", "x-go-name": "HasActions" }, + "has_code": { + "description": "either `true` to enable code for this repository or `false` to disable it.", + "type": "boolean", + "x-go-name": "HasCode" + }, "has_issues": { "description": "either `true` to enable issues for this repository or `false` to disable them.", "type": "boolean", @@ -27376,14 +27376,14 @@ "type": "string", "x-go-name": "FullName" }, - "has_code": { - "type": "boolean", - "x-go-name": "HasCode" - }, "has_actions": { "type": "boolean", "x-go-name": "HasActions" }, + "has_code": { + "type": "boolean", + "x-go-name": "HasCode" + }, "has_issues": { "type": "boolean", "x-go-name": "HasIssues" From 5bbe2380f393f9340b33b5c15bc6ad5c7f9923c4 Mon Sep 17 00:00:00 2001 From: "m.huber" Date: Wed, 6 Aug 2025 17:22:15 +0200 Subject: [PATCH 3/3] more test coverage --- tests/integration/api_repo_edit_test.go | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/integration/api_repo_edit_test.go b/tests/integration/api_repo_edit_test.go index e228da26e992b..7fe59c0d09f3f 100644 --- a/tests/integration/api_repo_edit_test.go +++ b/tests/integration/api_repo_edit_test.go @@ -76,12 +76,36 @@ func getRepoEditOptionFromRepo(repo *repo_model.Repository) *api.EditRepoOption allowFastForwardOnly = config.AllowFastForwardOnly } archived := repo.IsArchived + hasProjects := false + var projectsMode *string + if unit, err := repo.GetUnit(db.DefaultContext, unit_model.TypeProjects); err == nil && unit != nil { + hasProjects = true + pm := string(unit.ProjectsConfig().ProjectsMode) + projectsMode = &pm + } + hasCode := repo.UnitEnabled(db.DefaultContext, unit_model.TypeCode) + hasPackages := repo.UnitEnabled(db.DefaultContext, unit_model.TypePackages) + hasReleases := repo.UnitEnabled(db.DefaultContext, unit_model.TypeReleases) + hasActions := false + if unit, err := repo.GetUnit(db.DefaultContext, unit_model.TypeActions); err == nil && unit != nil { + hasActions = true + // TODO: expose action config of repo to api + // actionsConfig = &api.RepoActionsConfig{ + // DisabledWorkflows: unit.ActionsConfig().DisabledWorkflows, + // } + } return &api.EditRepoOption{ Name: &name, Description: &description, Website: &website, Private: &private, HasIssues: &hasIssues, + HasProjects: &hasProjects, + ProjectsMode: projectsMode, + HasCode: &hasCode, + HasPackages: &hasPackages, + HasReleases: &hasReleases, + HasActions: &hasActions, ExternalTracker: externalTracker, InternalTracker: internalTracker, HasWiki: &hasWiki, @@ -108,6 +132,11 @@ func getNewRepoEditOption(opts *api.EditRepoOption) *api.EditRepoOption { private := !*opts.Private hasIssues := !*opts.HasIssues hasWiki := !*opts.HasWiki + hasProjects := !*opts.HasProjects + hasCode := !*opts.HasCode + hasPackages := !*opts.HasPackages + hasReleases := !*opts.HasReleases + hasActions := !*opts.HasActions defaultBranch := "master" hasPullRequests := !*opts.HasPullRequests ignoreWhitespaceConflicts := !*opts.IgnoreWhitespaceConflicts @@ -125,6 +154,11 @@ func getNewRepoEditOption(opts *api.EditRepoOption) *api.EditRepoOption { DefaultBranch: &defaultBranch, HasIssues: &hasIssues, HasWiki: &hasWiki, + HasProjects: &hasProjects, + HasCode: &hasCode, + HasPackages: &hasPackages, + HasReleases: &hasReleases, + HasActions: &hasActions, HasPullRequests: &hasPullRequests, IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts, AllowMerge: &allowMerge, @@ -156,6 +190,11 @@ func TestAPIRepoEdit(t *testing.T) { // Test editing a repo1 which user2 owns, changing name and many properties origRepoEditOption := getRepoEditOptionFromRepo(repo1) + assert.True(t, *origRepoEditOption.HasCode) + assert.True(t, *origRepoEditOption.HasPackages) + assert.True(t, *origRepoEditOption.HasProjects) + assert.True(t, *origRepoEditOption.HasReleases) + assert.True(t, *origRepoEditOption.HasActions) repoEditOption := getNewRepoEditOption(origRepoEditOption) req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", user2.Name, repo1.Name), &repoEditOption). AddTokenAuth(token2) @@ -177,6 +216,11 @@ func TestAPIRepoEdit(t *testing.T) { assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived) assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private) assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki) + assert.Equal(t, *repoEditOption.HasCode, *repo1editedOption.HasCode) + assert.Equal(t, *repoEditOption.HasPackages, *repo1editedOption.HasPackages) + assert.Equal(t, *repoEditOption.HasProjects, *repo1editedOption.HasProjects) + assert.Equal(t, *repoEditOption.HasReleases, *repo1editedOption.HasReleases) + assert.Equal(t, *repoEditOption.HasActions, *repo1editedOption.HasActions) // Test editing repo1 to use internal issue and wiki (default) *repoEditOption.HasIssues = true @@ -224,6 +268,11 @@ func TestAPIRepoEdit(t *testing.T) { assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker) assert.True(t, *repo1editedOption.HasWiki) assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki) + assert.False(t, *repo1editedOption.HasCode) + assert.False(t, *repo1editedOption.HasPackages) + assert.False(t, *repo1editedOption.HasProjects) + assert.False(t, *repo1editedOption.HasReleases) + assert.False(t, *repo1editedOption.HasActions) repoEditOption.ExternalTracker.ExternalTrackerStyle = "regexp" repoEditOption.ExternalTracker.ExternalTrackerRegexpPattern = `(\d+)` @@ -272,6 +321,11 @@ func TestAPIRepoEdit(t *testing.T) { assert.NotNil(t, *repo1editedOption.ExternalTracker) assert.True(t, *repo1editedOption.HasWiki) assert.NotNil(t, *repo1editedOption.ExternalWiki) + assert.False(t, *repo1editedOption.HasCode) + assert.False(t, *repo1editedOption.HasPackages) + assert.False(t, *repo1editedOption.HasProjects) + assert.False(t, *repo1editedOption.HasReleases) + assert.False(t, *repo1editedOption.HasActions) // reset repo in db req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", user2.Name, *repoEditOption.Name), &origRepoEditOption).