mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-29 13:16:10 +01:00
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:
parent
d4e11ebb18
commit
0118b6aaf8
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
// __________ .__ .__ __________ __
|
// __________ .__ .__ __________ __
|
||||||
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
|
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
|
||||||
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
|
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
if err := models.InitalizeLabels(ctx.Repo.Repository.ID, form.TemplateName); err != nil {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, err))
|
if models.IsErrIssueLabelTemplateLoad(err) {
|
||||||
|
originalErr := err.(models.ErrIssueLabelTemplateLoad).OriginalError
|
||||||
|
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ctx.ServerError("InitalizeLabels", err)
|
||||||
labels := make([]*models.Label, len(list))
|
|
||||||
for i := 0; i < len(list); i++ {
|
|
||||||
labels[i] = &models.Label{
|
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
|
||||||
Name: list[i][0],
|
|
||||||
Description: list[i][2],
|
|
||||||
Color: list[i][1],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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")
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue