Add option to initialize repository with labels (#6061)

* Add optional label sets on repo creation

* Fix CRLF

* Instead of hardcoding default, make it the helper

* Move label set init out of repo init

Add a new error for the router
Combine router label init with repo creation label init

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Add issue labels to Swagger for repo creation

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Update models/issue_label.go

Co-Authored-By: Lauris BH <lauris@nix.lv>

* Update models/issue_label.go

Co-Authored-By: guillep2k <18600385+guillep2k@users.noreply.github.com>
This commit is contained in:
John Olheiser 2019-09-08 03:28:40 -05:00 committed by Lauris BH
parent d4e11ebb18
commit 0118b6aaf8
11 changed files with 87 additions and 16 deletions

View File

@ -1058,6 +1058,22 @@ func (err ErrIssueNotExist) Error() string {
return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index) return fmt.Sprintf("issue does not exist [id: %d, repo_id: %d, index: %d]", err.ID, err.RepoID, err.Index)
} }
// ErrIssueLabelTemplateLoad represents a "ErrIssueLabelTemplateLoad" kind of error.
type ErrIssueLabelTemplateLoad struct {
TemplateFile string
OriginalError error
}
// IsErrIssueLabelTemplateLoad checks if an error is a ErrIssueLabelTemplateLoad.
func IsErrIssueLabelTemplateLoad(err error) bool {
_, ok := err.(ErrIssueLabelTemplateLoad)
return ok
}
func (err ErrIssueLabelTemplateLoad) Error() string {
return fmt.Sprintf("Failed to load label template file '%s': %v", err.TemplateFile, err.OriginalError)
}
// __________ .__ .__ __________ __ // __________ .__ .__ __________ __
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_ // \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\

View File

@ -127,6 +127,34 @@ func (label *Label) ForegroundColor() template.CSS {
return template.CSS("#000") return template.CSS("#000")
} }
func initalizeLabels(e Engine, repoID int64, labelTemplate string) error {
list, err := GetLabelTemplateFile(labelTemplate)
if err != nil {
return ErrIssueLabelTemplateLoad{labelTemplate, err}
}
labels := make([]*Label, len(list))
for i := 0; i < len(list); i++ {
labels[i] = &Label{
RepoID: repoID,
Name: list[i][0],
Description: list[i][2],
Color: list[i][1],
}
}
for _, label := range labels {
if err = newLabel(e, label); err != nil {
return err
}
}
return nil
}
// InitalizeLabels adds a label set to a repository using a template
func InitalizeLabels(repoID int64, labelTemplate string) error {
return initalizeLabels(x, repoID, labelTemplate)
}
func newLabel(e Engine, label *Label) error { func newLabel(e Engine, label *Label) error {
_, err := e.Insert(label) _, err := e.Insert(label)
return err return err

View File

@ -1098,6 +1098,7 @@ type CreateRepoOptions struct {
Description string Description string
OriginalURL string OriginalURL string
Gitignores string Gitignores string
IssueLabels string
License string License string
Readme string Readme string
IsPrivate bool IsPrivate bool
@ -1394,6 +1395,13 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
return nil, fmt.Errorf("initRepository: %v", err) return nil, fmt.Errorf("initRepository: %v", err)
} }
// Initialize Issue Labels if selected
if len(opts.IssueLabels) > 0 {
if err = initalizeLabels(sess, repo.ID, opts.IssueLabels); err != nil {
return nil, fmt.Errorf("initalizeLabels: %v", err)
}
}
_, stderr, err := process.GetManager().ExecDir(-1, _, stderr, err := process.GetManager().ExecDir(-1,
repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath), repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath),
git.GitExecutable, "update-server-info") git.GitExecutable, "update-server-info")

View File

@ -33,6 +33,7 @@ type CreateRepoForm struct {
Description string `binding:"MaxSize(255)"` Description string `binding:"MaxSize(255)"`
AutoInit bool AutoInit bool
Gitignores string Gitignores string
IssueLabels string
License string License string
Readme string Readme string
} }

View File

