From b4f48a64fc411e2ba732e14f30ed0997c6e84796 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 21 Apr 2026 11:47:51 -0700 Subject: [PATCH] =?UTF-8?q?Fix=20an=20issue=20where=20changing=20an=20orga?= =?UTF-8?q?nization=E2=80=99s=20visibility=20caused=20problems=20when=20us?= =?UTF-8?q?ers=20had=20forked=20its=20repositories.=20(#37324)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A quick fix #37317 --- The current behavior for forks when an organization or repository is changed to private differs from GitHub. On GitHub, when a parent repository becomes private, the fork relationship is removed, which keeps the behavior simple and avoids visibility conflicts. I think we need a similar solution to handle cases where the parent repository becomes private while a fork remains public and the fork relationship is still preserved. --------- Signed-off-by: Lunny Xiao Co-authored-by: silverwind Co-authored-by: wxiaoguang Co-authored-by: Giteabot --- services/org/org.go | 16 ++++++++++------ services/org/org_test.go | 8 ++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/services/org/org.go b/services/org/org.go index 32c46d7cb9c..629b5acc443 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -102,10 +102,14 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge return nil } -func updateOrgRepoForVisibilityChanged(ctx context.Context, repo *repo_model.Repository, makePrivate bool) error { +func updateRepoForVisibilityChanged(ctx context.Context, repo *repo_model.Repository, makePrivate bool) error { + if err := repo.LoadOwner(ctx); err != nil { + return fmt.Errorf("LoadOwner: %w", err) + } + // Organization repository need to recalculate access table when visibility is changed. - if err := access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil { - return fmt.Errorf("recalculateTeamAccesses: %w", err) + if err := access_model.RecalculateAccesses(ctx, repo); err != nil { + return fmt.Errorf("RecalculateAccesses: %w", err) } if makePrivate { @@ -135,7 +139,7 @@ func updateOrgRepoForVisibilityChanged(ctx context.Context, repo *repo_model.Rep return fmt.Errorf("getRepositoriesByForkID: %w", err) } for i := range forkRepos { - if err := updateOrgRepoForVisibilityChanged(ctx, forkRepos[i], makePrivate); err != nil { + if err := updateRepoForVisibilityChanged(ctx, forkRepos[i], makePrivate); err != nil { return fmt.Errorf("updateRepoForVisibilityChanged[%s]: %w", forkRepos[i].FullName(), err) } } @@ -161,8 +165,8 @@ func ChangeOrganizationVisibility(ctx context.Context, org *org_model.Organizati return err } for _, repo := range repos { - if err := updateOrgRepoForVisibilityChanged(ctx, repo, visibility == structs.VisibleTypePrivate); err != nil { - return fmt.Errorf("updateOrgRepoForVisibilityChanged: %w", err) + if err := updateRepoForVisibilityChanged(ctx, repo, visibility == structs.VisibleTypePrivate); err != nil { + return fmt.Errorf("updateRepoForVisibilityChanged: %w", err) } } return nil diff --git a/services/org/org_test.go b/services/org/org_test.go index 5253c739020..9c0aa163df4 100644 --- a/services/org/org_test.go +++ b/services/org/org_test.go @@ -10,6 +10,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -60,4 +61,11 @@ func TestOrg(t *testing.T) { assert.Error(t, DeleteOrganization(t.Context(), user, false)) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{}) }) + + t.Run("ChangeVisibilityWithUserFork", func(t *testing.T) { + // org 19 has a repository 27 which has a forked repository 29 by user 20 + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 19}) + require.NoError(t, ChangeOrganizationVisibility(t.Context(), org, structs.VisibleTypePrivate)) + unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: org.ID, Visibility: structs.VisibleTypePrivate}) + }) }