mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08: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:
		@@ -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",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user