From b9eb5eccd83e73ab6fb392557b7036063244f357 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Wed, 9 Aug 2023 00:06:25 +0200 Subject: [PATCH] [UPGRADE] add sanity checks for [storage*] Refs: https://forgejo.org/2023-08-release-v1-20-3-0/ (cherry picked from commit a266dd0ce3fca1296c6713ff1266f0065f0cd72b) --- models/forgejo/semver/semver.go | 5 +- services/forgejo/sanity.go | 3 +- services/forgejo/sanity_v1TOv5_0_1Included.go | 91 ++++++++++++++ .../forgejo/sanity_v1TOv5_0_1Included_test.go | 115 ++++++++++++++++++ 4 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 services/forgejo/sanity_v1TOv5_0_1Included.go create mode 100644 services/forgejo/sanity_v1TOv5_0_1Included_test.go diff --git a/models/forgejo/semver/semver.go b/models/forgejo/semver/semver.go index 50923d0a09..7f122d2301 100644 --- a/models/forgejo/semver/semver.go +++ b/models/forgejo/semver/semver.go @@ -14,6 +14,8 @@ func init() { db.RegisterModel(new(ForgejoSemVer)) } +var DefaultVersionString = "1.0.0" + type ForgejoSemVer struct { Version string } @@ -23,7 +25,8 @@ func GetVersion(ctx context.Context) (*version.Version, error) { } func GetVersionWithEngine(e db.Engine) (*version.Version, error) { - versionString := "v1.0.0" + versionString := DefaultVersionString + exists, err := e.IsTableExist("forgejo_sem_ver") if err != nil { return nil, err diff --git a/services/forgejo/sanity.go b/services/forgejo/sanity.go index 0ca85c8406..5e817d67f5 100644 --- a/services/forgejo/sanity.go +++ b/services/forgejo/sanity.go @@ -9,6 +9,7 @@ import ( ) var ( + ForgejoV6DatabaseVersion = int64(261) // must be updated once v6 / Gitea v1.21 is out ForgejoV5DatabaseVersion = int64(260) ForgejoV4DatabaseVersion = int64(244) ) @@ -21,5 +22,5 @@ func fatal(err error) error { } func PreMigrationSanityChecks(e db.Engine, dbVersion int64, cfg setting.ConfigProvider) error { - return nil + return v1TOv5_0_1Included(e, dbVersion, cfg) } diff --git a/services/forgejo/sanity_v1TOv5_0_1Included.go b/services/forgejo/sanity_v1TOv5_0_1Included.go new file mode 100644 index 0000000000..49de636f33 --- /dev/null +++ b/services/forgejo/sanity_v1TOv5_0_1Included.go @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: MIT + +package forgejo + +import ( + "fmt" + "strings" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/forgejo/semver" + "code.gitea.io/gitea/modules/setting" + + "github.com/hashicorp/go-version" +) + +var v1TOv5_0_1IncludedStorageSections = []struct { + section string + storageSection string +}{ + {"attachment", "storage.attachments"}, + {"lfs", "storage.lfs"}, + {"avatar", "storage.avatars"}, + {"repo-avatar", "storage.repo-avatars"}, + {"repo-archive", "storage.repo-archive"}, + {"packages", "storage.packages"}, + // the actions sections are not included here because they were experimental at the time +} + +func v1TOv5_0_1Included(e db.Engine, dbVersion int64, cfg setting.ConfigProvider) error { + // + // When upgrading from Forgejo > v5 or Gitea > v1.20, no sanity check is necessary + // + if dbVersion > ForgejoV5DatabaseVersion { + return nil + } + + // + // When upgrading from a Forgejo point version >= v5.0.1, no sanity + // check is necessary + // + // When upgrading from a Gitea >= v1.20 the sanitiy checks will + // always be done They are necessary for Gitea [v1.20.0..v1.20.2] + // but not for [v1.20.3..] but there is no way to know which point + // release was running prior to the upgrade. This may require the + // Gitea admin to update their app.ini although it is not necessary + // but will have no other consequence. + // + previousServerVersion, err := semver.GetVersionWithEngine(e) + if err != nil { + return err + } + upper, err := version.NewVersion("v5.0.1") + if err != nil { + return err + } + + if previousServerVersion.GreaterThan(upper) { + return nil + } + + // + // Sanity checks + // + + originalCfg, err := cfg.PrepareSaving() + if err != nil { + return err + } + + messages := make([]string, 0, 10) + for _, c := range v1TOv5_0_1IncludedStorageSections { + section, _ := originalCfg.GetSection(c.section) + if section == nil { + continue + } + storageSection, _ := originalCfg.GetSection(c.storageSection) + if storageSection == nil { + continue + } + messages = append(messages, fmt.Sprintf("[%s] and [%s] may conflict with each other", c.section, c.storageSection)) + } + + if originalCfg.Section("storage").HasKey("PATH") { + messages = append(messages, "[storage].PATH is set and may create storage issues") + } + + if len(messages) > 0 { + return fatal(fmt.Errorf("%s\nThese issues need to be manually fixed in the app.ini file at %s. Please read https://forgejo.org/2023-08-release-v1-20-3-0/ for instructions", strings.Join(messages, "\n"), cfg.GetFile())) + } + return nil +} diff --git a/services/forgejo/sanity_v1TOv5_0_1Included_test.go b/services/forgejo/sanity_v1TOv5_0_1Included_test.go new file mode 100644 index 0000000000..93bca0d2fb --- /dev/null +++ b/services/forgejo/sanity_v1TOv5_0_1Included_test.go @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT + +package forgejo + +import ( + "fmt" + "testing" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/forgejo/semver" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/log" + + "github.com/stretchr/testify/assert" +) + +func TestForgejo_v1TOv5_0_1Included(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + logFatal = func(string, ...any) {} + defer func() { + logFatal = log.Fatal + }() + + configWithSoragePath := ` +[storage] +PATH = /something +` + verifyForgejoV1TOv5_0_1Included(t, configWithSoragePath, "[storage].PATH is set") + + for _, c := range v1TOv5_0_1IncludedStorageSections { + config := fmt.Sprintf("[%s]\n[%s]\n", c.section, c.storageSection) + verifyForgejoV1TOv5_0_1Included(t, config, fmt.Sprintf("[%s] and [%s]", c.section, c.storageSection)) + } +} + +func verifyForgejoV1TOv5_0_1Included(t *testing.T, config, message string) { + ctx := db.DefaultContext + e := db.GetEngine(ctx) + + for _, testCase := range []struct { + name string + dbVersion int64 + semver string + config string + }{ + { + name: "5.0.0 with no " + message, + dbVersion: ForgejoV5DatabaseVersion, + semver: "5.0.0+0-gitea-1.20.1", + config: "", + }, + { + name: "5.0.1 with no " + message, + dbVersion: ForgejoV5DatabaseVersion, + semver: "5.0.1+0-gitea-1.20.2", + config: "", + }, + { + name: "5.0.2 with " + message, + dbVersion: ForgejoV5DatabaseVersion, + semver: "5.0.2+0-gitea-1.20.3", + config: config, + }, + { + name: "6.0.0 with " + message, + dbVersion: ForgejoV6DatabaseVersion, + semver: "6.0.0+0-gitea-1.21.0", + config: config, + }, + } { + cfg := configFixture(t, testCase.config) + semver.SetVersionString(ctx, testCase.semver) + assert.NoError(t, v1TOv5_0_1Included(e, testCase.dbVersion, cfg)) + } + + for _, testCase := range []struct { + name string + dbVersion int64 + semver string + config string + }{ + { + name: "5.0.0 with " + message, + dbVersion: ForgejoV5DatabaseVersion, + semver: "5.0.0+0-gitea-1.20.1", + config: config, + }, + { + name: "5.0.1 with " + message, + dbVersion: ForgejoV5DatabaseVersion, + semver: "5.0.1+0-gitea-1.20.2", + config: config, + }, + { + // + // When upgrading from + // + // Forgejo >= 5.0.1+0-gitea-1.20.2 + // Gitea > v1.21 + // + // The version that the server was running prior to the upgrade + // is not available. + // + name: semver.DefaultVersionString + " with " + message, + dbVersion: ForgejoV4DatabaseVersion, + semver: semver.DefaultVersionString, + config: config, + }, + } { + cfg := configFixture(t, testCase.config) + semver.SetVersionString(ctx, testCase.semver) + assert.ErrorContains(t, v1TOv5_0_1Included(e, testCase.dbVersion, cfg), message) + } +}