diff --git a/.deadcode-out b/.deadcode-out
index 93bd2a976..7efe6f840 100644
--- a/.deadcode-out
+++ b/.deadcode-out
@@ -324,6 +324,7 @@ package "code.gitea.io/gitea/services/pull"
 
 package "code.gitea.io/gitea/services/repository"
 	func IsErrForkAlreadyExist
+	func UpdateRepositoryUnits
 
 package "code.gitea.io/gitea/services/repository/archiver"
 	func ArchiveRepository
diff --git a/services/repository/setting.go b/services/repository/setting.go
new file mode 100644
index 000000000..7dded5d6b
--- /dev/null
+++ b/services/repository/setting.go
@@ -0,0 +1,38 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+import (
+	"context"
+
+	"code.gitea.io/gitea/models/db"
+	repo_model "code.gitea.io/gitea/models/repo"
+	"code.gitea.io/gitea/models/unit"
+)
+
+// UpdateRepositoryUnits updates a repository's units
+func UpdateRepositoryUnits(ctx context.Context, repo *repo_model.Repository, units []repo_model.RepoUnit, deleteUnitTypes []unit.Type) (err error) {
+	ctx, committer, err := db.TxContext(ctx)
+	if err != nil {
+		return err
+	}
+	defer committer.Close()
+
+	// Delete existing settings of units before adding again
+	for _, u := range units {
+		deleteUnitTypes = append(deleteUnitTypes, u.Type)
+	}
+
+	if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil {
+		return err
+	}
+
+	if len(units) > 0 {
+		if err = db.Insert(ctx, units); err != nil {
+			return err
+		}
+	}
+
+	return committer.Commit()
+}