diff --git a/go.mod b/go.mod index 08a663dcdd837..e5303d0936843 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( github.com/go-redis/redis v6.15.2+incompatible github.com/go-sql-driver/mysql v1.4.1 github.com/go-swagger/go-swagger v0.20.1 - github.com/go-xorm/xorm v0.7.8 + github.com/go-xorm/xorm v0.7.9 github.com/gobwas/glob v0.2.3 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 diff --git a/go.sum b/go.sum index 10ad062635280..421c2ca7e4526 100644 --- a/go.sum +++ b/go.sum @@ -251,6 +251,8 @@ github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/go-xorm/xorm v0.7.8 h1:rKxZJB9mWQ9Nw2TbjsepiThR031jkGePOWXwTtEAU08= github.com/go-xorm/xorm v0.7.8/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= +github.com/go-xorm/xorm v0.7.9 h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0= +github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= diff --git a/integrations/api_repo_edit_test.go b/integrations/api_repo_edit_test.go index 1231201b978fe..c1b513d0753c1 100644 --- a/integrations/api_repo_edit_test.go +++ b/integrations/api_repo_edit_test.go @@ -23,12 +23,35 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption { website := repo.Website private := repo.IsPrivate hasIssues := false - if _, err := repo.GetUnit(models.UnitTypeIssues); err == nil { + var internalTracker *api.InternalTracker + var externalTracker *api.ExternalTracker + if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil { + config := unit.IssuesConfig() hasIssues = true + internalTracker = &api.InternalTracker{ + EnableTimeTracker: config.EnableTimetracker, + AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime, + EnableIssueDependencies: config.EnableDependencies, + } + } else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil { + config := unit.ExternalTrackerConfig() + hasIssues = true + externalTracker = &api.ExternalTracker{ + ExternalTrackerURL: config.ExternalTrackerURL, + ExternalTrackerFormat: config.ExternalTrackerFormat, + ExternalTrackerStyle: config.ExternalTrackerStyle, + } } hasWiki := false + var externalWiki *api.ExternalWiki if _, err := repo.GetUnit(models.UnitTypeWiki); err == nil { hasWiki = true + } else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil { + hasWiki = true + config := unit.ExternalWikiConfig() + externalWiki = &api.ExternalWiki{ + ExternalWikiURL: config.ExternalWikiURL, + } } defaultBranch := repo.DefaultBranch hasPullRequests := false @@ -53,7 +76,10 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption { Website: &website, Private: &private, HasIssues: &hasIssues, + ExternalTracker: externalTracker, + InternalTracker: internalTracker, HasWiki: &hasWiki, + ExternalWiki: externalWiki, DefaultBranch: &defaultBranch, HasPullRequests: &hasPullRequests, IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts, @@ -143,6 +169,84 @@ func TestAPIRepoEdit(t *testing.T) { assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived) assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private) assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki) + + //Test editing repo1 to use internal issue and wiki (default) + *repoEditOption.HasIssues = true + repoEditOption.ExternalTracker = nil + repoEditOption.InternalTracker = &api.InternalTracker{ + EnableTimeTracker: false, + AllowOnlyContributorsToTrackTime: false, + EnableIssueDependencies: false, + } + *repoEditOption.HasWiki = true + repoEditOption.ExternalWiki = nil + url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2) + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &repo) + assert.NotNil(t, repo) + // check repo1 was written to database + repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + repo1editedOption = getRepoEditOptionFromRepo(repo1edited) + assert.Equal(t, *repo1editedOption.HasIssues, true) + assert.Nil(t, repo1editedOption.ExternalTracker) + assert.Equal(t, *repo1editedOption.InternalTracker, *repoEditOption.InternalTracker) + assert.Equal(t, *repo1editedOption.HasWiki, true) + assert.Nil(t, repo1editedOption.ExternalWiki) + + //Test editing repo1 to use external issue and wiki + repoEditOption.ExternalTracker = &api.ExternalTracker{ + ExternalTrackerURL: "http://www.somewebsite.com", + ExternalTrackerFormat: "http://www.somewebsite.com/{user}/{repo}?issue={index}", + ExternalTrackerStyle: "alphanumeric", + } + repoEditOption.ExternalWiki = &api.ExternalWiki{ + ExternalWikiURL: "http://www.somewebsite.com", + } + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &repo) + assert.NotNil(t, repo) + // check repo1 was written to database + repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + repo1editedOption = getRepoEditOptionFromRepo(repo1edited) + assert.Equal(t, *repo1editedOption.HasIssues, true) + assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker) + assert.Equal(t, *repo1editedOption.HasWiki, true) + assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki) + + // Do some tests with invalid URL for external tracker and wiki + repoEditOption.ExternalTracker.ExternalTrackerURL = "htp://www.somewebsite.com" + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity) + repoEditOption.ExternalTracker.ExternalTrackerURL = "http://www.somewebsite.com" + repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user/{repo}?issue={index}" + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity) + repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user}/{repo}?issue={index}" + repoEditOption.ExternalWiki.ExternalWikiURL = "htp://www.somewebsite.com" + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity) + + //Test small repo change through API with issue and wiki option not set; They shall not be touched. + *repoEditOption.Description = "small change" + repoEditOption.HasIssues = nil + repoEditOption.ExternalTracker = nil + repoEditOption.HasWiki = nil + repoEditOption.ExternalWiki = nil + req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &repo) + assert.NotNil(t, repo) + // check repo1 was written to database + repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) + repo1editedOption = getRepoEditOptionFromRepo(repo1edited) + assert.Equal(t, *repo1editedOption.Description, *repoEditOption.Description) + assert.Equal(t, *repo1editedOption.HasIssues, true) + assert.NotNil(t, *repo1editedOption.ExternalTracker) + assert.Equal(t, *repo1editedOption.HasWiki, true) + assert.NotNil(t, *repo1editedOption.ExternalWiki) + // reset repo in db url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2) req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption) diff --git a/models/repo.go b/models/repo.go index eb7f286fec40a..69f32ae4a521a 100644 --- a/models/repo.go +++ b/models/repo.go @@ -275,12 +275,35 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) } } hasIssues := false - if _, err := repo.getUnit(e, UnitTypeIssues); err == nil { + var externalTracker *api.ExternalTracker + var internalTracker *api.InternalTracker + if unit, err := repo.getUnit(e, UnitTypeIssues); err == nil { + config := unit.IssuesConfig() hasIssues = true + internalTracker = &api.InternalTracker{ + EnableTimeTracker: config.EnableTimetracker, + AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime, + EnableIssueDependencies: config.EnableDependencies, + } + } else if unit, err := repo.getUnit(e, UnitTypeExternalTracker); err == nil { + config := unit.ExternalTrackerConfig() + hasIssues = true + externalTracker = &api.ExternalTracker{ + ExternalTrackerURL: config.ExternalTrackerURL, + ExternalTrackerFormat: config.ExternalTrackerFormat, + ExternalTrackerStyle: config.ExternalTrackerStyle, + } } hasWiki := false + var externalWiki *api.ExternalWiki if _, err := repo.getUnit(e, UnitTypeWiki); err == nil { hasWiki = true + } else if unit, err := repo.getUnit(e, UnitTypeExternalWiki); err == nil { + hasWiki = true + config := unit.ExternalWikiConfig() + externalWiki = &api.ExternalWiki{ + ExternalWikiURL: config.ExternalWikiURL, + } } hasPullRequests := false ignoreWhitespaceConflicts := false @@ -324,7 +347,10 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) Updated: repo.UpdatedUnix.AsTime(), Permissions: permission, HasIssues: hasIssues, + ExternalTracker: externalTracker, + InternalTracker: internalTracker, HasWiki: hasWiki, + ExternalWiki: externalWiki, HasPullRequests: hasPullRequests, IgnoreWhitespaceConflicts: ignoreWhitespaceConflicts, AllowMerge: allowMerge, diff --git a/modules/structs/repo.go b/modules/structs/repo.go index d94980fca4c7e..87396d6ce99a9 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -15,6 +15,35 @@ type Permission struct { Pull bool `json:"pull"` } +// InternalTracker represents settings for internal tracker +// swagger:model +type InternalTracker struct { + // Enable time tracking (Built-in issue tracker) + EnableTimeTracker bool `json:"enable_time_tracker"` + // Let only contributors track time (Built-in issue tracker) + AllowOnlyContributorsToTrackTime bool `json:"allow_only_contributors_to_track_time"` + // Enable dependencies for issues and pull requests (Built-in issue tracker) + EnableIssueDependencies bool `json:"enable_issue_dependencies"` +} + +// ExternalTracker represents settings for external tracker +// swagger:model +type ExternalTracker struct { + // URL of external issue tracker. + ExternalTrackerURL string `json:"external_tracker_url"` + // External Issue Tracker URL Format. Use the placeholders {user}, {repo} and {index} for the username, repository name and issue index. + ExternalTrackerFormat string `json:"external_tracker_format"` + // External Issue Tracker Number Format, either `numeric` or `alphanumeric` + ExternalTrackerStyle string `json:"external_tracker_style"` +} + +// ExternalWiki represents setting for external wiki +// swagger:model +type ExternalWiki struct { + // URL of external wiki. + ExternalWikiURL string `json:"external_wiki_url"` +} + // Repository represents a repository type Repository struct { ID int64 `json:"id"` @@ -42,17 +71,20 @@ type Repository struct { // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time - Updated time.Time `json:"updated_at"` - Permissions *Permission `json:"permissions,omitempty"` - HasIssues bool `json:"has_issues"` - HasWiki bool `json:"has_wiki"` - HasPullRequests bool `json:"has_pull_requests"` - IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"` - AllowMerge bool `json:"allow_merge_commits"` - AllowRebase bool `json:"allow_rebase"` - AllowRebaseMerge bool `json:"allow_rebase_explicit"` - AllowSquash bool `json:"allow_squash_merge"` - AvatarURL string `json:"avatar_url"` + Updated time.Time `json:"updated_at"` + Permissions *Permission `json:"permissions,omitempty"` + HasIssues bool `json:"has_issues"` + InternalTracker *InternalTracker `json:"internal_tracker,omitempty"` + ExternalTracker *ExternalTracker `json:"external_tracker,omitempty"` + HasWiki bool `json:"has_wiki"` + ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"` + HasPullRequests bool `json:"has_pull_requests"` + IgnoreWhitespaceConflicts bool `json:"ignore_whitespace_conflicts"` + AllowMerge bool `json:"allow_merge_commits"` + AllowRebase bool `json:"allow_rebase"` + AllowRebaseMerge bool `json:"allow_rebase_explicit"` + AllowSquash bool `json:"allow_squash_merge"` + AvatarURL string `json:"avatar_url"` } // CreateRepoOption options when creating repository @@ -95,8 +127,14 @@ type EditRepoOption struct { Private *bool `json:"private,omitempty"` // either `true` to enable issues for this repository or `false` to disable them. HasIssues *bool `json:"has_issues,omitempty"` + // set this structure to configure internal issue tracker (requires has_issues) + InternalTracker *InternalTracker `json:"internal_tracker,omitempty"` + // set this structure to use external issue tracker (requires has_issues) + ExternalTracker *ExternalTracker `json:"external_tracker,omitempty"` // either `true` to enable the wiki for this repository or `false` to disable it. HasWiki *bool `json:"has_wiki,omitempty"` + // set this structure to use external wiki instead of internal (requires has_wiki) + ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"` // sets the default branch for this repository. DefaultBranch *string `json:"default_branch,omitempty"` // either `true` to allow pull requests, or `false` to prevent pull request. diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index e464b016b1b55..ca38757e1c7fe 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1325,6 +1325,7 @@ settings.protect_merge_whitelist_committers_desc=ホワイトリストに登録 settings.protect_merge_whitelist_users=マージ・ホワイトリストに含むユーザー: settings.protect_merge_whitelist_teams=マージ・ホワイトリストに含むチーム: settings.protect_check_status_contexts=ステータスチェックを有効にする +settings.protect_check_status_contexts_desc=マージの前にステータスチェックがパスしていることを必須にします。 このルールの対象ブランチへのマージが可能となるまでに、事前にパスしている必要があるステータスチェックを選んでください。 有効にする場合は、まずコミットを別のブランチにプッシュし、ステータスチェックがパスしたあと、このルールの対象ブランチにマージするか、直接プッシュするようにします。 条件が選択されていない場合は、最後のコミットが成功していることが必須条件となります。 settings.protect_check_status_contexts_list=1週間の間にこのリポジトリにあったステータスチェック settings.protect_required_approvals=必要な承認数: settings.protect_required_approvals_desc=ホワイトリストに登録したユーザーやチームがレビューを行い、肯定的なレビューの数を満たしたプルリクエストしかマージできないようにします。 diff --git a/public/css/theme-arc-green.css b/public/css/theme-arc-green.css index 938904c0bc216..28a127a3dd7b1 100644 --- a/public/css/theme-arc-green.css +++ b/public/css/theme-arc-green.css @@ -42,7 +42,7 @@ a:hover{color:#a0cc75} .ui.attached.table{border:1px solid #304251;background:#304251} .feeds .list ul li:not(:last-child){border-bottom:1px solid #333640} .feeds .list ul li.private{background:#353945;border:1px solid #333640} -.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff} +.ui.secondary.menu .active.item:hover,.ui.secondary.menu .dropdown.item:hover,.ui.secondary.menu .link.item:hover,.ui.secondary.menu a.item:hover{color:#fff} .ui.menu .ui.dropdown .menu>.item{background:#2c303a!important;color:#9e9e9e!important} .ui.secondary.menu .dropdown.item>.menu,.ui.text.menu .dropdown.item>.menu{border:1px solid #434444} footer{background:#2e323e;border-top:1px solid #313131} diff --git a/public/less/themes/arc-green.less b/public/less/themes/arc-green.less index cff51f0908f9d..27c32728a2f61 100644 --- a/public/less/themes/arc-green.less +++ b/public/less/themes/arc-green.less @@ -225,6 +225,7 @@ a:hover { .ui.secondary.menu .dropdown.item:hover, .ui.secondary.menu .link.item:hover, +.ui.secondary.menu .active.item:hover, .ui.secondary.menu a.item:hover { color: #ffffff; } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 513e7a37b3560..d8b06862a5ea6 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/routers/api/v1/convert" mirror_service "code.gitea.io/gitea/services/mirror" ) @@ -669,27 +670,56 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { units = append(units, *unit) } } else if *opts.HasIssues { - // We don't currently allow setting individual issue settings through the API, - // only can enable/disable issues, so when enabling issues, - // we either get the existing config which means it was already enabled, - // or create a new config since it doesn't exist. - unit, err := repo.GetUnit(models.UnitTypeIssues) - var config *models.IssuesConfig - if err != nil { - // Unit type doesn't exist so we make a new config file with default values - config = &models.IssuesConfig{ - EnableTimetracker: true, - AllowOnlyContributorsToTrackTime: true, - EnableDependencies: true, + if opts.ExternalTracker != nil { + + // Check that values are valid + if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) { + err := fmt.Errorf("External tracker URL not valid") + ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL", err) + return err } + if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) { + err := fmt.Errorf("External tracker URL format not valid") + ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL format", err) + return err + } + + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeExternalTracker, + Config: &models.ExternalTrackerConfig{ + ExternalTrackerURL: opts.ExternalTracker.ExternalTrackerURL, + ExternalTrackerFormat: opts.ExternalTracker.ExternalTrackerFormat, + ExternalTrackerStyle: opts.ExternalTracker.ExternalTrackerStyle, + }, + }) } else { - config = unit.IssuesConfig() + // Default to built-in tracker + var config *models.IssuesConfig + + if opts.InternalTracker != nil { + config = &models.IssuesConfig{ + EnableTimetracker: opts.InternalTracker.EnableTimeTracker, + AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime, + EnableDependencies: opts.InternalTracker.EnableIssueDependencies, + } + } else if unit, err := repo.GetUnit(models.UnitTypeIssues); err != nil { + // Unit type doesn't exist so we make a new config file with default values + config = &models.IssuesConfig{ + EnableTimetracker: true, + AllowOnlyContributorsToTrackTime: true, + EnableDependencies: true, + } + } else { + config = unit.IssuesConfig() + } + + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeIssues, + Config: config, + }) } - units = append(units, models.RepoUnit{ - RepoID: repo.ID, - Type: models.UnitTypeIssues, - Config: config, - }) } if opts.HasWiki == nil { @@ -700,16 +730,30 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { units = append(units, *unit) } } else if *opts.HasWiki { - // We don't currently allow setting individual wiki settings through the API, - // only can enable/disable the wiki, so when enabling the wiki, - // we either get the existing config which means it was already enabled, - // or create a new config since it doesn't exist. - config := &models.UnitConfig{} - units = append(units, models.RepoUnit{ - RepoID: repo.ID, - Type: models.UnitTypeWiki, - Config: config, - }) + if opts.ExternalWiki != nil { + + // Check that values are valid + if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) { + err := fmt.Errorf("External wiki URL not valid") + ctx.Error(http.StatusUnprocessableEntity, "", "Invalid external wiki URL") + return err + } + + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeExternalWiki, + Config: &models.ExternalWikiConfig{ + ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL, + }, + }) + } else { + config := &models.UnitConfig{} + units = append(units, models.RepoUnit{ + RepoID: repo.ID, + Type: models.UnitTypeWiki, + Config: config, + }) + } } if opts.HasPullRequests == nil { diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index 0711270cb9fd7..48b4e7afff66e 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -198,20 +198,17 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { } // GogsHooksNewPost response for creating webhook -func GogsHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { - newGenericWebhookPost(ctx, form, models.GOGS) +func GogsHooksNewPost(ctx *context.Context, form auth.NewGogshookForm) { + newGogsWebhookPost(ctx, form, models.GOGS) } -func newGenericWebhookPost(ctx *context.Context, form auth.NewWebhookForm, kind models.HookTaskType) { +// newGogsWebhookPost response for creating gogs hook +func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind models.HookTaskType) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} - - ctx.Data["HookType"] = "gitea" - if kind == models.GOGS { - ctx.Data["HookType"] = "gogs" - } + ctx.Data["HookType"] = "gogs" orCtx, err := getOrgRepoCtx(ctx) if err != nil { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 5262d4ad5cf7f..11f2029226a7a 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -444,7 +444,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", admin.DeleteDefaultWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) @@ -452,7 +452,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) m.Get("/:id", repo.WebHooksEdit) m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) - m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksEditPost) + m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost) m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) @@ -585,7 +585,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", org.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) @@ -647,7 +647,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", repo.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) - m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost) + m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index fcc26f5c54bcd..d8750d8bcce46 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -8469,6 +8469,12 @@ "type": "string", "x-go-name": "Description" }, + "external_tracker": { + "$ref": "#/definitions/ExternalTracker" + }, + "external_wiki": { + "$ref": "#/definitions/ExternalWiki" + }, "has_issues": { "description": "either `true` to enable issues for this repository or `false` to disable them.", "type": "boolean", @@ -8489,6 +8495,9 @@ "type": "boolean", "x-go-name": "IgnoreWhitespaceConflicts" }, + "internal_tracker": { + "$ref": "#/definitions/InternalTracker" + }, "name": { "description": "name of the repository", "type": "string", @@ -8644,6 +8653,40 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "ExternalTracker": { + "description": "ExternalTracker represents settings for external tracker", + "type": "object", + "properties": { + "external_tracker_format": { + "description": "External Issue Tracker URL Format. Use the placeholders {user}, {repo} and {index} for the username, repository name and issue index.", + "type": "string", + "x-go-name": "ExternalTrackerFormat" + }, + "external_tracker_style": { + "description": "External Issue Tracker Number Format, either `numeric` or `alphanumeric`", + "type": "string", + "x-go-name": "ExternalTrackerStyle" + }, + "external_tracker_url": { + "description": "URL of external issue tracker.", + "type": "string", + "x-go-name": "ExternalTrackerURL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, + "ExternalWiki": { + "description": "ExternalWiki represents setting for external wiki", + "type": "object", + "properties": { + "external_wiki_url": { + "description": "URL of external wiki.", + "type": "string", + "x-go-name": "ExternalWikiURL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "FileCommitResponse": { "type": "object", "title": "FileCommitResponse contains information generated from a Git commit for a repo's file.", @@ -9008,6 +9051,28 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "InternalTracker": { + "description": "InternalTracker represents settings for internal tracker", + "type": "object", + "properties": { + "allow_only_contributors_to_track_time": { + "description": "Let only contributors track time (Built-in issue tracker)", + "type": "boolean", + "x-go-name": "AllowOnlyContributorsToTrackTime" + }, + "enable_issue_dependencies": { + "description": "Enable dependencies for issues and pull requests (Built-in issue tracker)", + "type": "boolean", + "x-go-name": "EnableIssueDependencies" + }, + "enable_time_tracker": { + "description": "Enable time tracking (Built-in issue tracker)", + "type": "boolean", + "x-go-name": "EnableTimeTracker" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Issue": { "description": "Issue represents an issue in a repository", "type": "object", @@ -9863,6 +9928,12 @@ "type": "boolean", "x-go-name": "Empty" }, + "external_tracker": { + "$ref": "#/definitions/ExternalTracker" + }, + "external_wiki": { + "$ref": "#/definitions/ExternalWiki" + }, "fork": { "type": "boolean", "x-go-name": "Fork" @@ -9901,6 +9972,9 @@ "type": "boolean", "x-go-name": "IgnoreWhitespaceConflicts" }, + "internal_tracker": { + "$ref": "#/definitions/InternalTracker" + }, "mirror": { "type": "boolean", "x-go-name": "Mirror" diff --git a/vendor/github.com/go-xorm/xorm/.drone.yml b/vendor/github.com/go-xorm/xorm/.drone.yml index bd682e5ff16da..b162d7c8a4ff3 100644 --- a/vendor/github.com/go-xorm/xorm/.drone.yml +++ b/vendor/github.com/go-xorm/xorm/.drone.yml @@ -114,7 +114,18 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.10 + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -133,6 +144,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 @@ -309,8 +329,23 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" + + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.11 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" - go get github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -329,6 +364,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 @@ -377,13 +421,6 @@ steps: depth: 50 tags: true -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - - name: build pull: default image: golang:1.12 @@ -505,8 +542,22 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - - go get -u github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.12 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" + - go get github.com/wadey/gocovmerge + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -525,6 +576,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 @@ -573,13 +633,6 @@ steps: depth: 50 tags: true -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - - name: build pull: default image: golang:1.13 @@ -701,8 +754,22 @@ steps: commands: - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - - go get -u github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt > coverage.txt + when: + event: + - push + - pull_request + +- name: test-tidb + pull: default + image: golang:1.13 + environment: + GO111MODULE: "on" + GOPROXY: "https://goproxy.cn" + commands: + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" + - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" + - go get github.com/wadey/gocovmerge + - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt when: event: - push @@ -721,6 +788,15 @@ services: - tag - pull_request +- name: tidb + pull: default + image: pingcap/tidb:v3.0.3 + when: + event: + - push + - tag + - pull_request + - name: pgsql pull: default image: postgres:9.5 diff --git a/vendor/github.com/go-xorm/xorm/dialect_mssql.go b/vendor/github.com/go-xorm/xorm/dialect_mssql.go index ce4dd00c19bd6..29070da2fbec3 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_mssql.go +++ b/vendor/github.com/go-xorm/xorm/dialect_mssql.go @@ -338,8 +338,9 @@ func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) { func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{} s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable, + "default_is_null" = (CASE WHEN c.text is null THEN 1 ELSE 0 END), replace(replace(isnull(c.text,''),'(',''),')','') as vdefault, - ISNULL(i.is_primary_key, 0) + ISNULL(i.is_primary_key, 0), a.is_identity as is_identity from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id left join sys.syscomments c on a.default_object_id=c.id @@ -361,8 +362,8 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column for rows.Next() { var name, ctype, vdefault string var maxLen, precision, scale int - var nullable, isPK bool - err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault, &isPK) + var nullable, isPK, defaultIsNull, isIncrement bool + err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &defaultIsNull, &vdefault, &isPK, &isIncrement) if err != nil { return nil, nil, err } @@ -371,8 +372,12 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column col.Indexes = make(map[string]int) col.Name = strings.Trim(name, "` ") col.Nullable = nullable - col.Default = vdefault + col.DefaultIsEmpty = defaultIsNull + if !defaultIsNull { + col.Default = vdefault + } col.IsPrimaryKey = isPK + col.IsAutoIncrement = isIncrement ct := strings.ToUpper(ctype) if ct == "DECIMAL" { col.Length = precision @@ -395,15 +400,6 @@ func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column } } - if col.SQLType.IsText() || col.SQLType.IsTime() { - if col.Default != "" { - col.Default = "'" + col.Default + "'" - } else { - if col.DefaultIsEmpty { - col.Default = "''" - } - } - } cols[col.Name] = col colSeq = append(colSeq, col.Name) } diff --git a/vendor/github.com/go-xorm/xorm/dialect_mysql.go b/vendor/github.com/go-xorm/xorm/dialect_mysql.go index a108b81f5e0ca..cf1dbb6f214f3 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_mysql.go +++ b/vendor/github.com/go-xorm/xorm/dialect_mysql.go @@ -345,9 +345,9 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column if colDefault != nil { col.Default = *colDefault - if col.Default == "" { - col.DefaultIsEmpty = true - } + col.DefaultIsEmpty = false + } else { + col.DefaultIsEmpty = true } cts := strings.Split(colType, "(") @@ -411,13 +411,11 @@ func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column col.IsAutoIncrement = true } - if col.SQLType.IsText() || col.SQLType.IsTime() { - if col.Default != "" { + if !col.DefaultIsEmpty { + if col.SQLType.IsText() { + col.Default = "'" + col.Default + "'" + } else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" { col.Default = "'" + col.Default + "'" - } else { - if col.DefaultIsEmpty { - col.Default = "''" - } } } cols[col.Name] = col diff --git a/vendor/github.com/go-xorm/xorm/dialect_postgres.go b/vendor/github.com/go-xorm/xorm/dialect_postgres.go index 3df682e81ac4c..ccef3086b264a 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_postgres.go +++ b/vendor/github.com/go-xorm/xorm/dialect_postgres.go @@ -1005,16 +1005,18 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att col.Name = strings.Trim(colName, `" `) - if colDefault != nil || isPK { - if isPK { - col.IsPrimaryKey = true - } else { - col.Default = *colDefault + if colDefault != nil { + col.Default = *colDefault + col.DefaultIsEmpty = false + if strings.HasPrefix(col.Default, "nextval(") { + col.IsAutoIncrement = true } + } else { + col.DefaultIsEmpty = true } - if colDefault != nil && strings.HasPrefix(*colDefault, "nextval(") { - col.IsAutoIncrement = true + if isPK { + col.IsPrimaryKey = true } col.Nullable = (isNullable == "YES") @@ -1043,12 +1045,16 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att col.Length = maxLen - if col.SQLType.IsText() || col.SQLType.IsTime() { - if col.Default != "" { - col.Default = "'" + col.Default + "'" - } else { - if col.DefaultIsEmpty { - col.Default = "''" + if !col.DefaultIsEmpty { + if col.SQLType.IsText() { + if strings.HasSuffix(col.Default, "::character varying") { + col.Default = strings.TrimRight(col.Default, "::character varying") + } else if !strings.HasPrefix(col.Default, "'") { + col.Default = "'" + col.Default + "'" + } + } else if col.SQLType.IsTime() { + if strings.HasSuffix(col.Default, "::timestamp without time zone") { + col.Default = strings.TrimRight(col.Default, "::timestamp without time zone") } } } diff --git a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go index 60f07295e843b..0a290f3c480df 100644 --- a/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go +++ b/vendor/github.com/go-xorm/xorm/dialect_sqlite3.go @@ -270,6 +270,68 @@ func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) { return false, nil } +// splitColStr splits a sqlite col strings as fields +func splitColStr(colStr string) []string { + colStr = strings.TrimSpace(colStr) + var results = make([]string, 0, 10) + var lastIdx int + var hasC, hasQuote bool + for i, c := range colStr { + if c == ' ' && !hasQuote { + if hasC { + results = append(results, colStr[lastIdx:i]) + hasC = false + } + } else { + if c == '\'' { + hasQuote = !hasQuote + } + if !hasC { + lastIdx = i + } + hasC = true + if i == len(colStr)-1 { + results = append(results, colStr[lastIdx:i+1]) + } + } + } + return results +} + +func parseString(colStr string) (*core.Column, error) { + fields := splitColStr(colStr) + col := new(core.Column) + col.Indexes = make(map[string]int) + col.Nullable = true + col.DefaultIsEmpty = true + + for idx, field := range fields { + if idx == 0 { + col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`) + continue + } else if idx == 1 { + col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0} + continue + } + switch field { + case "PRIMARY": + col.IsPrimaryKey = true + case "AUTOINCREMENT": + col.IsAutoIncrement = true + case "NULL": + if fields[idx-1] == "NOT" { + col.Nullable = false + } else { + col.Nullable = true + } + case "DEFAULT": + col.Default = fields[idx+1] + col.DefaultIsEmpty = false + } + } + return col, nil +} + func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { args := []interface{}{tableName} s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?" @@ -299,6 +361,7 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu colCreates := reg.FindAllString(name[nStart+1:nEnd], -1) cols := make(map[string]*core.Column) colSeq := make([]string, 0) + for _, colStr := range colCreates { reg = regexp.MustCompile(`,\s`) colStr = reg.ReplaceAllString(colStr, ",") @@ -315,38 +378,11 @@ func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Colu continue } - fields := strings.Fields(strings.TrimSpace(colStr)) - col := new(core.Column) - col.Indexes = make(map[string]int) - col.Nullable = true - col.DefaultIsEmpty = true - - for idx, field := range fields { - if idx == 0 { - col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`) - continue - } else if idx == 1 { - col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0} - } - switch field { - case "PRIMARY": - col.IsPrimaryKey = true - case "AUTOINCREMENT": - col.IsAutoIncrement = true - case "NULL": - if fields[idx-1] == "NOT" { - col.Nullable = false - } else { - col.Nullable = true - } - case "DEFAULT": - col.Default = fields[idx+1] - col.DefaultIsEmpty = false - } - } - if !col.SQLType.IsNumeric() && !col.DefaultIsEmpty { - col.Default = "'" + col.Default + "'" + col, err := parseString(colStr) + if err != nil { + return colSeq, cols, err } + cols[col.Name] = col colSeq = append(colSeq, col.Name) } diff --git a/vendor/github.com/go-xorm/xorm/engine.go b/vendor/github.com/go-xorm/xorm/engine.go index 649fd1e306bc0..4ed0f77a9269a 100644 --- a/vendor/github.com/go-xorm/xorm/engine.go +++ b/vendor/github.com/go-xorm/xorm/engine.go @@ -377,6 +377,32 @@ func (engine *Engine) NoAutoCondition(no ...bool) *Session { return session.NoAutoCondition(no...) } +func (engine *Engine) loadTableInfo(table *core.Table) error { + colSeq, cols, err := engine.dialect.GetColumns(table.Name) + if err != nil { + return err + } + for _, name := range colSeq { + table.AddColumn(cols[name]) + } + indexes, err := engine.dialect.GetIndexes(table.Name) + if err != nil { + return err + } + table.Indexes = indexes + + for _, index := range indexes { + for _, name := range index.Cols { + if col := table.GetColumn(name); col != nil { + col.Indexes[index.Name] = index.Type + } else { + return fmt.Errorf("Unknown col %s in index %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq()) + } + } + } + return nil +} + // DBMetas Retrieve all tables, columns, indexes' informations from database. func (engine *Engine) DBMetas() ([]*core.Table, error) { tables, err := engine.dialect.GetTables() @@ -385,28 +411,9 @@ func (engine *Engine) DBMetas() ([]*core.Table, error) { } for _, table := range tables { - colSeq, cols, err := engine.dialect.GetColumns(table.Name) - if err != nil { - return nil, err - } - for _, name := range colSeq { - table.AddColumn(cols[name]) - } - indexes, err := engine.dialect.GetIndexes(table.Name) - if err != nil { + if err = engine.loadTableInfo(table); err != nil { return nil, err } - table.Indexes = indexes - - for _, index := range indexes { - for _, name := range index.Cols { - if col := table.GetColumn(name); col != nil { - col.Indexes[index.Name] = index.Type - } else { - return nil, fmt.Errorf("Unknown col %s in index %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq()) - } - } - } } return tables, nil } @@ -907,8 +914,15 @@ func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) { fieldType := fieldValue.Type() if ormTagStr != "" { - col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false, - IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]int)} + col = &core.Column{ + FieldName: t.Field(i).Name, + Nullable: true, + IsPrimaryKey: false, + IsAutoIncrement: false, + MapType: core.TWOSIDES, + Indexes: make(map[string]int), + DefaultIsEmpty: true, + } tags := splitTag(ormTagStr) if len(tags) > 0 { diff --git a/vendor/github.com/go-xorm/xorm/session_schema.go b/vendor/github.com/go-xorm/xorm/session_schema.go index da5c88559914a..5e576c29aa103 100644 --- a/vendor/github.com/go-xorm/xorm/session_schema.go +++ b/vendor/github.com/go-xorm/xorm/session_schema.go @@ -228,7 +228,7 @@ func (session *Session) Sync2(beans ...interface{}) error { defer session.Close() } - tables, err := engine.DBMetas() + tables, err := engine.dialect.GetTables() if err != nil { return err } @@ -239,26 +239,29 @@ func (session *Session) Sync2(beans ...interface{}) error { session.resetStatement() }() - var structTables []*core.Table - for _, bean := range beans { v := rValue(bean) table, err := engine.mapType(v) if err != nil { return err } - structTables = append(structTables, table) - tbName := engine.TableName(bean) - tbNameWithSchema := engine.TableName(tbName, true) + var tbName string + if len(session.statement.AltTableName) > 0 { + tbName = session.statement.AltTableName + } else { + tbName = engine.TableName(bean) + } + tbNameWithSchema := engine.tbNameWithSchema(tbName) var oriTable *core.Table for _, tb := range tables { - if strings.EqualFold(tb.Name, tbName) { + if strings.EqualFold(engine.tbNameWithSchema(tb.Name), engine.tbNameWithSchema(tbName)) { oriTable = tb break } } + // this is a new table if oriTable == nil { err = session.StoreEngine(session.statement.StoreEngine).createTable(bean) if err != nil { @@ -274,148 +277,154 @@ func (session *Session) Sync2(beans ...interface{}) error { if err != nil { return err } - } else { - for _, col := range table.Columns() { - var oriCol *core.Column - for _, col2 := range oriTable.Columns() { - if strings.EqualFold(col.Name, col2.Name) { - oriCol = col2 - break - } - } + continue + } - if oriCol != nil { - expectedType := engine.dialect.SqlType(col) - curType := engine.dialect.SqlType(oriCol) - if expectedType != curType { - if expectedType == core.Text && - strings.HasPrefix(curType, core.Varchar) { - // currently only support mysql & postgres - if engine.dialect.DBType() == core.MYSQL || - engine.dialect.DBType() == core.POSTGRES { - engine.logger.Infof("Table %s column %s change type from %s to %s\n", - tbNameWithSchema, col.Name, curType, expectedType) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } else { - engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n", - tbNameWithSchema, col.Name, curType, expectedType) - } - } else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) { - if engine.dialect.DBType() == core.MYSQL { - if oriCol.Length < col.Length { - engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", - tbNameWithSchema, col.Name, oriCol.Length, col.Length) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } - } - } else { - if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') { - engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s", - tbNameWithSchema, col.Name, curType, expectedType) - } - } - } else if expectedType == core.Varchar { - if engine.dialect.DBType() == core.MYSQL { - if oriCol.Length < col.Length { - engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", - tbNameWithSchema, col.Name, oriCol.Length, col.Length) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } - } - } - if col.Default != oriCol.Default { - engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s", - tbName, col.Name, oriCol.Default, col.Default) - } - if col.Nullable != oriCol.Nullable { - engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v", - tbName, col.Name, oriCol.Nullable, col.Nullable) - } - } else { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addColumn(col.Name) + // this will modify an old table + if err = engine.loadTableInfo(oriTable); err != nil { + return err + } + + // check columns + for _, col := range table.Columns() { + var oriCol *core.Column + for _, col2 := range oriTable.Columns() { + if strings.EqualFold(col.Name, col2.Name) { + oriCol = col2 + break } - if err != nil { + } + + // column is not exist on table + if oriCol == nil { + session.statement.RefTable = table + session.statement.tableName = tbNameWithSchema + if err = session.addColumn(col.Name); err != nil { return err } + continue } - var foundIndexNames = make(map[string]bool) - var addedNames = make(map[string]*core.Index) - - for name, index := range table.Indexes { - var oriIndex *core.Index - for name2, index2 := range oriTable.Indexes { - if index.Equal(index2) { - oriIndex = index2 - foundIndexNames[name2] = true - break + err = nil + expectedType := engine.dialect.SqlType(col) + curType := engine.dialect.SqlType(oriCol) + if expectedType != curType { + if expectedType == core.Text && + strings.HasPrefix(curType, core.Varchar) { + // currently only support mysql & postgres + if engine.dialect.DBType() == core.MYSQL || + engine.dialect.DBType() == core.POSTGRES { + engine.logger.Infof("Table %s column %s change type from %s to %s\n", + tbNameWithSchema, col.Name, curType, expectedType) + _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) + } else { + engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n", + tbNameWithSchema, col.Name, curType, expectedType) } - } - - if oriIndex != nil { - if oriIndex.Type != index.Type { - sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex) - _, err = session.exec(sql) - if err != nil { - return err + } else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) { + if engine.dialect.DBType() == core.MYSQL { + if oriCol.Length < col.Length { + engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", + tbNameWithSchema, col.Name, oriCol.Length, col.Length) + _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) } - oriIndex = nil + } + } else { + if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') { + engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s", + tbNameWithSchema, col.Name, curType, expectedType) + } + } + } else if expectedType == core.Varchar { + if engine.dialect.DBType() == core.MYSQL { + if oriCol.Length < col.Length { + engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", + tbNameWithSchema, col.Name, oriCol.Length, col.Length) + _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) } } + } - if oriIndex == nil { - addedNames[name] = index + if col.Default != oriCol.Default { + if (col.SQLType.Name == core.Bool || col.SQLType.Name == core.Boolean) && + ((strings.EqualFold(col.Default, "true") && oriCol.Default == "1") || + (strings.EqualFold(col.Default, "false") && oriCol.Default == "0")) { + } else { + engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s", + tbName, col.Name, oriCol.Default, col.Default) } } + if col.Nullable != oriCol.Nullable { + engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v", + tbName, col.Name, oriCol.Nullable, col.Nullable) + } + + if err != nil { + return err + } + } + + var foundIndexNames = make(map[string]bool) + var addedNames = make(map[string]*core.Index) + for name, index := range table.Indexes { + var oriIndex *core.Index for name2, index2 := range oriTable.Indexes { - if _, ok := foundIndexNames[name2]; !ok { - sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2) + if index.Equal(index2) { + oriIndex = index2 + foundIndexNames[name2] = true + break + } + } + + if oriIndex != nil { + if oriIndex.Type != index.Type { + sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex) _, err = session.exec(sql) if err != nil { return err } + oriIndex = nil } } - for name, index := range addedNames { - if index.Type == core.UniqueType { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addUnique(tbNameWithSchema, name) - } else if index.Type == core.IndexType { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addIndex(tbNameWithSchema, name) - } + if oriIndex == nil { + addedNames[name] = index + } + } + + for name2, index2 := range oriTable.Indexes { + if _, ok := foundIndexNames[name2]; !ok { + sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2) + _, err = session.exec(sql) if err != nil { return err } } } - } - for _, table := range tables { - var oriTable *core.Table - for _, structTable := range structTables { - if strings.EqualFold(table.Name, session.tbNameNoSchema(structTable)) { - oriTable = structTable - break + for name, index := range addedNames { + if index.Type == core.UniqueType { + session.statement.RefTable = table + session.statement.tableName = tbNameWithSchema + err = session.addUnique(tbNameWithSchema, name) + } else if index.Type == core.IndexType { + session.statement.RefTable = table + session.statement.tableName = tbNameWithSchema + err = session.addIndex(tbNameWithSchema, name) + } + if err != nil { + return err } } - if oriTable == nil { - //engine.LogWarnf("Table %s has no struct to mapping it", table.Name) - continue - } - - for _, colName := range table.ColumnsSeq() { - if oriTable.GetColumn(colName) == nil { - engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(table.Name, true), colName) + // check all the columns which removed from struct fields but left on database tables. + for _, colName := range oriTable.ColumnsSeq() { + if table.GetColumn(colName) == nil { + engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(oriTable.Name, true), colName) } } } + return nil } diff --git a/vendor/github.com/go-xorm/xorm/statement.go b/vendor/github.com/go-xorm/xorm/statement.go index 3cc0831eec42a..ae396c4bae4dd 100644 --- a/vendor/github.com/go-xorm/xorm/statement.go +++ b/vendor/github.com/go-xorm/xorm/statement.go @@ -266,6 +266,14 @@ func (statement *Statement) buildUpdates(bean interface{}, continue } + if statement.incrColumns.isColExist(col.Name) { + continue + } else if statement.decrColumns.isColExist(col.Name) { + continue + } else if statement.exprColumns.isColExist(col.Name) { + continue + } + fieldValuePtr, err := col.ValueOf(bean) if err != nil { engine.logger.Error(err) diff --git a/vendor/github.com/go-xorm/xorm/tag.go b/vendor/github.com/go-xorm/xorm/tag.go index 6feb581a4685e..ec8d5cf05bf3c 100644 --- a/vendor/github.com/go-xorm/xorm/tag.go +++ b/vendor/github.com/go-xorm/xorm/tag.go @@ -125,6 +125,7 @@ func DefaultTagHandler(ctx *tagContext) error { ctx.col.Default = ctx.nextTag ctx.ignoreNext = true } + ctx.col.DefaultIsEmpty = false return nil } diff --git a/vendor/github.com/go-xorm/xorm/test_mssql.sh b/vendor/github.com/go-xorm/xorm/test_mssql.sh index e26e164118993..7f060cff32cda 100644 --- a/vendor/github.com/go-xorm/xorm/test_mssql.sh +++ b/vendor/github.com/go-xorm/xorm/test_mssql.sh @@ -1 +1 @@ -go test -db=mssql -conn_str="server=localhost;user id=sa;password=MwantsaSecurePassword1;database=xorm_test" \ No newline at end of file +go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" \ No newline at end of file diff --git a/vendor/modules.txt b/vendor/modules.txt index e2cb07eda9cec..e3ad523a5d9c0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -198,7 +198,7 @@ github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd github.com/go-swagger/go-swagger/codescan github.com/go-swagger/go-swagger/generator github.com/go-swagger/go-swagger/scan -# github.com/go-xorm/xorm v0.7.8 +# github.com/go-xorm/xorm v0.7.9 github.com/go-xorm/xorm # github.com/gobwas/glob v0.2.3 github.com/gobwas/glob