@ -67,6 +67,8 @@ type CreateRepoOption struct {
Description string `json:"description" binding:"MaxSize(255)"` Description string `json:"description" binding:"MaxSize(255)"`
// Whether the repository is private // Whether the repository is private
Private bool `json:"private"` Private bool `json:"private"`
// Issue Label set to use
IssueLabels string `json:"issue_labels"`
// Whether the repository should be auto-intialized? // Whether the repository should be auto-intialized?
AutoInit bool `json:"auto_init"` AutoInit bool `json:"auto_init"`
// Gitignores to use // Gitignores to use

View File

@ -578,6 +578,8 @@ fork_visibility_helper = The visibility of a forked repository cannot be changed
repo_desc = Description repo_desc = Description
repo_lang = Language repo_lang = Language
repo_gitignore_helper = Select .gitignore templates. repo_gitignore_helper = Select .gitignore templates.
issue_labels = Issue Labels
issue_labels_helper = Select an issue label set.
license = License license = License
license_helper = Select a license file. license_helper = Select a license file.
readme = README readme = README

View File

@ -206,6 +206,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
repo, err := models.CreateRepository(ctx.User, owner, models.CreateRepoOptions{ repo, err := models.CreateRepository(ctx.User, owner, models.CreateRepoOptions{
Name: opt.Name, Name: opt.Name,
Description: opt.Description, Description: opt.Description,
IssueLabels: opt.IssueLabels,
Gitignores: opt.Gitignores, Gitignores: opt.Gitignores,
License: opt.License, License: opt.License,
Readme: opt.Readme, Readme: opt.Readme,

View File

@ -33,24 +33,15 @@ func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
ctx.Redirect(ctx.Repo.RepoLink + "/labels") ctx.Redirect(ctx.Repo.RepoLink + "/labels")
return return
} }
list, err := models.GetLabelTemplateFile(form.TemplateName)
if err != nil {
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, err))
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
return
}
labels := make([]*models.Label, len(list)) if err := models.InitalizeLabels(ctx.Repo.Repository.ID, form.TemplateName); err != nil {
for i := 0; i < len(list); i++ { if models.IsErrIssueLabelTemplateLoad(err) {
labels[i] = &models.Label{ originalErr := err.(models.ErrIssueLabelTemplateLoad).OriginalError
RepoID: ctx.Repo.Repository.ID, ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr))
Name: list[i][0], ctx.Redirect(ctx.Repo.RepoLink + "/labels")
Description: list[i][2], return
Color: list[i][1],
} }
} ctx.ServerError("InitalizeLabels", err)
if err := models.NewLabels(labels...); err != nil {
ctx.ServerError("NewLabels", err)
return return
} }
ctx.Redirect(ctx.Repo.RepoLink + "/labels") ctx.Redirect(ctx.Repo.RepoLink + "/labels")

View File

@ -115,6 +115,7 @@ func Create(ctx *context.Context) {
// Give default value for template to render. // Give default value for template to render.
ctx.Data["Gitignores"] = models.Gitignores ctx.Data["Gitignores"] = models.Gitignores
ctx.Data["LabelTemplates"] = models.LabelTemplates
ctx.Data["Licenses"] = models.Licenses ctx.Data["Licenses"] = models.Licenses
ctx.Data["Readmes"] = models.Readmes ctx.Data["Readmes"] = models.Readmes
ctx.Data["readme"] = "Default" ctx.Data["readme"] = "Default"
@ -155,6 +156,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
ctx.Data["Title"] = ctx.Tr("new_repo") ctx.Data["Title"] = ctx.Tr("new_repo")
ctx.Data["Gitignores"] = models.Gitignores ctx.Data["Gitignores"] = models.Gitignores
ctx.Data["LabelTemplates"] = models.LabelTemplates
ctx.Data["Licenses"] = models.Licenses ctx.Data["Licenses"] = models.Licenses
ctx.Data["Readmes"] = models.Readmes ctx.Data["Readmes"] = models.Readmes
@ -173,6 +175,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
Name: form.RepoName, Name: form.RepoName,
Description: form.Description, Description: form.Description,
Gitignores: form.Gitignores, Gitignores: form.Gitignores,
IssueLabels: form.IssueLabels,
License: form.License, License: form.License,
Readme: form.Readme, Readme: form.Readme,
IsPrivate: form.Private || setting.Repository.ForcePrivate, IsPrivate: form.Private || setting.Repository.ForcePrivate,

View File

@ -56,6 +56,20 @@
<textarea id="description" name="description">{{.description}}</textarea> <textarea id="description" name="description">{{.description}}</textarea>
</div> </div>
<div class="inline field">
<label>{{.i18n.Tr "repo.issue_labels"}}</label>
<div class="ui search normal selection dropdown">
<input type="hidden" name="issue_labels" value="{{.issueLabels}}">
<div class="default text">{{.i18n.Tr "repo.issue_labels_helper"}}</div>
<div class="menu">
<div class="item" data-value="">{{.i18n.Tr "repo.issue_labels_helper"}}</div>
{{range .LabelTemplates}}
<div class="item" data-value="{{.}}">{{.}}</div>
{{end}}
</div>
</div>
</div>
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="inline field"> <div class="inline field">

View File

@ -7843,6 +7843,11 @@
"type": "string", "type": "string",
"x-go-name": "Gitignores" "x-go-name": "Gitignores"
}, },
"issue_labels": {
"description": "Issue Label set to use",
"type": "string",
"x-go-name": "IssueLabels"
},
"license": { "license": {
"description": "License to use", "description": "License to use",
"type": "string", "type": "string",