* Remove migration support from versions earlier than 1.6.0 * Remove unused functions * Update gogs upgrade instructions * Improve "latest" link as per @jolheiser Co-authored-by: Antoine GIRARD <sapk@users.noreply.github.com> Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>tags/v1.21.12.1
| @@ -70,9 +70,14 @@ There are some basic steps to follow. On a Linux system run as the Gogs user: | |||
| ## Upgrading to most recent `gitea` version | |||
| After successful migration from `gogs` to `gitea 1.0.x`, it is possible to upgrade to the recent `gitea` version. | |||
| Simply download the file matching the destination platform from the [downloads page](https://dl.gitea.io/gitea) | |||
| and replace the binary. | |||
| After successful migration from `gogs` to `gitea 1.0.x`, it is possible to upgrade `gitea` to a modern version | |||
| in a two steps process. | |||
| Upgrade to [`gitea 1.6.4`](https://dl.gitea.io/gitea/1.6.4/) first. Download the file matching | |||
| the destination platform from the [downloads page](https://dl.gitea.io/gitea/1.6.4/) and replace the binary. | |||
| Run Gitea at least once and check that everything works as expected. | |||
| Then repeat the procedure, but this time using the [lastest release](https://dl.gitea.io/gitea/{{< version >}}/). | |||
| ## Upgrading from a more recent version of Gogs | |||
| @@ -6,28 +6,17 @@ | |||
| package migrations | |||
| import ( | |||
| "bytes" | |||
| "encoding/json" | |||
| "fmt" | |||
| "io/ioutil" | |||
| "os" | |||
| "path" | |||
| "path/filepath" | |||
| "regexp" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/generate" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| gouuid "github.com/satori/go.uuid" | |||
| "github.com/unknwon/com" | |||
| ini "gopkg.in/ini.v1" | |||
| "xorm.io/xorm" | |||
| ) | |||
| const minDBVersion = 4 | |||
| const minDBVersion = 70 // Gitea 1.5.3 | |||
| // Migration describes on migration from lower version to high version | |||
| type Migration interface { | |||
| @@ -61,151 +50,31 @@ type Version struct { | |||
| Version int64 | |||
| } | |||
| func emptyMigration(x *xorm.Engine) error { | |||
| return nil | |||
| } | |||
| // This is a sequence of migrations. Add new migrations to the bottom of the list. | |||
| // If you want to "retire" a migration, remove it from the top of the list and | |||
| // update minDBVersion accordingly | |||
| var migrations = []Migration{ | |||
| // v0 -> v4: before 0.6.0 -> 0.7.33 | |||
| NewMigration("fix locale file load panic", fixLocaleFileLoadPanic), // V4 -> V5:v0.6.0 | |||
| NewMigration("trim action compare URL prefix", trimCommitActionAppURLPrefix), // V5 -> V6:v0.6.3 | |||
| NewMigration("generate issue-label from issue", issueToIssueLabel), // V6 -> V7:v0.6.4 | |||
| NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4 | |||
| NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16 | |||
| NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo), // V9 -> V10:v0.6.20 | |||
| NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5 | |||
| NewMigration("convert date to unix timestamp", convertDateToUnix), // V11 -> V12:v0.9.2 | |||
| NewMigration("convert LDAP UseSSL option to SecurityProtocol", ldapUseSSLToSecurityProtocol), // V12 -> V13:v0.9.37 | |||
| // v13 -> v14:v0.9.87 | |||
| NewMigration("set comment updated with created", setCommentUpdatedWithCreated), | |||
| // v14 -> v15 | |||
| NewMigration("create user column diff view style", createUserColumnDiffViewStyle), | |||
| // v15 -> v16 | |||
| NewMigration("create user column allow create organization", createAllowCreateOrganizationColumn), | |||
| // V16 -> v17 | |||
| NewMigration("create repo unit table and add units for all repos", addUnitsToTables), | |||
| // v17 -> v18 | |||
| NewMigration("set protect branches updated with created", setProtectedBranchUpdatedWithCreated), | |||
| // v18 -> v19 | |||
| NewMigration("add external login user", addExternalLoginUser), | |||
| // v19 -> v20 | |||
| NewMigration("generate and migrate Git hooks", generateAndMigrateGitHooks), | |||
| // v20 -> v21 | |||
| NewMigration("use new avatar path name for security reason", useNewNameAvatars), | |||
| // v21 -> v22 | |||
| NewMigration("rewrite authorized_keys file via new format", useNewPublickeyFormat), | |||
| // v22 -> v23 | |||
| NewMigration("generate and migrate wiki Git hooks", generateAndMigrateWikiGitHooks), | |||
| // v23 -> v24 | |||
| NewMigration("add user openid table", addUserOpenID), | |||
| // v24 -> v25 | |||
| NewMigration("change the key_id and primary_key_id type", changeGPGKeysColumns), | |||
| // v25 -> v26 | |||
| NewMigration("add show field in user openid table", addUserOpenIDShow), | |||
| // v26 -> v27 | |||
| NewMigration("generate and migrate repo and wiki Git hooks", generateAndMigrateGitHookChains), | |||
| // v27 -> v28 | |||
| NewMigration("change mirror interval from hours to time.Duration", convertIntervalToDuration), | |||
| // v28 -> v29 | |||
| NewMigration("add field for repo size", addRepoSize), | |||
| // v29 -> v30 | |||
| NewMigration("add commit status table", addCommitStatus), | |||
| // v30 -> 31 | |||
| NewMigration("add primary key to external login user", addExternalLoginUserPK), | |||
| // v31 -> 32 | |||
| NewMigration("add field for login source synchronization", addLoginSourceSyncEnabledColumn), | |||
| // v32 -> v33 | |||
| NewMigration("add units for team", addUnitsToRepoTeam), | |||
| // v33 -> v34 | |||
| NewMigration("remove columns from action", removeActionColumns), | |||
| // v34 -> v35 | |||
| NewMigration("give all units to owner teams", giveAllUnitsToOwnerTeams), | |||
| // v35 -> v36 | |||
| NewMigration("adds comment to an action", addCommentIDToAction), | |||
| // v36 -> v37 | |||
| NewMigration("regenerate git hooks", regenerateGitHooks36), | |||
| // v37 -> v38 | |||
| NewMigration("unescape user full names", unescapeUserFullNames), | |||
| // v38 -> v39 | |||
| NewMigration("remove commits and settings unit types", removeCommitsUnitType), | |||
| // v39 -> v40 | |||
| NewMigration("add tags to releases and sync existing repositories", releaseAddColumnIsTagAndSyncTags), | |||
| // v40 -> v41 | |||
| NewMigration("fix protected branch can push value to false", fixProtectedBranchCanPushValue), | |||
| // v41 -> v42 | |||
| NewMigration("remove duplicate unit types", removeDuplicateUnitTypes), | |||
| // v42 -> v43 | |||
| NewMigration("empty step", emptyMigration), | |||
| // v43 -> v44 | |||
| NewMigration("empty step", emptyMigration), | |||
| // v44 -> v45 | |||
| NewMigration("empty step", emptyMigration), | |||
| // v45 -> v46 | |||
| NewMigration("remove index column from repo_unit table", removeIndexColumnFromRepoUnitTable), | |||
| // v46 -> v47 | |||
| NewMigration("remove organization watch repositories", removeOrganizationWatchRepo), | |||
| // v47 -> v48 | |||
| NewMigration("add deleted branches", addDeletedBranch), | |||
| // v48 -> v49 | |||
| NewMigration("add repo indexer status", addRepoIndexerStatus), | |||
| // v49 -> v50 | |||
| NewMigration("adds time tracking and stopwatches", addTimetracking), | |||
| // v50 -> v51 | |||
| NewMigration("migrate protected branch struct", migrateProtectedBranchStruct), | |||
| // v51 -> v52 | |||
| NewMigration("add default value to user prohibit_login", addDefaultValueToUserProhibitLogin), | |||
| // v52 -> v53 | |||
| NewMigration("add lfs lock table", addLFSLock), | |||
| // v53 -> v54 | |||
| NewMigration("add reactions", addReactions), | |||
| // v54 -> v55 | |||
| NewMigration("add pull request options", addPullRequestOptions), | |||
| // v55 -> v56 | |||
| NewMigration("add writable deploy keys", addModeToDeploKeys), | |||
| // v56 -> v57 | |||
| NewMigration("remove is_owner, num_teams columns from org_user", removeIsOwnerColumnFromOrgUser), | |||
| // v57 -> v58 | |||
| NewMigration("add closed_unix column for issues", addIssueClosedTime), | |||
| // v58 -> v59 | |||
| NewMigration("add label descriptions", addLabelsDescriptions), | |||
| // v59 -> v60 | |||
| NewMigration("add merge whitelist for protected branches", addProtectedBranchMergeWhitelist), | |||
| // v60 -> v61 | |||
| NewMigration("add is_fsck_enabled column for repos", addFsckEnabledToRepo), | |||
| // v61 -> v62 | |||
| NewMigration("add size column for attachments", addSizeToAttachment), | |||
| // v62 -> v63 | |||
| NewMigration("add last used passcode column for TOTP", addLastUsedPasscodeTOTP), | |||
| // v63 -> v64 | |||
| NewMigration("add language column for user setting", addLanguageSetting), | |||
| // v64 -> v65 | |||
| NewMigration("add multiple assignees", addMultipleAssignees), | |||
| // v65 -> v66 | |||
| NewMigration("add u2f", addU2FReg), | |||
| // v66 -> v67 | |||
| NewMigration("add login source id column for public_key table", addLoginSourceIDToPublicKeyTable), | |||
| // v67 -> v68 | |||
| NewMigration("remove stale watches", removeStaleWatches), | |||
| // v68 -> V69 | |||
| NewMigration("Reformat and remove incorrect topics", reformatAndRemoveIncorrectTopics), | |||
| // v69 -> v70 | |||
| NewMigration("move team units to team_unit table", moveTeamUnitsToTeamUnitTable), | |||
| // Gitea 1.5.3 ends at v70 | |||
| // v70 -> v71 | |||
| NewMigration("add issue_dependencies", addIssueDependencies), | |||
| // v71 -> v72 | |||
| NewMigration("protect each scratch token", addScratchHash), | |||
| // v72 -> v73 | |||
| NewMigration("add review", addReview), | |||
| // Gitea 1.6.4 ends at v73 | |||
| // v73 -> v74 | |||
| NewMigration("add must_change_password column for users table", addMustChangePassword), | |||
| // v74 -> v75 | |||
| NewMigration("add approval whitelists to protected branches", addApprovalWhitelistsToProtectedBranches), | |||
| // v75 -> v76 | |||
| NewMigration("clear nonused data which not deleted when user was deleted", clearNonusedData), | |||
| // Gitea 1.7.6 ends at v76 | |||
| // v76 -> v77 | |||
| NewMigration("add pull request rebase with merge commit", addPullRequestRebaseWithMerge), | |||
| // v77 -> v78 | |||
| @@ -218,6 +87,9 @@ var migrations = []Migration{ | |||
| NewMigration("add is locked to issues", addIsLockedToIssues), | |||
| // v81 -> v82 | |||
| NewMigration("update U2F counter type", changeU2FCounterType), | |||
| // Gitea 1.8.3 ends at v82 | |||
| // v82 -> v83 | |||
| NewMigration("hot fix for wrong release sha1 on release table", fixReleaseSha1OnReleaseTable), | |||
| // v83 -> v84 | |||
| @@ -230,6 +102,9 @@ var migrations = []Migration{ | |||
| NewMigration("add http method to webhook", addHTTPMethodToWebhook), | |||
| // v87 -> v88 | |||
| NewMigration("add avatar field to repository", addAvatarFieldToRepository), | |||
| // Gitea 1.9.6 ends at v88 | |||
| // v88 -> v89 | |||
| NewMigration("add commit status context field to commit_status", addCommitStatusContext), | |||
| // v89 -> v90 | |||
| @@ -252,6 +127,9 @@ var migrations = []Migration{ | |||
| NewMigration("add repo_admin_change_team_access to user", addRepoAdminChangeTeamAccessColumnForUser), | |||
| // v98 -> v99 | |||
| NewMigration("add original author name and id on migrated release", addOriginalAuthorOnMigratedReleases), | |||
| // Gitea 1.10.3 ends at v99 | |||
| // v99 -> v100 | |||
| NewMigration("add task table and status column for repository table", addTaskTable), | |||
| // v100 -> v101 | |||
| @@ -334,7 +212,7 @@ func Migrate(x *xorm.Engine) error { | |||
| v := currentVersion.Version | |||
| if minDBVersion > v { | |||
| log.Fatal(`Gitea no longer supports auto-migration from your previously installed version. | |||
| Please try to upgrade to a lower version (>= v0.6.0) first, then upgrade to current version.`) | |||
| Please try upgrading to a lower version first (suggested v1.6.4), then upgrade to this version.`) | |||
| return nil | |||
| } | |||
| @@ -512,591 +390,3 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin | |||
| return nil | |||
| } | |||
| func fixLocaleFileLoadPanic(_ *xorm.Engine) error { | |||
| cfg, err := ini.Load(setting.CustomConf) | |||
| if err != nil { | |||
| return fmt.Errorf("load custom config: %v", err) | |||
| } | |||
| cfg.DeleteSection("i18n") | |||
| if err = cfg.SaveTo(setting.CustomConf); err != nil { | |||
| return fmt.Errorf("save custom config: %v", err) | |||
| } | |||
| setting.Langs = strings.Split(strings.Replace(strings.Join(setting.Langs, ","), "fr-CA", "fr-FR", 1), ",") | |||
| return nil | |||
| } | |||
| func trimCommitActionAppURLPrefix(x *xorm.Engine) error { | |||
| type PushCommit struct { | |||
| Sha1 string | |||
| Message string | |||
| AuthorEmail string | |||
| AuthorName string | |||
| } | |||
| type PushCommits struct { | |||
| Len int | |||
| Commits []*PushCommit | |||
| CompareURL string `json:"CompareUrl"` | |||
| } | |||
| type Action struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Content string `xorm:"TEXT"` | |||
| } | |||
| results, err := x.Query("SELECT `id`,`content` FROM `action` WHERE `op_type`=?", 5) | |||
| if err != nil { | |||
| return fmt.Errorf("select commit actions: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| var pushCommits *PushCommits | |||
| for _, action := range results { | |||
| actID := com.StrTo(string(action["id"])).MustInt64() | |||
| if actID == 0 { | |||
| continue | |||
| } | |||
| pushCommits = new(PushCommits) | |||
| if err = json.Unmarshal(action["content"], pushCommits); err != nil { | |||
| return fmt.Errorf("unmarshal action content[%d]: %v", actID, err) | |||
| } | |||
| infos := strings.Split(pushCommits.CompareURL, "/") | |||
| if len(infos) <= 4 { | |||
| continue | |||
| } | |||
| pushCommits.CompareURL = strings.Join(infos[len(infos)-4:], "/") | |||
| p, err := json.Marshal(pushCommits) | |||
| if err != nil { | |||
| return fmt.Errorf("marshal action content[%d]: %v", actID, err) | |||
| } | |||
| if _, err = sess.ID(actID).Update(&Action{ | |||
| Content: string(p), | |||
| }); err != nil { | |||
| return fmt.Errorf("update action[%d]: %v", actID, err) | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func issueToIssueLabel(x *xorm.Engine) error { | |||
| type IssueLabel struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| IssueID int64 `xorm:"UNIQUE(s)"` | |||
| LabelID int64 `xorm:"UNIQUE(s)"` | |||
| } | |||
| issueLabels := make([]*IssueLabel, 0, 50) | |||
| results, err := x.Query("SELECT `id`,`label_ids` FROM `issue`") | |||
| if err != nil { | |||
| if strings.Contains(err.Error(), "no such column") || | |||
| strings.Contains(err.Error(), "Unknown column") { | |||
| return nil | |||
| } | |||
| return fmt.Errorf("select issues: %v", err) | |||
| } | |||
| for _, issue := range results { | |||
| issueID := com.StrTo(issue["id"]).MustInt64() | |||
| // Just in case legacy code can have duplicated IDs for same label. | |||
| mark := make(map[int64]bool) | |||
| for _, idStr := range strings.Split(string(issue["label_ids"]), "|") { | |||
| labelID := com.StrTo(strings.TrimPrefix(idStr, "$")).MustInt64() | |||
| if labelID == 0 || mark[labelID] { | |||
| continue | |||
| } | |||
| mark[labelID] = true | |||
| issueLabels = append(issueLabels, &IssueLabel{ | |||
| IssueID: issueID, | |||
| LabelID: labelID, | |||
| }) | |||
| } | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if err = sess.Sync2(new(IssueLabel)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } else if _, err = sess.Insert(issueLabels); err != nil { | |||
| return fmt.Errorf("insert issue-labels: %v", err) | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func attachmentRefactor(x *xorm.Engine) error { | |||
| type Attachment struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| UUID string `xorm:"uuid INDEX"` | |||
| // For rename purpose. | |||
| Path string `xorm:"-"` | |||
| NewPath string `xorm:"-"` | |||
| } | |||
| results, err := x.Query("SELECT * FROM `attachment`") | |||
| if err != nil { | |||
| return fmt.Errorf("select attachments: %v", err) | |||
| } | |||
| attachments := make([]*Attachment, 0, len(results)) | |||
| for _, attach := range results { | |||
| if !com.IsExist(string(attach["path"])) { | |||
| // If the attachment is already missing, there is no point to update it. | |||
| continue | |||
| } | |||
| attachments = append(attachments, &Attachment{ | |||
| ID: com.StrTo(attach["id"]).MustInt64(), | |||
| UUID: gouuid.NewV4().String(), | |||
| Path: string(attach["path"]), | |||
| }) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if err = sess.Sync2(new(Attachment)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| // Note: Roll back for rename can be a dead loop, | |||
| // so produces a backup file. | |||
| var buf bytes.Buffer | |||
| buf.WriteString("# old path -> new path\n") | |||
| // Update database first because this is where error happens the most often. | |||
| for _, attach := range attachments { | |||
| if _, err = sess.ID(attach.ID).Update(attach); err != nil { | |||
| return err | |||
| } | |||
| attach.NewPath = path.Join(setting.AttachmentPath, attach.UUID[0:1], attach.UUID[1:2], attach.UUID) | |||
| buf.WriteString(attach.Path) | |||
| buf.WriteString("\t") | |||
| buf.WriteString(attach.NewPath) | |||
| buf.WriteString("\n") | |||
| } | |||
| // Then rename attachments. | |||
| isSucceed := true | |||
| defer func() { | |||
| if isSucceed { | |||
| return | |||
| } | |||
| dumpPath := path.Join(setting.LogRootPath, "attachment_path.dump") | |||
| ioutil.WriteFile(dumpPath, buf.Bytes(), 0666) | |||
| log.Info("Failed to rename some attachments, old and new paths are saved into: %s", dumpPath) | |||
| }() | |||
| for _, attach := range attachments { | |||
| if err = os.MkdirAll(path.Dir(attach.NewPath), os.ModePerm); err != nil { | |||
| isSucceed = false | |||
| return err | |||
| } | |||
| if err = os.Rename(attach.Path, attach.NewPath); err != nil { | |||
| isSucceed = false | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func renamePullRequestFields(x *xorm.Engine) (err error) { | |||
| type PullRequest struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| PullID int64 `xorm:"INDEX"` | |||
| PullIndex int64 | |||
| HeadBarcnh string | |||
| IssueID int64 `xorm:"INDEX"` | |||
| Index int64 | |||
| HeadBranch string | |||
| } | |||
| if err = x.Sync(new(PullRequest)); err != nil { | |||
| return fmt.Errorf("sync: %v", err) | |||
| } | |||
| results, err := x.Query("SELECT `id`,`pull_id`,`pull_index`,`head_barcnh` FROM `pull_request`") | |||
| if err != nil { | |||
| if strings.Contains(err.Error(), "no such column") { | |||
| return nil | |||
| } | |||
| return fmt.Errorf("select pull requests: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| var pull *PullRequest | |||
| for _, pr := range results { | |||
| pull = &PullRequest{ | |||
| ID: com.StrTo(pr["id"]).MustInt64(), | |||
| IssueID: com.StrTo(pr["pull_id"]).MustInt64(), | |||
| Index: com.StrTo(pr["pull_index"]).MustInt64(), | |||
| HeadBranch: string(pr["head_barcnh"]), | |||
| } | |||
| if pull.Index == 0 { | |||
| continue | |||
| } | |||
| if _, err = sess.ID(pull.ID).Update(pull); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func cleanUpMigrateRepoInfo(x *xorm.Engine) (err error) { | |||
| type ( | |||
| User struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| LowerName string | |||
| } | |||
| Repository struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| OwnerID int64 | |||
| LowerName string | |||
| } | |||
| ) | |||
| repos := make([]*Repository, 0, 25) | |||
| if err = x.Where("is_mirror=?", false).Find(&repos); err != nil { | |||
| return fmt.Errorf("select all non-mirror repositories: %v", err) | |||
| } | |||
| var user *User | |||
| for _, repo := range repos { | |||
| user = &User{ID: repo.OwnerID} | |||
| has, err := x.Get(user) | |||
| if err != nil { | |||
| return fmt.Errorf("get owner of repository[%d - %d]: %v", repo.ID, repo.OwnerID, err) | |||
| } else if !has { | |||
| continue | |||
| } | |||
| configPath := filepath.Join(setting.RepoRootPath, user.LowerName, repo.LowerName+".git/config") | |||
| // In case repository file is somehow missing. | |||
| if !com.IsFile(configPath) { | |||
| continue | |||
| } | |||
| cfg, err := ini.Load(configPath) | |||
| if err != nil { | |||
| return fmt.Errorf("open config file: %v", err) | |||
| } | |||
| cfg.DeleteSection("remote \"origin\"") | |||
| if err = cfg.SaveToIndent(configPath, "\t"); err != nil { | |||
| return fmt.Errorf("save config file: %v", err) | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func generateOrgRandsAndSalt(x *xorm.Engine) (err error) { | |||
| type User struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Rands string `xorm:"VARCHAR(10)"` | |||
| Salt string `xorm:"VARCHAR(10)"` | |||
| } | |||
| orgs := make([]*User, 0, 10) | |||
| if err = x.Where("type=1").And("rands=''").Find(&orgs); err != nil { | |||
| return fmt.Errorf("select all organizations: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| for _, org := range orgs { | |||
| if org.Rands, err = generate.GetRandomString(10); err != nil { | |||
| return err | |||
| } | |||
| if org.Salt, err = generate.GetRandomString(10); err != nil { | |||
| return err | |||
| } | |||
| if _, err = sess.ID(org.ID).Update(org); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| // TAction defines the struct for migrating table action | |||
| type TAction struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TAction) TableName() string { return "action" } | |||
| // TNotice defines the struct for migrating table notice | |||
| type TNotice struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TNotice) TableName() string { return "notice" } | |||
| // TComment defines the struct for migrating table comment | |||
| type TComment struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TComment) TableName() string { return "comment" } | |||
| // TIssue defines the struct for migrating table issue | |||
| type TIssue struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| DeadlineUnix int64 | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TIssue) TableName() string { return "issue" } | |||
| // TMilestone defines the struct for migrating table milestone | |||
| type TMilestone struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| DeadlineUnix int64 | |||
| ClosedDateUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TMilestone) TableName() string { return "milestone" } | |||
| // TAttachment defines the struct for migrating table attachment | |||
| type TAttachment struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TAttachment) TableName() string { return "attachment" } | |||
| // TLoginSource defines the struct for migrating table login_source | |||
| type TLoginSource struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TLoginSource) TableName() string { return "login_source" } | |||
| // TPull defines the struct for migrating table pull_request | |||
| type TPull struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| MergedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TPull) TableName() string { return "pull_request" } | |||
| // TRelease defines the struct for migrating table release | |||
| type TRelease struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TRelease) TableName() string { return "release" } | |||
| // TRepo defines the struct for migrating table repository | |||
| type TRepo struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TRepo) TableName() string { return "repository" } | |||
| // TMirror defines the struct for migrating table mirror | |||
| type TMirror struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| UpdatedUnix int64 | |||
| NextUpdateUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TMirror) TableName() string { return "mirror" } | |||
| // TPublicKey defines the struct for migrating table public_key | |||
| type TPublicKey struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TPublicKey) TableName() string { return "public_key" } | |||
| // TDeployKey defines the struct for migrating table deploy_key | |||
| type TDeployKey struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TDeployKey) TableName() string { return "deploy_key" } | |||
| // TAccessToken defines the struct for migrating table access_token | |||
| type TAccessToken struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TAccessToken) TableName() string { return "access_token" } | |||
| // TUser defines the struct for migrating table user | |||
| type TUser struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TUser) TableName() string { return "user" } | |||
| // TWebhook defines the struct for migrating table webhook | |||
| type TWebhook struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| CreatedUnix int64 | |||
| UpdatedUnix int64 | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (t *TWebhook) TableName() string { return "webhook" } | |||
| func convertDateToUnix(x *xorm.Engine) (err error) { | |||
| log.Info("This migration could take up to minutes, please be patient.") | |||
| type Bean struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Created time.Time | |||
| Updated time.Time | |||
| Merged time.Time | |||
| Deadline time.Time | |||
| ClosedDate time.Time | |||
| NextUpdate time.Time | |||
| } | |||
| var tables = []struct { | |||
| name string | |||
| cols []string | |||
| bean interface{} | |||
| }{ | |||
| {"action", []string{"created"}, new(TAction)}, | |||
| {"notice", []string{"created"}, new(TNotice)}, | |||
| {"comment", []string{"created"}, new(TComment)}, | |||
| {"issue", []string{"deadline", "created", "updated"}, new(TIssue)}, | |||
| {"milestone", []string{"deadline", "closed_date"}, new(TMilestone)}, | |||
| {"attachment", []string{"created"}, new(TAttachment)}, | |||
| {"login_source", []string{"created", "updated"}, new(TLoginSource)}, | |||
| {"pull_request", []string{"merged"}, new(TPull)}, | |||
| {"release", []string{"created"}, new(TRelease)}, | |||
| {"repository", []string{"created", "updated"}, new(TRepo)}, | |||
| {"mirror", []string{"updated", "next_update"}, new(TMirror)}, | |||
| {"public_key", []string{"created", "updated"}, new(TPublicKey)}, | |||
| {"deploy_key", []string{"created", "updated"}, new(TDeployKey)}, | |||
| {"access_token", []string{"created", "updated"}, new(TAccessToken)}, | |||
| {"user", []string{"created", "updated"}, new(TUser)}, | |||
| {"webhook", []string{"created", "updated"}, new(TWebhook)}, | |||
| } | |||
| for _, table := range tables { | |||
| log.Info("Converting table: %s", table.name) | |||
| if err = x.Sync2(table.bean); err != nil { | |||
| return fmt.Errorf("Sync [table: %s]: %v", table.name, err) | |||
| } | |||
| offset := 0 | |||
| for { | |||
| beans := make([]*Bean, 0, 100) | |||
| if err = x.Table(table.name).Asc("id").Limit(100, offset).Find(&beans); err != nil { | |||
| return fmt.Errorf("select beans [table: %s, offset: %d]: %v", table.name, offset, err) | |||
| } | |||
| log.Trace("Table [%s]: offset: %d, beans: %d", table.name, offset, len(beans)) | |||
| if len(beans) == 0 { | |||
| break | |||
| } | |||
| offset += 100 | |||
| baseSQL := "UPDATE `" + table.name + "` SET " | |||
| for _, bean := range beans { | |||
| valSQLs := make([]string, 0, len(table.cols)) | |||
| for _, col := range table.cols { | |||
| fieldSQL := "" | |||
| fieldSQL += col + "_unix = " | |||
| switch col { | |||
| case "deadline": | |||
| if bean.Deadline.IsZero() { | |||
| continue | |||
| } | |||
| fieldSQL += com.ToStr(bean.Deadline.Unix()) | |||
| case "created": | |||
| fieldSQL += com.ToStr(bean.Created.Unix()) | |||
| case "updated": | |||
| fieldSQL += com.ToStr(bean.Updated.Unix()) | |||
| case "closed_date": | |||
| fieldSQL += com.ToStr(bean.ClosedDate.Unix()) | |||
| case "merged": | |||
| fieldSQL += com.ToStr(bean.Merged.Unix()) | |||
| case "next_update": | |||
| fieldSQL += com.ToStr(bean.NextUpdate.Unix()) | |||
| } | |||
| valSQLs = append(valSQLs, fieldSQL) | |||
| } | |||
| if len(valSQLs) == 0 { | |||
| continue | |||
| } | |||
| if _, err = x.Exec(baseSQL + strings.Join(valSQLs, ",") + " WHERE id = " + com.ToStr(bean.ID)); err != nil { | |||
| return fmt.Errorf("update bean [table: %s, id: %d]: %v", table.name, bean.ID, err) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,52 +0,0 @@ | |||
| // Copyright 2016 The Gogs Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "encoding/json" | |||
| "fmt" | |||
| "strings" | |||
| "github.com/unknwon/com" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func ldapUseSSLToSecurityProtocol(x *xorm.Engine) error { | |||
| results, err := x.Query("SELECT `id`,`cfg` FROM `login_source` WHERE `type` = 2 OR `type` = 5") | |||
| if err != nil { | |||
| if strings.Contains(err.Error(), "no such column") { | |||
| return nil | |||
| } | |||
| return fmt.Errorf("select LDAP login sources: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| for _, result := range results { | |||
| cfg := map[string]interface{}{} | |||
| if err = json.Unmarshal(result["cfg"], &cfg); err != nil { | |||
| return fmt.Errorf("decode JSON config: %v", err) | |||
| } | |||
| if com.ToStr(cfg["UseSSL"]) == "true" { | |||
| cfg["SecurityProtocol"] = 1 // LDAPS | |||
| } | |||
| delete(cfg, "UseSSL") | |||
| data, err := json.Marshal(&cfg) | |||
| if err != nil { | |||
| return fmt.Errorf("encode JSON config: %v", err) | |||
| } | |||
| if _, err = sess.Exec("UPDATE `login_source` SET `cfg`=? WHERE `id`=?", | |||
| string(data), com.StrTo(result["id"]).MustInt64()); err != nil { | |||
| return fmt.Errorf("update config column: %v", err) | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,38 +0,0 @@ | |||
| // Copyright 2016 The Gogs Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func setCommentUpdatedWithCreated(x *xorm.Engine) (err error) { | |||
| type Comment struct { | |||
| UpdatedUnix int64 | |||
| } | |||
| if err = x.Sync2(new(Comment)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } else if _, err = x.Exec("UPDATE comment SET updated_unix = created_unix"); err != nil { | |||
| return fmt.Errorf("set update_unix: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| // UserV14 describes the added fields for migrating from v13 -> v14 | |||
| type UserV14 struct { | |||
| DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"` | |||
| } | |||
| // TableName will be invoked by XORM to customize the table name | |||
| func (*UserV14) TableName() string { | |||
| return "user" | |||
| } | |||
| func createUserColumnDiffViewStyle(x *xorm.Engine) error { | |||
| return x.Sync2(new(UserV14)) | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| // Copyright 2016 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func createAllowCreateOrganizationColumn(x *xorm.Engine) error { | |||
| type User struct { | |||
| KeepEmailPrivate bool | |||
| AllowCreateOrganization bool | |||
| } | |||
| if err := x.Sync2(new(User)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } else if _, err = x.Where("`type` = 0").Cols("allow_create_organization").Update(&User{AllowCreateOrganization: true}); err != nil { | |||
| return fmt.Errorf("set allow_create_organization: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,123 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/markup" | |||
| "xorm.io/xorm" | |||
| ) | |||
| // Enumerate all the unit types | |||
| const ( | |||
| V16UnitTypeCode = iota + 1 // 1 code | |||
| V16UnitTypeIssues // 2 issues | |||
| V16UnitTypePRs // 3 PRs | |||
| V16UnitTypeCommits // 4 Commits | |||
| V16UnitTypeReleases // 5 Releases | |||
| V16UnitTypeWiki // 6 Wiki | |||
| V16UnitTypeSettings // 7 Settings | |||
| V16UnitTypeExternalWiki // 8 ExternalWiki | |||
| V16UnitTypeExternalTracker // 9 ExternalTracker | |||
| ) | |||
| func addUnitsToTables(x *xorm.Engine) error { | |||
| // RepoUnit describes all units of a repository | |||
| type RepoUnit struct { | |||
| ID int64 | |||
| RepoID int64 `xorm:"INDEX(s)"` | |||
| Type int `xorm:"INDEX(s)"` | |||
| Index int | |||
| Config map[string]interface{} `xorm:"JSON"` | |||
| CreatedUnix int64 `xorm:"INDEX CREATED"` | |||
| Created time.Time `xorm:"-"` | |||
| } | |||
| // Repo describes a repository | |||
| type Repo struct { | |||
| ID int64 | |||
| EnableWiki, EnableExternalWiki, EnableIssues, EnableExternalTracker, EnablePulls bool | |||
| ExternalWikiURL, ExternalTrackerURL, ExternalTrackerFormat, ExternalTrackerStyle string | |||
| } | |||
| var repos []Repo | |||
| err := x.Table("repository").Select("*").Find(&repos) | |||
| if err != nil { | |||
| return fmt.Errorf("Query repositories: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| var repoUnit RepoUnit | |||
| if exist, err := sess.IsTableExist(&repoUnit); err != nil { | |||
| return fmt.Errorf("IsExist RepoUnit: %v", err) | |||
| } else if exist { | |||
| return nil | |||
| } | |||
| if err := sess.CreateTable(&repoUnit); err != nil { | |||
| return fmt.Errorf("CreateTable RepoUnit: %v", err) | |||
| } | |||
| if err := sess.CreateUniques(&repoUnit); err != nil { | |||
| return fmt.Errorf("CreateUniques RepoUnit: %v", err) | |||
| } | |||
| if err := sess.CreateIndexes(&repoUnit); err != nil { | |||
| return fmt.Errorf("CreateIndexes RepoUnit: %v", err) | |||
| } | |||
| for _, repo := range repos { | |||
| for i := 1; i <= 9; i++ { | |||
| if (i == V16UnitTypeWiki || i == V16UnitTypeExternalWiki) && !repo.EnableWiki { | |||
| continue | |||
| } | |||
| if i == V16UnitTypeExternalWiki && !repo.EnableExternalWiki { | |||
| continue | |||
| } | |||
| if i == V16UnitTypePRs && !repo.EnablePulls { | |||
| continue | |||
| } | |||
| if (i == V16UnitTypeIssues || i == V16UnitTypeExternalTracker) && !repo.EnableIssues { | |||
| continue | |||
| } | |||
| if i == V16UnitTypeExternalTracker && !repo.EnableExternalTracker { | |||
| continue | |||
| } | |||
| var config = make(map[string]interface{}) | |||
| switch i { | |||
| case V16UnitTypeExternalTracker: | |||
| config["ExternalTrackerURL"] = repo.ExternalTrackerURL | |||
| config["ExternalTrackerFormat"] = repo.ExternalTrackerFormat | |||
| if len(repo.ExternalTrackerStyle) == 0 { | |||
| repo.ExternalTrackerStyle = markup.IssueNameStyleNumeric | |||
| } | |||
| config["ExternalTrackerStyle"] = repo.ExternalTrackerStyle | |||
| case V16UnitTypeExternalWiki: | |||
| config["ExternalWikiURL"] = repo.ExternalWikiURL | |||
| } | |||
| if _, err = sess.Insert(&RepoUnit{ | |||
| RepoID: repo.ID, | |||
| Type: i, | |||
| Index: i, | |||
| Config: config, | |||
| }); err != nil { | |||
| return fmt.Errorf("Insert repo unit: %v", err) | |||
| } | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2016 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func setProtectedBranchUpdatedWithCreated(x *xorm.Engine) (err error) { | |||
| type ProtectedBranch struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"UNIQUE(s)"` | |||
| BranchName string `xorm:"UNIQUE(s)"` | |||
| CanPush bool | |||
| Created time.Time `xorm:"-"` | |||
| CreatedUnix int64 | |||
| Updated time.Time `xorm:"-"` | |||
| UpdatedUnix int64 | |||
| } | |||
| if err = x.Sync2(new(ProtectedBranch)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| // Copyright 2016 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| // ExternalLoginUser makes the connecting between some existing user and additional external login sources | |||
| type ExternalLoginUser struct { | |||
| ExternalID string `xorm:"NOT NULL"` | |||
| UserID int64 `xorm:"NOT NULL"` | |||
| LoginSourceID int64 `xorm:"NOT NULL"` | |||
| } | |||
| func addExternalLoginUser(x *xorm.Engine) error { | |||
| if err := x.Sync2(new(ExternalLoginUser)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,91 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "io/ioutil" | |||
| "os" | |||
| "path/filepath" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "github.com/unknwon/com" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func generateAndMigrateGitHooks(x *xorm.Engine) (err error) { | |||
| type Repository struct { | |||
| ID int64 | |||
| OwnerID int64 | |||
| Name string | |||
| } | |||
| type User struct { | |||
| ID int64 | |||
| Name string | |||
| } | |||
| var ( | |||
| hookNames = []string{"pre-receive", "update", "post-receive"} | |||
| hookTpls = []string{ | |||
| fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/pre-receive.d\"`; do\n sh \"$SHELL_FOLDER/pre-receive.d/$i\"\ndone", setting.ScriptType), | |||
| fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/update.d\"`; do\n sh \"$SHELL_FOLDER/update.d/$i\" $1 $2 $3\ndone", setting.ScriptType), | |||
| fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/post-receive.d\"`; do\n sh \"$SHELL_FOLDER/post-receive.d/$i\"\ndone", setting.ScriptType), | |||
| } | |||
| giteaHookTpls = []string{ | |||
| fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | |||
| fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | |||
| fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | |||
| } | |||
| ) | |||
| return x.Where("id > 0").BufferSize(setting.Database.IterateBufferSize).Iterate(new(Repository), | |||
| func(idx int, bean interface{}) error { | |||
| repo := bean.(*Repository) | |||
| user := new(User) | |||
| has, err := x.Where("id = ?", repo.OwnerID).Get(user) | |||
| if err != nil { | |||
| return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err) | |||
| } else if !has { | |||
| return nil | |||
| } | |||
| repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git" | |||
| hookDir := filepath.Join(repoPath, "hooks") | |||
| for i, hookName := range hookNames { | |||
| oldHookPath := filepath.Join(hookDir, hookName) | |||
| newHookPath := filepath.Join(hookDir, hookName+".d", "gitea") | |||
| customHooksDir := filepath.Join(hookDir, hookName+".d") | |||
| // if it's exist, that means you have upgraded ever | |||
| if com.IsExist(customHooksDir) { | |||
| continue | |||
| } | |||
| if err = os.MkdirAll(customHooksDir, os.ModePerm); err != nil { | |||
| return fmt.Errorf("create hooks dir '%s': %v", customHooksDir, err) | |||
| } | |||
| // WARNING: Old server-side hooks will be moved to sub directory with the same name | |||
| if hookName != "update" && com.IsExist(oldHookPath) { | |||
| newPlace := filepath.Join(hookDir, hookName+".d", hookName) | |||
| if err = os.Rename(oldHookPath, newPlace); err != nil { | |||
| return fmt.Errorf("Remove old hook file '%s' to '%s': %v", oldHookPath, newPlace, err) | |||
| } | |||
| } | |||
| if err = ioutil.WriteFile(oldHookPath, []byte(hookTpls[i]), 0777); err != nil { | |||
| return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err) | |||
| } | |||
| if err = ioutil.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0777); err != nil { | |||
| return fmt.Errorf("write new hook file '%s': %v", oldHookPath, err) | |||
| } | |||
| } | |||
| return nil | |||
| }) | |||
| } | |||
| @@ -1,73 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "crypto/md5" | |||
| "errors" | |||
| "fmt" | |||
| "io/ioutil" | |||
| "os" | |||
| "path/filepath" | |||
| "strconv" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func useNewNameAvatars(x *xorm.Engine) error { | |||
| d, err := os.Open(setting.AvatarUploadPath) | |||
| if err != nil { | |||
| if os.IsNotExist(err) { | |||
| // Nothing to do if AvatarUploadPath does not exist | |||
| return nil | |||
| } | |||
| return err | |||
| } | |||
| names, err := d.Readdirnames(0) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| type User struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Avatar string | |||
| UseCustomAvatar bool | |||
| } | |||
| for _, name := range names { | |||
| userID, err := strconv.ParseInt(name, 10, 64) | |||
| if err != nil { | |||
| log.Warn("ignore avatar %s rename: %v", name, err) | |||
| continue | |||
| } | |||
| var user User | |||
| if has, err := x.ID(userID).Get(&user); err != nil { | |||
| return err | |||
| } else if !has { | |||
| return errors.New("Avatar user is not exist") | |||
| } | |||
| fPath := filepath.Join(setting.AvatarUploadPath, name) | |||
| bs, err := ioutil.ReadFile(fPath) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| user.Avatar = fmt.Sprintf("%x", md5.Sum(bs)) | |||
| err = os.Rename(fPath, filepath.Join(setting.AvatarUploadPath, user.Avatar)) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| _, err = x.ID(userID).Cols("avatar").Update(&user) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,55 +0,0 @@ | |||
| // Copyright 2017 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "os" | |||
| "path/filepath" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "github.com/unknwon/com" | |||
| "xorm.io/xorm" | |||
| ) | |||
| const ( | |||
| tplCommentPrefix = `# gitea public key` | |||
| tplPublicKey = tplCommentPrefix + "\n" + `command="%s serv key-%d --config='%s'",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n" | |||
| ) | |||
| func useNewPublickeyFormat(x *xorm.Engine) error { | |||
| fpath := filepath.Join(setting.SSH.RootPath, "authorized_keys") | |||
| if !com.IsExist(fpath) { | |||
| return nil | |||
| } | |||
| tmpPath := fpath + ".tmp" | |||
| f, err := os.OpenFile(tmpPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| defer func() { | |||
| f.Close() | |||
| os.Remove(tmpPath) | |||
| }() | |||
| type PublicKey struct { | |||
| ID int64 | |||
| Content string | |||
| } | |||
| err = x.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) { | |||
| key := bean.(*PublicKey) | |||
| _, err = f.WriteString(fmt.Sprintf(tplPublicKey, setting.AppPath, key.ID, setting.CustomConf, key.Content)) | |||
| return err | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| f.Close() | |||
| return os.Rename(tmpPath, fpath) | |||
| } | |||
| @@ -1,94 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "io/ioutil" | |||
| "os" | |||
| "path/filepath" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "github.com/unknwon/com" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func generateAndMigrateWikiGitHooks(x *xorm.Engine) (err error) { | |||
| type Repository struct { | |||
| ID int64 | |||
| OwnerID int64 | |||
| Name string | |||
| } | |||
| type User struct { | |||
| ID int64 | |||
| Name string | |||
| } | |||
| var ( | |||
| hookNames = []string{"pre-receive", "update", "post-receive"} | |||
| hookTpls = []string{ | |||
| fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/pre-receive.d\"`; do\n sh \"$SHELL_FOLDER/pre-receive.d/$i\"\ndone", setting.ScriptType), | |||
| fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/update.d\"`; do\n sh \"$SHELL_FOLDER/update.d/$i\" $1 $2 $3\ndone", setting.ScriptType), | |||
| fmt.Sprintf("#!/usr/bin/env %s\nORI_DIR=`pwd`\nSHELL_FOLDER=$(cd \"$(dirname \"$0\")\";pwd)\ncd \"$ORI_DIR\"\nfor i in `ls \"$SHELL_FOLDER/post-receive.d\"`; do\n sh \"$SHELL_FOLDER/post-receive.d/$i\"\ndone", setting.ScriptType), | |||
| } | |||
| giteaHookTpls = []string{ | |||
| fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' pre-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | |||
| fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' update $1 $2 $3\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | |||
| fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | |||
| } | |||
| ) | |||
| return x.Where("id > 0").BufferSize(setting.Database.IterateBufferSize).Iterate(new(Repository), | |||
| func(idx int, bean interface{}) error { | |||
| repo := bean.(*Repository) | |||
| user := new(User) | |||
| has, err := x.Where("id = ?", repo.OwnerID).Get(user) | |||
| if err != nil { | |||
| return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err) | |||
| } else if !has { | |||
| return nil | |||
| } | |||
| repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".wiki.git" | |||
| if !com.IsExist(repoPath) { | |||
| return nil | |||
| } | |||
| hookDir := filepath.Join(repoPath, "hooks") | |||
| for i, hookName := range hookNames { | |||
| oldHookPath := filepath.Join(hookDir, hookName) | |||
| newHookPath := filepath.Join(hookDir, hookName+".d", "gitea") | |||
| customHooksDir := filepath.Join(hookDir, hookName+".d") | |||
| // if it's exist, that means you have upgraded ever | |||
| if com.IsExist(customHooksDir) { | |||
| continue | |||
| } | |||
| if err = os.MkdirAll(customHooksDir, os.ModePerm); err != nil { | |||
| return fmt.Errorf("create hooks dir '%s': %v", customHooksDir, err) | |||
| } | |||
| // WARNING: Old server-side hooks will be moved to sub directory with the same name | |||
| if hookName != "update" && com.IsExist(oldHookPath) { | |||
| newPlace := filepath.Join(hookDir, hookName+".d", hookName) | |||
| if err = os.Rename(oldHookPath, newPlace); err != nil { | |||
| return fmt.Errorf("Remove old hook file '%s' to '%s': %v", oldHookPath, newPlace, err) | |||
| } | |||
| } | |||
| if err = ioutil.WriteFile(oldHookPath, []byte(hookTpls[i]), 0777); err != nil { | |||
| return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err) | |||
| } | |||
| if err = ioutil.WriteFile(newHookPath, []byte(giteaHookTpls[i]), 0777); err != nil { | |||
| return fmt.Errorf("write new hook file '%s': %v", oldHookPath, err) | |||
| } | |||
| } | |||
| return nil | |||
| }) | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| // Copyright 2017 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| // UserOpenID is the list of all OpenID identities of a user. | |||
| type UserOpenID struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| UID int64 `xorm:"INDEX NOT NULL"` | |||
| URI string `xorm:"UNIQUE NOT NULL"` | |||
| } | |||
| func addUserOpenID(x *xorm.Engine) error { | |||
| if err := x.Sync2(new(UserOpenID)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,50 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "time" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func changeGPGKeysColumns(x *xorm.Engine) error { | |||
| // EmailAddress is the list of all email addresses of a user. Can contain the | |||
| // primary email address, but is not obligatory. | |||
| type EmailAddress struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| UID int64 `xorm:"INDEX NOT NULL"` | |||
| Email string `xorm:"UNIQUE NOT NULL"` | |||
| IsActivated bool | |||
| IsPrimary bool `xorm:"-"` | |||
| } | |||
| // GPGKey represents a GPG key. | |||
| type GPGKey struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| OwnerID int64 `xorm:"INDEX NOT NULL"` | |||
| KeyID string `xorm:"INDEX CHAR(16) NOT NULL"` | |||
| PrimaryKeyID string `xorm:"CHAR(16)"` | |||
| Content string `xorm:"TEXT NOT NULL"` | |||
| Created time.Time `xorm:"-"` | |||
| CreatedUnix int64 | |||
| Expired time.Time `xorm:"-"` | |||
| ExpiredUnix int64 | |||
| Added time.Time `xorm:"-"` | |||
| AddedUnix int64 | |||
| SubsKey []*GPGKey `xorm:"-"` | |||
| Emails []*EmailAddress | |||
| CanSign bool | |||
| CanEncryptComms bool | |||
| CanEncryptStorage bool | |||
| CanCertify bool | |||
| } | |||
| if err := x.DropTables(new(GPGKey)); err != nil { | |||
| return err | |||
| } | |||
| return x.Sync(new(GPGKey)) | |||
| } | |||
| @@ -1,18 +0,0 @@ | |||
| // Copyright 2017 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addUserOpenIDShow(x *xorm.Engine) error { | |||
| if err := x.Sync2(new(UserOpenID)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,87 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "crypto/md5" | |||
| "encoding/hex" | |||
| "fmt" | |||
| "io" | |||
| "io/ioutil" | |||
| "os" | |||
| "path/filepath" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "github.com/unknwon/com" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func generateAndMigrateGitHookChains(x *xorm.Engine) (err error) { | |||
| type Repository struct { | |||
| ID int64 | |||
| OwnerID int64 | |||
| Name string | |||
| } | |||
| type User struct { | |||
| ID int64 | |||
| Name string | |||
| } | |||
| var ( | |||
| hookNames = []string{"pre-receive", "update", "post-receive"} | |||
| hookTpl = fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType) | |||
| ) | |||
| return x.Where("id > 0").BufferSize(setting.Database.IterateBufferSize).Iterate(new(Repository), | |||
| func(idx int, bean interface{}) error { | |||
| repo := bean.(*Repository) | |||
| user := new(User) | |||
| has, err := x.Where("id = ?", repo.OwnerID).Get(user) | |||
| if err != nil { | |||
| return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err) | |||
| } else if !has { | |||
| return nil | |||
| } | |||
| repoPaths := []string{ | |||
| filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git", | |||
| filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".wiki.git", | |||
| } | |||
| for _, repoPath := range repoPaths { | |||
| if com.IsExist(repoPath) { | |||
| hookDir := filepath.Join(repoPath, "hooks") | |||
| for _, hookName := range hookNames { | |||
| oldHookPath := filepath.Join(hookDir, hookName) | |||
| // compare md5sums of hooks | |||
| if com.IsExist(oldHookPath) { | |||
| f, err := os.Open(oldHookPath) | |||
| if err != nil { | |||
| return fmt.Errorf("cannot open old hook file '%s': %v", oldHookPath, err) | |||
| } | |||
| defer f.Close() | |||
| h := md5.New() | |||
| if _, err := io.Copy(h, f); err != nil { | |||
| return fmt.Errorf("cannot read old hook file '%s': %v", oldHookPath, err) | |||
| } | |||
| if hex.EncodeToString(h.Sum(nil)) == "6718ef67d0834e0a7908259acd566e3f" { | |||
| return nil | |||
| } | |||
| } | |||
| if err = ioutil.WriteFile(oldHookPath, []byte(hookTpl), 0777); err != nil { | |||
| return fmt.Errorf("write old hook file '%s': %v", oldHookPath, err) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| }) | |||
| } | |||
| @@ -1,72 +0,0 @@ | |||
| // Copyright 2017 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func convertIntervalToDuration(x *xorm.Engine) (err error) { | |||
| type Repository struct { | |||
| ID int64 | |||
| OwnerID int64 | |||
| Name string | |||
| } | |||
| type Mirror struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"INDEX"` | |||
| Repo *Repository `xorm:"-"` | |||
| Interval time.Duration | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| dialect := x.Dialect().DriverName() | |||
| switch dialect { | |||
| case "mysql": | |||
| _, err = sess.Exec("ALTER TABLE mirror MODIFY `interval` BIGINT") | |||
| case "postgres": | |||
| _, err = sess.Exec("ALTER TABLE mirror ALTER COLUMN \"interval\" SET DATA TYPE bigint") | |||
| case "mssql": | |||
| _, err = sess.Exec("ALTER TABLE mirror ALTER COLUMN \"interval\" BIGINT") | |||
| case "sqlite3": | |||
| } | |||
| if err != nil { | |||
| return fmt.Errorf("Error changing mirror interval column type: %v", err) | |||
| } | |||
| var mirrors []Mirror | |||
| err = sess.Table("mirror").Select("*").Find(&mirrors) | |||
| if err != nil { | |||
| return fmt.Errorf("Query repositories: %v", err) | |||
| } | |||
| for _, mirror := range mirrors { | |||
| mirror.Interval *= time.Hour | |||
| if mirror.Interval < setting.Mirror.MinInterval { | |||
| log.Info("Mirror interval less than Mirror.MinInterval, setting default interval: repo id %v", mirror.RepoID) | |||
| mirror.Interval = setting.Mirror.DefaultInterval | |||
| } | |||
| log.Debug("Mirror interval set to %v for repo id %v", mirror.Interval, mirror.RepoID) | |||
| _, err := sess.ID(mirror.ID).Cols("interval").Update(mirror) | |||
| if err != nil { | |||
| return fmt.Errorf("update mirror interval failed: %v", err) | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,76 +0,0 @@ | |||
| // Copyright 2017 The Gogs Authors. All rights reserved. | |||
| // Copyright 2017 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "path/filepath" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/git" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addRepoSize(x *xorm.Engine) (err error) { | |||
| log.Info("This migration could take up to minutes, please be patient.") | |||
| type Repository struct { | |||
| ID int64 | |||
| OwnerID int64 | |||
| Name string | |||
| Size int64 | |||
| } | |||
| type User struct { | |||
| ID int64 | |||
| Name string | |||
| } | |||
| if err = x.Sync2(new(Repository)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| // For the sake of SQLite3, we can't use x.Iterate here. | |||
| offset := 0 | |||
| for { | |||
| repos := make([]*Repository, 0, 10) | |||
| if err = x.Table("repository").Asc("id").Limit(10, offset).Find(&repos); err != nil { | |||
| return fmt.Errorf("select repos [offset: %d]: %v", offset, err) | |||
| } | |||
| log.Trace("Select [offset: %d, repos: %d]", offset, len(repos)) | |||
| if len(repos) == 0 { | |||
| break | |||
| } | |||
| offset += 10 | |||
| for _, repo := range repos { | |||
| if repo.Name == "." || repo.Name == ".." { | |||
| continue | |||
| } | |||
| user := new(User) | |||
| has, err := x.Where("id = ?", repo.OwnerID).Get(user) | |||
| if err != nil { | |||
| return fmt.Errorf("query owner of repository [repo_id: %d, owner_id: %d]: %v", repo.ID, repo.OwnerID, err) | |||
| } else if !has { | |||
| continue | |||
| } | |||
| repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(user.Name), strings.ToLower(repo.Name)) + ".git" | |||
| countObject, err := git.CountObjects(repoPath) | |||
| if err != nil { | |||
| log.Warn("CountObjects: %v", err) | |||
| continue | |||
| } | |||
| repo.Size = countObject.Size + countObject.SizePack | |||
| if _, err = x.ID(repo.ID).Cols("size").Update(repo); err != nil { | |||
| return fmt.Errorf("update size: %v", err) | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,34 +0,0 @@ | |||
| // Copyright 2017 The Gogs Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| // CommitStatus see models/status.go | |||
| type CommitStatus struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` | |||
| RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` | |||
| State string `xorm:"VARCHAR(7) NOT NULL"` | |||
| SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` | |||
| TargetURL string `xorm:"TEXT"` | |||
| Description string `xorm:"TEXT"` | |||
| Context string `xorm:"TEXT"` | |||
| CreatorID int64 `xorm:"INDEX"` | |||
| CreatedUnix int64 `xorm:"INDEX"` | |||
| UpdatedUnix int64 `xorm:"INDEX"` | |||
| } | |||
| func addCommitStatus(x *xorm.Engine) error { | |||
| if err := x.Sync2(new(CommitStatus)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,38 +0,0 @@ | |||
| // Copyright 2017 The Gogs Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addExternalLoginUserPK(x *xorm.Engine) error { | |||
| // ExternalLoginUser see models/external_login_user.go | |||
| type ExternalLoginUser struct { | |||
| ExternalID string `xorm:"pk NOT NULL"` | |||
| UserID int64 `xorm:"INDEX NOT NULL"` | |||
| LoginSourceID int64 `xorm:"pk NOT NULL"` | |||
| } | |||
| extlogins := make([]*ExternalLoginUser, 0, 6) | |||
| if err := x.Find(&extlogins); err != nil { | |||
| return fmt.Errorf("Find: %v", err) | |||
| } | |||
| if err := x.DropTables(new(ExternalLoginUser)); err != nil { | |||
| return fmt.Errorf("DropTables: %v", err) | |||
| } | |||
| if err := x.Sync2(new(ExternalLoginUser)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| if _, err := x.Insert(extlogins); err != nil { | |||
| return fmt.Errorf("Insert: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,35 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "xorm.io/core" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addLoginSourceSyncEnabledColumn(x *xorm.Engine) error { | |||
| // LoginSource see models/login_source.go | |||
| type LoginSource struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Type int | |||
| Name string `xorm:"UNIQUE"` | |||
| IsActived bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| IsSyncEnabled bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| Cfg core.Conversion `xorm:"TEXT"` | |||
| Created time.Time `xorm:"-"` | |||
| CreatedUnix int64 `xorm:"INDEX"` | |||
| Updated time.Time `xorm:"-"` | |||
| UpdatedUnix int64 `xorm:"INDEX"` | |||
| } | |||
| if err := x.Sync2(new(LoginSource)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import "xorm.io/xorm" | |||
| func addUnitsToRepoTeam(x *xorm.Engine) error { | |||
| type Team struct { | |||
| UnitTypes []int `xorm:"json"` | |||
| } | |||
| err := x.Sync(new(Team)) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| _, err = x.Update(&Team{ | |||
| UnitTypes: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, | |||
| }) | |||
| return err | |||
| } | |||
| @@ -1,32 +0,0 @@ | |||
| // Copyright 2017 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func removeActionColumns(x *xorm.Engine) error { | |||
| switch { | |||
| case setting.Database.UseSQLite3: | |||
| log.Warn("Unable to drop columns in SQLite") | |||
| case setting.Database.UseMySQL, setting.Database.UsePostgreSQL, setting.Database.UseMSSQL: | |||
| if _, err := x.Exec("ALTER TABLE action DROP COLUMN act_user_name"); err != nil { | |||
| return fmt.Errorf("DROP COLUMN act_user_name: %v", err) | |||
| } else if _, err = x.Exec("ALTER TABLE action DROP COLUMN repo_user_name"); err != nil { | |||
| return fmt.Errorf("DROP COLUMN repo_user_name: %v", err) | |||
| } else if _, err = x.Exec("ALTER TABLE action DROP COLUMN repo_name"); err != nil { | |||
| return fmt.Errorf("DROP COLUMN repo_name: %v", err) | |||
| } | |||
| default: | |||
| log.Fatal("Unrecognized DB") | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| // Copyright 2017 Gitea. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "xorm.io/xorm" | |||
| ) | |||
| // Team see models/team.go | |||
| type Team struct { | |||
| UnitTypes []int `xorm:"json"` | |||
| } | |||
| const ownerAccessMode = 4 | |||
| var allUnitTypes = []int{1, 2, 3, 4, 5, 6, 7, 8, 9} | |||
| func giveAllUnitsToOwnerTeams(x *xorm.Engine) error { | |||
| _, err := x.Cols("unit_types"). | |||
| Where("authorize = ?", ownerAccessMode). | |||
| Update(&Team{UnitTypes: allUnitTypes}) | |||
| return err | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addCommentIDToAction(x *xorm.Engine) error { | |||
| // Action see models/action.go | |||
| type Action struct { | |||
| CommentID int64 `xorm:"INDEX"` | |||
| IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| } | |||
| if err := x.Sync2(new(Action)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,16 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "code.gitea.io/gitea/modules/graceful" | |||
| repo_module "code.gitea.io/gitea/modules/repository" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func regenerateGitHooks36(x *xorm.Engine) (err error) { | |||
| return repo_module.SyncRepositoryHooks(graceful.GetManager().ShutdownContext()) | |||
| } | |||
| @@ -1,35 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "html" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func unescapeUserFullNames(x *xorm.Engine) (err error) { | |||
| type User struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| FullName string | |||
| } | |||
| const batchSize = 100 | |||
| for start := 0; ; start += batchSize { | |||
| users := make([]*User, 0, batchSize) | |||
| if err := x.Limit(batchSize, start).Find(&users); err != nil { | |||
| return err | |||
| } | |||
| if len(users) == 0 { | |||
| return nil | |||
| } | |||
| for _, user := range users { | |||
| user.FullName = html.UnescapeString(user.FullName) | |||
| if _, err := x.ID(user.ID).Cols("full_name").Update(user); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,75 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "xorm.io/core" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func removeCommitsUnitType(x *xorm.Engine) (err error) { | |||
| // RepoUnit describes all units of a repository | |||
| type RepoUnit struct { | |||
| ID int64 | |||
| RepoID int64 `xorm:"INDEX(s)"` | |||
| Type int `xorm:"INDEX(s)"` | |||
| Index int | |||
| Config core.Conversion `xorm:"TEXT"` | |||
| CreatedUnix int64 `xorm:"INDEX CREATED"` | |||
| Created time.Time `xorm:"-"` | |||
| } | |||
| type Team struct { | |||
| ID int64 | |||
| UnitTypes []int `xorm:"json"` | |||
| } | |||
| // Update team unit types | |||
| const batchSize = 100 | |||
| for start := 0; ; start += batchSize { | |||
| teams := make([]*Team, 0, batchSize) | |||
| if err := x.Limit(batchSize, start).Find(&teams); err != nil { | |||
| return err | |||
| } | |||
| if len(teams) == 0 { | |||
| break | |||
| } | |||
| for _, team := range teams { | |||
| ut := make([]int, 0, len(team.UnitTypes)) | |||
| for _, u := range team.UnitTypes { | |||
| if u < V16UnitTypeCommits { | |||
| ut = append(ut, u) | |||
| } else if u > V16UnitTypeSettings { | |||
| ut = append(ut, u-2) | |||
| } else if u > V16UnitTypeCommits && u != V16UnitTypeSettings { | |||
| ut = append(ut, u-1) | |||
| } | |||
| } | |||
| team.UnitTypes = ut | |||
| if _, err := x.ID(team.ID).Cols("unit_types").Update(team); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| // Delete commits and settings unit types | |||
| if _, err = x.In("`type`", []models.UnitType{V16UnitTypeCommits, V16UnitTypeSettings}).Delete(new(RepoUnit)); err != nil { | |||
| return err | |||
| } | |||
| // Fix renumber unit types that where in enumeration after settings unit type | |||
| if _, err = x.Where("`type` > ?", V16UnitTypeSettings).Decr("type").Decr("index").Update(new(RepoUnit)); err != nil { | |||
| return err | |||
| } | |||
| // Fix renumber unit types that where in enumeration after commits unit type | |||
| if _, err = x.Where("`type` > ?", V16UnitTypeCommits).Decr("type").Decr("index").Update(new(RepoUnit)); err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,59 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/git" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| "xorm.io/xorm" | |||
| ) | |||
| // ReleaseV39 describes the added field for Release | |||
| type ReleaseV39 struct { | |||
| IsTag bool `xorm:"NOT NULL DEFAULT false"` | |||
| } | |||
| // TableName will be invoked by XORM to customrize the table name | |||
| func (*ReleaseV39) TableName() string { | |||
| return "release" | |||
| } | |||
| func releaseAddColumnIsTagAndSyncTags(x *xorm.Engine) error { | |||
| if err := x.Sync2(new(ReleaseV39)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| // For the sake of SQLite3, we can't use x.Iterate here. | |||
| offset := 0 | |||
| pageSize := models.RepositoryListDefaultPageSize | |||
| for { | |||
| repos := make([]*models.Repository, 0, pageSize) | |||
| if err := x.Table("repository").Cols("id", "name", "owner_id").Asc("id").Limit(pageSize, offset).Find(&repos); err != nil { | |||
| return fmt.Errorf("select repos [offset: %d]: %v", offset, err) | |||
| } | |||
| for _, repo := range repos { | |||
| gitRepo, err := git.OpenRepository(repo.RepoPath()) | |||
| if err != nil { | |||
| log.Warn("OpenRepository: %v", err) | |||
| continue | |||
| } | |||
| if err = repository.SyncReleasesWithTags(repo, gitRepo); err != nil { | |||
| log.Warn("SyncReleasesWithTags: %v", err) | |||
| } | |||
| gitRepo.Close() | |||
| } | |||
| if len(repos) < pageSize { | |||
| break | |||
| } | |||
| offset += pageSize | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,26 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func fixProtectedBranchCanPushValue(x *xorm.Engine) error { | |||
| type ProtectedBranch struct { | |||
| CanPush bool `xorm:"NOT NULL DEFAULT false"` | |||
| } | |||
| if err := x.Sync2(new(ProtectedBranch)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| _, err := x.Cols("can_push").Update(&ProtectedBranch{ | |||
| CanPush: false, | |||
| }) | |||
| return err | |||
| } | |||
| @@ -1,69 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func removeDuplicateUnitTypes(x *xorm.Engine) error { | |||
| // RepoUnit describes all units of a repository | |||
| type RepoUnit struct { | |||
| RepoID int64 | |||
| Type int | |||
| } | |||
| // Enumerate all the unit types | |||
| const ( | |||
| UnitTypeCode = iota + 1 // 1 code | |||
| UnitTypeIssues // 2 issues | |||
| UnitTypePullRequests // 3 PRs | |||
| UnitTypeReleases // 4 Releases | |||
| UnitTypeWiki // 5 Wiki | |||
| UnitTypeExternalWiki // 6 ExternalWiki | |||
| UnitTypeExternalTracker // 7 ExternalTracker | |||
| ) | |||
| var externalIssueRepoUnits []RepoUnit | |||
| err := x.Where("type = ?", UnitTypeExternalTracker).Find(&externalIssueRepoUnits) | |||
| if err != nil { | |||
| return fmt.Errorf("Query repositories: %v", err) | |||
| } | |||
| var externalWikiRepoUnits []RepoUnit | |||
| err = x.Where("type = ?", UnitTypeExternalWiki).Find(&externalWikiRepoUnits) | |||
| if err != nil { | |||
| return fmt.Errorf("Query repositories: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| for _, repoUnit := range externalIssueRepoUnits { | |||
| if _, err = sess.Delete(&RepoUnit{ | |||
| RepoID: repoUnit.RepoID, | |||
| Type: UnitTypeIssues, | |||
| }); err != nil { | |||
| return fmt.Errorf("Delete repo unit: %v", err) | |||
| } | |||
| } | |||
| for _, repoUnit := range externalWikiRepoUnits { | |||
| if _, err = sess.Delete(&RepoUnit{ | |||
| RepoID: repoUnit.RepoID, | |||
| Type: UnitTypeWiki, | |||
| }); err != nil { | |||
| return fmt.Errorf("Delete repo unit: %v", err) | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,28 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func removeIndexColumnFromRepoUnitTable(x *xorm.Engine) (err error) { | |||
| switch { | |||
| case setting.Database.UseSQLite3: | |||
| log.Warn("Unable to drop columns in SQLite") | |||
| case setting.Database.UseMySQL, setting.Database.UsePostgreSQL, setting.Database.UseMSSQL: | |||
| if _, err := x.Exec("ALTER TABLE repo_unit DROP COLUMN `index`"); err != nil { | |||
| // Ignoring this error in case we run this migration second time (after migration reordering) | |||
| log.Warn("DROP COLUMN index: %v", err) | |||
| } | |||
| default: | |||
| log.Fatal("Unrecognized DB") | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,36 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "xorm.io/xorm" | |||
| ) | |||
| func removeOrganizationWatchRepo(x *xorm.Engine) error { | |||
| // UserType defines the user type | |||
| type UserType int | |||
| const ( | |||
| // UserTypeIndividual defines an individual user | |||
| UserTypeIndividual UserType = iota // Historic reason to make it starts at 0. | |||
| // UserTypeOrganization defines an organization | |||
| UserTypeOrganization | |||
| ) | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.Exec("DELETE FROM `watch` WHERE `user_id` IN (SELECT `id` FROM `user` WHERE `type` = ?)", UserTypeOrganization); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.Exec("UPDATE `repository` SET num_watches = (SELECT count(*) FROM watch WHERE `repository`.`id` = watch.repo_id)"); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addDeletedBranch(x *xorm.Engine) (err error) { | |||
| // DeletedBranch contains the deleted branch information | |||
| type DeletedBranch struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` | |||
| Name string `xorm:"UNIQUE(s) NOT NULL"` | |||
| Commit string `xorm:"UNIQUE(s) NOT NULL"` | |||
| DeletedByID int64 `xorm:"INDEX NOT NULL"` | |||
| DeletedUnix int64 `xorm:"INDEX"` | |||
| } | |||
| if err = x.Sync2(new(DeletedBranch)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addRepoIndexerStatus(x *xorm.Engine) error { | |||
| // RepoIndexerStatus see models/repo_indexer.go | |||
| type RepoIndexerStatus struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"INDEX NOT NULL"` | |||
| CommitSha string `xorm:"VARCHAR(40)"` | |||
| } | |||
| if err := x.Sync2(new(RepoIndexerStatus)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,73 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addTimetracking(x *xorm.Engine) error { | |||
| // RepoUnit describes all units of a repository | |||
| type RepoUnit struct { | |||
| ID int64 | |||
| RepoID int64 `xorm:"INDEX(s)"` | |||
| Type int `xorm:"INDEX(s)"` | |||
| Config map[string]interface{} `xorm:"JSON"` | |||
| CreatedUnix int64 `xorm:"INDEX CREATED"` | |||
| Created time.Time `xorm:"-"` | |||
| } | |||
| // Stopwatch see models/issue_stopwatch.go | |||
| type Stopwatch struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| IssueID int64 `xorm:"INDEX"` | |||
| UserID int64 `xorm:"INDEX"` | |||
| Created time.Time `xorm:"-"` | |||
| CreatedUnix int64 | |||
| } | |||
| // TrackedTime see models/issue_tracked_time.go | |||
| type TrackedTime struct { | |||
| ID int64 `xorm:"pk autoincr" json:"id"` | |||
| IssueID int64 `xorm:"INDEX" json:"issue_id"` | |||
| UserID int64 `xorm:"INDEX" json:"user_id"` | |||
| Created time.Time `xorm:"-" json:"created"` | |||
| CreatedUnix int64 `json:"-"` | |||
| Time int64 `json:"time"` | |||
| } | |||
| if err := x.Sync2(new(Stopwatch)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| if err := x.Sync2(new(TrackedTime)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| //Updating existing issue units | |||
| units := make([]*RepoUnit, 0, 100) | |||
| err := x.Where("`type` = ?", V16UnitTypeIssues).Find(&units) | |||
| if err != nil { | |||
| return fmt.Errorf("Query repo units: %v", err) | |||
| } | |||
| for _, unit := range units { | |||
| if unit.Config == nil { | |||
| unit.Config = make(map[string]interface{}) | |||
| } | |||
| if _, ok := unit.Config["EnableTimetracker"]; !ok { | |||
| unit.Config["EnableTimetracker"] = setting.Service.DefaultEnableTimetracking | |||
| } | |||
| if _, ok := unit.Config["AllowOnlyContributorsToTrackTime"]; !ok { | |||
| unit.Config["AllowOnlyContributorsToTrackTime"] = setting.Service.DefaultAllowOnlyContributorsToTrackTime | |||
| } | |||
| if _, err := x.ID(unit.ID).Cols("config").Update(unit); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,55 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "time" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func migrateProtectedBranchStruct(x *xorm.Engine) error { | |||
| type ProtectedBranch struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"UNIQUE(s)"` | |||
| BranchName string `xorm:"UNIQUE(s)"` | |||
| CanPush bool | |||
| Created time.Time `xorm:"-"` | |||
| CreatedUnix int64 | |||
| Updated time.Time `xorm:"-"` | |||
| UpdatedUnix int64 | |||
| } | |||
| var pbs []ProtectedBranch | |||
| err := x.Find(&pbs) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| for _, pb := range pbs { | |||
| if pb.CanPush { | |||
| if _, err = x.ID(pb.ID).Delete(new(ProtectedBranch)); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| switch { | |||
| case setting.Database.UseSQLite3: | |||
| log.Warn("Unable to drop columns in SQLite") | |||
| case setting.Database.UseMySQL, setting.Database.UsePostgreSQL, setting.Database.UseMSSQL: | |||
| if _, err := x.Exec("ALTER TABLE protected_branch DROP COLUMN can_push"); err != nil { | |||
| // Ignoring this error in case we run this migration second time (after migration reordering) | |||
| log.Warn("DROP COLUMN can_push (skipping): %v", err) | |||
| } | |||
| default: | |||
| log.Fatal("Unrecognized DB") | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,42 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addDefaultValueToUserProhibitLogin(x *xorm.Engine) (err error) { | |||
| user := &models.User{ | |||
| ProhibitLogin: false, | |||
| } | |||
| if _, err := x.Where("`prohibit_login` IS NULL").Cols("prohibit_login").Update(user); err != nil { | |||
| return err | |||
| } | |||
| dialect := x.Dialect().DriverName() | |||
| switch dialect { | |||
| case "mysql": | |||
| _, err = x.Exec("ALTER TABLE user MODIFY `prohibit_login` tinyint(1) NOT NULL DEFAULT 0") | |||
| case "postgres": | |||
| _, err = x.Exec("ALTER TABLE \"user\" ALTER COLUMN `prohibit_login` SET NOT NULL, ALTER COLUMN `prohibit_login` SET DEFAULT false") | |||
| case "mssql": | |||
| // xorm already set DEFAULT 0 for data type BIT in mssql | |||
| _, err = x.Exec(`ALTER TABLE [user] ALTER COLUMN "prohibit_login" BIT NOT NULL`) | |||
| case "sqlite3": | |||
| } | |||
| if err != nil { | |||
| // Ignoring this error in case we run this migration second time (after migration reordering) | |||
| log.Warn("Error changing user prohibit_login column definition (skipping): %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,31 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addLFSLock(x *xorm.Engine) error { | |||
| // LFSLock see models/lfs_lock.go | |||
| type LFSLock struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"INDEX NOT NULL"` | |||
| Owner *models.User `xorm:"-"` | |||
| OwnerID int64 `xorm:"INDEX NOT NULL"` | |||
| Path string `xorm:"TEXT"` | |||
| Created time.Time `xorm:"created"` | |||
| } | |||
| if err := x.Sync2(new(LFSLock)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,28 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addReactions(x *xorm.Engine) error { | |||
| // Reaction see models/issue_reaction.go | |||
| type Reaction struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Type string `xorm:"INDEX UNIQUE(s) NOT NULL"` | |||
| IssueID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"` | |||
| CommentID int64 `xorm:"INDEX UNIQUE(s)"` | |||
| UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"` | |||
| CreatedUnix int64 `xorm:"INDEX created"` | |||
| } | |||
| if err := x.Sync2(new(Reaction)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,57 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addPullRequestOptions(x *xorm.Engine) error { | |||
| // RepoUnit describes all units of a repository | |||
| type RepoUnit struct { | |||
| ID int64 | |||
| RepoID int64 `xorm:"INDEX(s)"` | |||
| Type int `xorm:"INDEX(s)"` | |||
| Config map[string]interface{} `xorm:"JSON"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| //Updating existing issue units | |||
| units := make([]*RepoUnit, 0, 100) | |||
| if err := sess.Where("`type` = ?", V16UnitTypePRs).Find(&units); err != nil { | |||
| return fmt.Errorf("Query repo units: %v", err) | |||
| } | |||
| for _, unit := range units { | |||
| if unit.Config == nil { | |||
| unit.Config = make(map[string]interface{}) | |||
| } | |||
| if _, ok := unit.Config["IgnoreWhitespaceConflicts"]; !ok { | |||
| unit.Config["IgnoreWhitespaceConflicts"] = false | |||
| } | |||
| if _, ok := unit.Config["AllowMerge"]; !ok { | |||
| unit.Config["AllowMerge"] = true | |||
| } | |||
| if _, ok := unit.Config["AllowRebase"]; !ok { | |||
| unit.Config["AllowRebase"] = true | |||
| } | |||
| if _, ok := unit.Config["AllowSquash"]; !ok { | |||
| unit.Config["AllowSquash"] = true | |||
| } | |||
| if _, err := sess.ID(unit.ID).Cols("config").Update(unit); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,24 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "code.gitea.io/gitea/models" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addModeToDeploKeys(x *xorm.Engine) error { | |||
| type DeployKey struct { | |||
| Mode models.AccessMode `xorm:"NOT NULL DEFAULT 1"` | |||
| } | |||
| if err := x.Sync2(new(DeployKey)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "xorm.io/xorm" | |||
| ) | |||
| func removeIsOwnerColumnFromOrgUser(x *xorm.Engine) (err error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if err := dropTableColumns(sess, "org_user", "is_owner", "num_teams"); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,30 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addIssueClosedTime(x *xorm.Engine) error { | |||
| // Issue see models/issue.go | |||
| type Issue struct { | |||
| ClosedUnix timeutil.TimeStamp `xorm:"INDEX"` | |||
| } | |||
| if err := x.Sync2(new(Issue)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| if _, err := x.Exec("UPDATE `issue` SET `closed_unix` = `updated_unix` WHERE `is_closed` = ?", true); err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addLabelsDescriptions(x *xorm.Engine) error { | |||
| type Label struct { | |||
| Description string | |||
| } | |||
| if err := x.Sync2(new(Label)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,24 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addProtectedBranchMergeWhitelist(x *xorm.Engine) error { | |||
| type ProtectedBranch struct { | |||
| EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` | |||
| MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"` | |||
| MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | |||
| } | |||
| if err := x.Sync2(new(ProtectedBranch)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addFsckEnabledToRepo(x *xorm.Engine) error { | |||
| type Repository struct { | |||
| IsFsckEnabled bool `xorm:"NOT NULL DEFAULT true"` | |||
| } | |||
| if err := x.Sync2(new(Repository)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,45 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "os" | |||
| "path" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addSizeToAttachment(x *xorm.Engine) error { | |||
| type Attachment struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| UUID string `xorm:"uuid UNIQUE"` | |||
| Size int64 `xorm:"DEFAULT 0"` | |||
| } | |||
| if err := x.Sync2(new(Attachment)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| attachments := make([]Attachment, 0, 100) | |||
| if err := x.Find(&attachments); err != nil { | |||
| return fmt.Errorf("query attachments: %v", err) | |||
| } | |||
| for _, attach := range attachments { | |||
| localPath := path.Join(setting.AttachmentPath, attach.UUID[0:1], attach.UUID[1:2], attach.UUID) | |||
| fi, err := os.Stat(localPath) | |||
| if err != nil { | |||
| log.Error("calculate file size of attachment[UUID: %s]: %v", attach.UUID, err) | |||
| continue | |||
| } | |||
| attach.Size = fi.Size() | |||
| if _, err := x.ID(attach.ID).Cols("size").Update(attach); err != nil { | |||
| return fmt.Errorf("update size column: %v", err) | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addLastUsedPasscodeTOTP(x *xorm.Engine) error { | |||
| type TwoFactor struct { | |||
| LastUsedPasscode string `xorm:"VARCHAR(10)"` | |||
| } | |||
| if err := x.Sync2(new(TwoFactor)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addLanguageSetting(x *xorm.Engine) error { | |||
| type User struct { | |||
| Language string `xorm:"VARCHAR(5)"` | |||
| } | |||
| if err := x.Sync2(new(User)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,138 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addMultipleAssignees(x *xorm.Engine) error { | |||
| // Redeclare issue struct | |||
| type Issue struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"` | |||
| Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository. | |||
| PosterID int64 `xorm:"INDEX"` | |||
| Title string `xorm:"name"` | |||
| Content string `xorm:"TEXT"` | |||
| MilestoneID int64 `xorm:"INDEX"` | |||
| Priority int | |||
| AssigneeID int64 `xorm:"INDEX"` | |||
| IsClosed bool `xorm:"INDEX"` | |||
| IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not. | |||
| NumComments int | |||
| DeadlineUnix timeutil.TimeStamp `xorm:"INDEX"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| ClosedUnix timeutil.TimeStamp `xorm:"INDEX"` | |||
| } | |||
| // Updated the comment table | |||
| type Comment struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Type int | |||
| PosterID int64 `xorm:"INDEX"` | |||
| IssueID int64 `xorm:"INDEX"` | |||
| LabelID int64 | |||
| OldMilestoneID int64 | |||
| MilestoneID int64 | |||
| OldAssigneeID int64 | |||
| AssigneeID int64 | |||
| RemovedAssignee bool | |||
| OldTitle string | |||
| NewTitle string | |||
| CommitID int64 | |||
| Line int64 | |||
| Content string `xorm:"TEXT"` | |||
| RenderedContent string `xorm:"-"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| // Reference issue in commit message | |||
| CommitSHA string `xorm:"VARCHAR(40)"` | |||
| } | |||
| // Create the table | |||
| type IssueAssignees struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| AssigneeID int64 `xorm:"INDEX"` | |||
| IssueID int64 `xorm:"INDEX"` | |||
| } | |||
| if err := x.Sync2(IssueAssignees{}); err != nil { | |||
| return err | |||
| } | |||
| if err := x.Sync2(Comment{}); err != nil { | |||
| return err | |||
| } | |||
| // Range over all issues and insert a new entry for each issue/assignee | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| allIssues := []*Issue{} | |||
| if err := sess.Find(&allIssues); err != nil { | |||
| return err | |||
| } | |||
| for _, issue := range allIssues { | |||
| if issue.AssigneeID != 0 { | |||
| _, err := sess.Insert(IssueAssignees{IssueID: issue.ID, AssigneeID: issue.AssigneeID}) | |||
| if err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| // Migrate comments | |||
| // First update everything to not have nulls in db | |||
| if _, err := sess.Where("type = ?", 9).Cols("removed_assignee").Update(Comment{RemovedAssignee: false}); err != nil { | |||
| return err | |||
| } | |||
| allAssignementComments := []*Comment{} | |||
| if err := sess.Where("type = ?", 9).Find(&allAssignementComments); err != nil { | |||
| return err | |||
| } | |||
| for _, comment := range allAssignementComments { | |||
| // Everytime where OldAssigneeID is > 0, the assignement was removed. | |||
| if comment.OldAssigneeID > 0 { | |||
| _, err := sess.ID(comment.ID).Update(Comment{RemovedAssignee: true}) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| // Commit and begin new transaction for dropping columns | |||
| if err := sess.Commit(); err != nil { | |||
| return err | |||
| } | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if err := dropTableColumns(sess, "issue", "assignee_id"); err != nil { | |||
| return err | |||
| } | |||
| if err := dropTableColumns(sess, "issue_user", "is_assigned"); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,20 +0,0 @@ | |||
| package migrations | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addU2FReg(x *xorm.Engine) error { | |||
| type U2FRegistration struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Name string | |||
| UserID int64 `xorm:"INDEX"` | |||
| Raw []byte | |||
| Counter uint32 | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| } | |||
| return x.Sync2(&U2FRegistration{}) | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| // Copyright 2017 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func addLoginSourceIDToPublicKeyTable(x *xorm.Engine) error { | |||
| type PublicKey struct { | |||
| LoginSourceID int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| } | |||
| if err := x.Sync2(new(PublicKey)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -1,167 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func removeStaleWatches(x *xorm.Engine) error { | |||
| type Watch struct { | |||
| ID int64 | |||
| UserID int64 | |||
| RepoID int64 | |||
| } | |||
| type IssueWatch struct { | |||
| ID int64 | |||
| UserID int64 | |||
| RepoID int64 | |||
| IsWatching bool | |||
| } | |||
| type Repository struct { | |||
| ID int64 | |||
| IsPrivate bool | |||
| OwnerID int64 | |||
| } | |||
| type Access struct { | |||
| UserID int64 | |||
| RepoID int64 | |||
| Mode int | |||
| } | |||
| const ( | |||
| // AccessModeNone no access | |||
| AccessModeNone int = iota // 0 | |||
| // AccessModeRead read access | |||
| AccessModeRead // 1 | |||
| ) | |||
| accessLevel := func(e *xorm.Session, userID int64, repo *Repository) (int, error) { | |||
| mode := AccessModeNone | |||
| if !repo.IsPrivate { | |||
| mode = AccessModeRead | |||
| } | |||
| if userID == 0 { | |||
| return mode, nil | |||
| } | |||
| if userID == repo.OwnerID { | |||
| return 4, nil | |||
| } | |||
| a := &Access{UserID: userID, RepoID: repo.ID} | |||
| if has, err := e.Get(a); !has || err != nil { | |||
| return mode, err | |||
| } | |||
| return a.Mode, nil | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| var issueWatch IssueWatch | |||
| if exist, err := sess.IsTableExist(&issueWatch); err != nil { | |||
| return fmt.Errorf("IsExist IssueWatch: %v", err) | |||
| } else if !exist { | |||
| return nil | |||
| } | |||
| repoCache := make(map[int64]*Repository) | |||
| err := sess.BufferSize(setting.Database.IterateBufferSize).Iterate(new(Watch), | |||
| func(idx int, bean interface{}) error { | |||
| watch := bean.(*Watch) | |||
| repo := repoCache[watch.RepoID] | |||
| if repo == nil { | |||
| repo = &Repository{ | |||
| ID: watch.RepoID, | |||
| } | |||
| if _, err := sess.Get(repo); err != nil { | |||
| return err | |||
| } | |||
| repoCache[watch.RepoID] = repo | |||
| } | |||
| // Remove watches from now unaccessible repositories | |||
| mode, err := accessLevel(sess, watch.UserID, repo) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| has := AccessModeRead <= mode | |||
| if has { | |||
| return nil | |||
| } | |||
| if _, err = sess.Delete(&Watch{0, watch.UserID, repo.ID}); err != nil { | |||
| return err | |||
| } | |||
| _, err = sess.Exec("UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?", repo.ID) | |||
| return err | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| repoCache = make(map[int64]*Repository) | |||
| err = sess.BufferSize(setting.Database.IterateBufferSize). | |||
| Distinct("issue_watch.user_id", "issue.repo_id"). | |||
| Join("INNER", "issue", "issue_watch.issue_id = issue.id"). | |||
| Where("issue_watch.is_watching = ?", true). | |||
| Iterate(new(IssueWatch), | |||
| func(idx int, bean interface{}) error { | |||
| watch := bean.(*IssueWatch) | |||
| repo := repoCache[watch.RepoID] | |||
| if repo == nil { | |||
| repo = &Repository{ | |||
| ID: watch.RepoID, | |||
| } | |||
| if _, err := sess.Get(repo); err != nil { | |||
| return err | |||
| } | |||
| repoCache[watch.RepoID] = repo | |||
| } | |||
| // Remove issue watches from now unaccssible repositories | |||
| mode, err := accessLevel(sess, watch.UserID, repo) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| has := AccessModeRead <= mode | |||
| if has { | |||
| return nil | |||
| } | |||
| iw := &IssueWatch{ | |||
| IsWatching: false, | |||
| } | |||
| _, err = sess. | |||
| Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", watch.RepoID). | |||
| Cols("is_watching", "updated_unix"). | |||
| Where("`issue_watch`.user_id = ?", watch.UserID). | |||
| Update(iw) | |||
| return err | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,210 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "regexp" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "xorm.io/xorm" | |||
| ) | |||
| var topicPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`) | |||
| func validateTopic(topic string) bool { | |||
| return len(topic) <= 35 && topicPattern.MatchString(topic) | |||
| } | |||
| func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) { | |||
| log.Info("This migration could take up to minutes, please be patient.") | |||
| type Topic struct { | |||
| ID int64 | |||
| Name string `xorm:"UNIQUE VARCHAR(25)"` | |||
| RepoCount int | |||
| CreatedUnix int64 `xorm:"INDEX created"` | |||
| UpdatedUnix int64 `xorm:"INDEX updated"` | |||
| } | |||
| type RepoTopic struct { | |||
| RepoID int64 `xorm:"UNIQUE(s)"` | |||
| TopicID int64 `xorm:"UNIQUE(s)"` | |||
| } | |||
| type Repository struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| Topics []string `xorm:"TEXT JSON"` | |||
| } | |||
| if err := x.Sync2(new(Topic)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| if err := x.Sync2(new(RepoTopic)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| const batchSize = 100 | |||
| touchedRepo := make(map[int64]struct{}) | |||
| delTopicIDs := make([]int64, 0, batchSize) | |||
| log.Info("Validating existed topics...") | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| for start := 0; ; start += batchSize { | |||
| topics := make([]*Topic, 0, batchSize) | |||
| if err := x.Cols("id", "name").Asc("id").Limit(batchSize, start).Find(&topics); err != nil { | |||
| return err | |||
| } | |||
| if len(topics) == 0 { | |||
| break | |||
| } | |||
| for _, topic := range topics { | |||
| if validateTopic(topic.Name) { | |||
| continue | |||
| } | |||
| log.Info("Incorrect topic: id = %v, name = %q", topic.ID, topic.Name) | |||
| topic.Name = strings.Replace(strings.TrimSpace(strings.ToLower(topic.Name)), " ", "-", -1) | |||
| ids := make([]int64, 0, 30) | |||
| if err := sess.Table("repo_topic").Cols("repo_id"). | |||
| Where("topic_id = ?", topic.ID).Find(&ids); err != nil { | |||
| return err | |||
| } | |||
| log.Info("Touched repo ids: %v", ids) | |||
| for _, id := range ids { | |||
| touchedRepo[id] = struct{}{} | |||
| } | |||
| if validateTopic(topic.Name) { | |||
| unifiedTopic := Topic{Name: topic.Name} | |||
| exists, err := sess.Cols("id", "name").Get(&unifiedTopic) | |||
| log.Info("Exists topic with the name %q? %v, id = %v", topic.Name, exists, unifiedTopic.ID) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if exists { | |||
| log.Info("Updating repo_topic rows with topic_id = %v to topic_id = %v", topic.ID, unifiedTopic.ID) | |||
| if _, err := sess.Where("topic_id = ? AND repo_id NOT IN "+ | |||
| "(SELECT rt1.repo_id FROM repo_topic rt1 INNER JOIN repo_topic rt2 "+ | |||
| "ON rt1.repo_id = rt2.repo_id WHERE rt1.topic_id = ? AND rt2.topic_id = ?)", | |||
| topic.ID, topic.ID, unifiedTopic.ID).Update(&RepoTopic{TopicID: unifiedTopic.ID}); err != nil { | |||
| return err | |||
| } | |||
| log.Info("Updating topic `repo_count` field") | |||
| if _, err := sess.Exec( | |||
| "UPDATE topic SET repo_count = (SELECT COUNT(*) FROM repo_topic WHERE topic_id = ? GROUP BY topic_id) WHERE id = ?", | |||
| unifiedTopic.ID, unifiedTopic.ID); err != nil { | |||
| return err | |||
| } | |||
| } else { | |||
| log.Info("Updating topic: id = %v, name = %q", topic.ID, topic.Name) | |||
| if _, err := sess.Table("topic").ID(topic.ID). | |||
| Update(&Topic{Name: topic.Name}); err != nil { | |||
| return err | |||
| } | |||
| continue | |||
| } | |||
| } | |||
| delTopicIDs = append(delTopicIDs, topic.ID) | |||
| } | |||
| } | |||
| if err := sess.Commit(); err != nil { | |||
| return err | |||
| } | |||
| sess.Init() | |||
| log.Info("Deleting incorrect topics...") | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| log.Info("Deleting 'repo_topic' rows for topics with ids = %v", delTopicIDs) | |||
| if _, err := sess.In("topic_id", delTopicIDs).Delete(&RepoTopic{}); err != nil { | |||
| return err | |||
| } | |||
| log.Info("Deleting topics with id = %v", delTopicIDs) | |||
| if _, err := sess.In("id", delTopicIDs).Delete(&Topic{}); err != nil { | |||
| return err | |||
| } | |||
| if err := sess.Commit(); err != nil { | |||
| return err | |||
| } | |||
| delRepoTopics := make([]*RepoTopic, 0, batchSize) | |||
| log.Info("Checking the number of topics in the repositories...") | |||
| for start := 0; ; start += batchSize { | |||
| repoTopics := make([]*RepoTopic, 0, batchSize) | |||
| if err := x.Cols("repo_id").Asc("repo_id").Limit(batchSize, start). | |||
| GroupBy("repo_id").Having("COUNT(*) > 25").Find(&repoTopics); err != nil { | |||
| return err | |||
| } | |||
| if len(repoTopics) == 0 { | |||
| break | |||
| } | |||
| log.Info("Number of repositories with more than 25 topics: %v", len(repoTopics)) | |||
| for _, repoTopic := range repoTopics { | |||
| touchedRepo[repoTopic.RepoID] = struct{}{} | |||
| tmpRepoTopics := make([]*RepoTopic, 0, 30) | |||
| if err := x.Where("repo_id = ?", repoTopic.RepoID).Find(&tmpRepoTopics); err != nil { | |||
| return err | |||
| } | |||
| log.Info("Repository with id = %v has %v topics", repoTopic.RepoID, len(tmpRepoTopics)) | |||
| for i := len(tmpRepoTopics) - 1; i > 24; i-- { | |||
| delRepoTopics = append(delRepoTopics, tmpRepoTopics[i]) | |||
| } | |||
| } | |||
| } | |||
| sess.Init() | |||
| log.Info("Deleting superfluous topics for repositories (more than 25 topics)...") | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| for _, repoTopic := range delRepoTopics { | |||
| log.Info("Deleting 'repo_topic' rows for 'repository' with id = %v. Topic id = %v", | |||
| repoTopic.RepoID, repoTopic.TopicID) | |||
| if _, err := sess.Where("repo_id = ? AND topic_id = ?", repoTopic.RepoID, | |||
| repoTopic.TopicID).Delete(&RepoTopic{}); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.Exec( | |||
| "UPDATE topic SET repo_count = (SELECT repo_count FROM topic WHERE id = ?) - 1 WHERE id = ?", | |||
| repoTopic.TopicID, repoTopic.TopicID); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| log.Info("Updating repositories 'topics' fields...") | |||
| for repoID := range touchedRepo { | |||
| topicNames := make([]string, 0, 30) | |||
| if err := sess.Table("topic").Cols("name"). | |||
| Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id"). | |||
| Where("repo_topic.repo_id = ?", repoID).Desc("topic.repo_count").Find(&topicNames); err != nil { | |||
| return err | |||
| } | |||
| log.Info("Updating 'topics' field for repository with id = %v", repoID) | |||
| if _, err := sess.ID(repoID).Cols("topics"). | |||
| Update(&Repository{Topics: topicNames}); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -1,88 +0,0 @@ | |||
| // Copyright 2018 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "fmt" | |||
| "xorm.io/xorm" | |||
| ) | |||
| func moveTeamUnitsToTeamUnitTable(x *xorm.Engine) error { | |||
| // Team see models/team.go | |||
| type Team struct { | |||
| ID int64 | |||
| OrgID int64 | |||
| UnitTypes []int `xorm:"json"` | |||
| } | |||
| // TeamUnit see models/org_team.go | |||
| type TeamUnit struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| OrgID int64 `xorm:"INDEX"` | |||
| TeamID int64 `xorm:"UNIQUE(s)"` | |||
| Type int `xorm:"UNIQUE(s)"` | |||
| } | |||
| if err := x.Sync2(new(TeamUnit)); err != nil { | |||
| return fmt.Errorf("Sync2: %v", err) | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| // Update team unit types | |||
| const batchSize = 100 | |||
| for start := 0; ; start += batchSize { | |||
| teams := make([]*Team, 0, batchSize) | |||
| if err := x.Limit(batchSize, start).Find(&teams); err != nil { | |||
| return err | |||
| } | |||
| if len(teams) == 0 { | |||
| break | |||
| } | |||
| for _, team := range teams { | |||
| var unitTypes []int | |||
| if len(team.UnitTypes) == 0 { | |||
| unitTypes = allUnitTypes | |||
| } else { | |||
| unitTypes = team.UnitTypes | |||
| } | |||
| // insert units for team | |||
| var units = make([]TeamUnit, 0, len(unitTypes)) | |||
| for _, tp := range unitTypes { | |||
| units = append(units, TeamUnit{ | |||
| OrgID: team.OrgID, | |||
| TeamID: team.ID, | |||
| Type: tp, | |||
| }) | |||
| } | |||
| if _, err := sess.Insert(&units); err != nil { | |||
| return fmt.Errorf("Insert team units: %v", err) | |||
| } | |||
| } | |||
| } | |||
| // Commit and begin new transaction for dropping columns | |||
| if err := sess.Commit(); err != nil { | |||
| return err | |||
| } | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if err := dropTableColumns(sess, "team", "unit_types"); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -26,6 +26,18 @@ func addIssueDependencies(x *xorm.Engine) (err error) { | |||
| UpdatedUnix int64 `xorm:"updated"` | |||
| } | |||
| const ( | |||
| v16UnitTypeCode = iota + 1 // 1 code | |||
| v16UnitTypeIssues // 2 issues | |||
| v16UnitTypePRs // 3 PRs | |||
| v16UnitTypeCommits // 4 Commits | |||
| v16UnitTypeReleases // 5 Releases | |||
| v16UnitTypeWiki // 6 Wiki | |||
| v16UnitTypeSettings // 7 Settings | |||
| v16UnitTypeExternalWiki // 8 ExternalWiki | |||
| v16UnitTypeExternalTracker // 9 ExternalTracker | |||
| ) | |||
| if err = x.Sync(new(IssueDependency)); err != nil { | |||
| return fmt.Errorf("Error creating issue_dependency_table column definition: %v", err) | |||
| } | |||
| @@ -80,7 +92,7 @@ func addIssueDependencies(x *xorm.Engine) (err error) { | |||
| //Updating existing issue units | |||
| units := make([]*RepoUnit, 0, 100) | |||
| err = x.Where("`type` = ?", V16UnitTypeIssues).Find(&units) | |||
| err = x.Where("`type` = ?", v16UnitTypeIssues).Find(&units) | |||
| if err != nil { | |||
| return fmt.Errorf("Query repo units: %v", err) | |||
| } | |||
| @@ -22,6 +22,18 @@ func addPullRequestRebaseWithMerge(x *xorm.Engine) error { | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"` | |||
| } | |||
| const ( | |||
| v16UnitTypeCode = iota + 1 // 1 code | |||
| v16UnitTypeIssues // 2 issues | |||
| v16UnitTypePRs // 3 PRs | |||
| v16UnitTypeCommits // 4 Commits | |||
| v16UnitTypeReleases // 5 Releases | |||
| v16UnitTypeWiki // 6 Wiki | |||
| v16UnitTypeSettings // 7 Settings | |||
| v16UnitTypeExternalWiki // 8 ExternalWiki | |||
| v16UnitTypeExternalTracker // 9 ExternalTracker | |||
| ) | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| @@ -30,7 +42,7 @@ func addPullRequestRebaseWithMerge(x *xorm.Engine) error { | |||
| //Updating existing issue units | |||
| units := make([]*RepoUnit, 0, 100) | |||
| if err := sess.Where("`type` = ?", V16UnitTypePRs).Find(&units); err != nil { | |||
| if err := sess.Where("`type` = ?", v16UnitTypePRs).Find(&units); err != nil { | |||
| return fmt.Errorf("Query repo units: %v", err) | |||
| } | |||
| for _, unit := range units { | |||