From bd35e3b7bc2d64e649915c5103067be1c7ffbe44 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) (cherry picked from commit b9eb5eccd83e73ab6fb392557b7036063244f357) (cherry picked from commit 7fc2028ede6e3a576c3714b27940de9f871c33bd) (cherry picked from commit 0c988e612028eab277f03c16c0597da08c2c293a) (cherry picked from commit 7ba05e8c2b51c4c08ab3885f9014f7bdaf3d0f6b) (cherry picked from commit 2ed5068abe0cb57a257167d669faee207762b1d0) (cherry picked from commit 353913a26dd749f017cf8b76cf9218f68e8ca408) (cherry picked from commit 4e63a01a8bf9d0c8a1a6a6d7a3b18c64369bbaf1) (cherry picked from commit 99f612aed30852b23fe325bd5b6095aee9bd558e) (cherry picked from commit b4fe189caea9c656edd9c0c20e0d667911e4921c) --- 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) + } +}