Add avatar and issue labels to template repositories (#9149)
* Add avatar and issue labels Signed-off-by: jolheiser <john.olheiser@gmail.com> * Fix redundant if-err Signed-off-by: jolheiser <john.olheiser@gmail.com>
This commit is contained in:
parent
95c3dc856a
commit
62bcb2b7f1
8 changed files with 95 additions and 22 deletions
|
@ -279,10 +279,9 @@ func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) {
|
||||||
Find(&labels)
|
Find(&labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLabelsByRepoID returns all labels that belong to given repository by ID.
|
func getLabelsByRepoID(e Engine, repoID int64, sortType string) ([]*Label, error) {
|
||||||
func GetLabelsByRepoID(repoID int64, sortType string) ([]*Label, error) {
|
|
||||||
labels := make([]*Label, 0, 10)
|
labels := make([]*Label, 0, 10)
|
||||||
sess := x.Where("repo_id = ?", repoID)
|
sess := e.Where("repo_id = ?", repoID)
|
||||||
|
|
||||||
switch sortType {
|
switch sortType {
|
||||||
case "reversealphabetically":
|
case "reversealphabetically":
|
||||||
|
@ -298,6 +297,11 @@ func GetLabelsByRepoID(repoID int64, sortType string) ([]*Label, error) {
|
||||||
return labels, sess.Find(&labels)
|
return labels, sess.Find(&labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLabelsByRepoID returns all labels that belong to given repository by ID.
|
||||||
|
func GetLabelsByRepoID(repoID int64, sortType string) ([]*Label, error) {
|
||||||
|
return getLabelsByRepoID(x, repoID, sortType)
|
||||||
|
}
|
||||||
|
|
||||||
func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
|
func getLabelsByIssueID(e Engine, issueID int64) ([]*Label, error) {
|
||||||
var labels []*Label
|
var labels []*Label
|
||||||
return labels, e.Where("issue_label.issue_id = ?", issueID).
|
return labels, e.Where("issue_label.issue_id = ?", issueID).
|
||||||
|
|
|
@ -1257,22 +1257,6 @@ type CreateRepoOptions struct {
|
||||||
Status RepositoryStatus
|
Status RepositoryStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateRepoOptions contains the template units to generate
|
|
||||||
type GenerateRepoOptions struct {
|
|
||||||
Name string
|
|
||||||
Description string
|
|
||||||
Private bool
|
|
||||||
GitContent bool
|
|
||||||
Topics bool
|
|
||||||
GitHooks bool
|
|
||||||
Webhooks bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValid checks whether at least one option is chosen for generation
|
|
||||||
func (gro GenerateRepoOptions) IsValid() bool {
|
|
||||||
return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks // or other items as they are added
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRepoInitFile(tp, name string) ([]byte, error) {
|
func getRepoInitFile(tp, name string) ([]byte, error) {
|
||||||
cleanedName := strings.TrimLeft(path.Clean("/"+name), "/")
|
cleanedName := strings.TrimLeft(path.Clean("/"+name), "/")
|
||||||
relPath := path.Join("options", tp, cleanedName)
|
relPath := path.Join("options", tp, cleanedName)
|
||||||
|
@ -2957,8 +2941,12 @@ func (repo *Repository) GetTreePathLock(treePath string) (*LFSLock, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRepositoryCols updates repository's columns
|
func updateRepositoryCols(e Engine, repo *Repository, cols ...string) error {
|
||||||
func UpdateRepositoryCols(repo *Repository, cols ...string) error {
|
_, err := e.ID(repo.ID).Cols(cols...).Update(repo)
|
||||||
_, err := x.ID(repo.ID).Cols(cols...).Update(repo)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateRepositoryCols updates repository's columns
|
||||||
|
func UpdateRepositoryCols(repo *Repository, cols ...string) error {
|
||||||
|
return updateRepositoryCols(x, repo, cols...)
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -17,6 +18,24 @@ import (
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GenerateRepoOptions contains the template units to generate
|
||||||
|
type GenerateRepoOptions struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
Private bool
|
||||||
|
GitContent bool
|
||||||
|
Topics bool
|
||||||
|
GitHooks bool
|
||||||
|
Webhooks bool
|
||||||
|
Avatar bool
|
||||||
|
IssueLabels bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid checks whether at least one option is chosen for generation
|
||||||
|
func (gro GenerateRepoOptions) IsValid() bool {
|
||||||
|
return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks || gro.Avatar || gro.IssueLabels // or other items as they are added
|
||||||
|
}
|
||||||
|
|
||||||
// generateRepository initializes repository from template
|
// generateRepository initializes repository from template
|
||||||
func generateRepository(e Engine, repo, templateRepo *Repository) (err error) {
|
func generateRepository(e Engine, repo, templateRepo *Repository) (err error) {
|
||||||
tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
|
tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
|
||||||
|
@ -160,3 +179,34 @@ func GenerateWebhooks(ctx DBContext, templateRepo, generateRepo *Repository) err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateAvatar generates the avatar from a template repository
|
||||||
|
func GenerateAvatar(ctx DBContext, templateRepo, generateRepo *Repository) error {
|
||||||
|
generateRepo.Avatar = strings.Replace(templateRepo.Avatar, strconv.FormatInt(templateRepo.ID, 10), strconv.FormatInt(generateRepo.ID, 10), 1)
|
||||||
|
if err := com.Copy(templateRepo.CustomAvatarPath(), generateRepo.CustomAvatarPath()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateRepositoryCols(ctx.e, generateRepo, "avatar")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateIssueLabels generates issue labels from a template repository
|
||||||
|
func GenerateIssueLabels(ctx DBContext, templateRepo, generateRepo *Repository) error {
|
||||||
|
templateLabels, err := getLabelsByRepoID(ctx.e, templateRepo.ID, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, templateLabel := range templateLabels {
|
||||||
|
generateLabel := &Label{
|
||||||
|
RepoID: generateRepo.ID,
|
||||||
|
Name: templateLabel.Name,
|
||||||
|
Description: templateLabel.Description,
|
||||||
|
Color: templateLabel.Color,
|
||||||
|
}
|
||||||
|
if err := newLabel(ctx.e, generateLabel); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ type CreateRepoForm struct {
|
||||||
Topics bool
|
Topics bool
|
||||||
GitHooks bool
|
GitHooks bool
|
||||||
Webhooks bool
|
Webhooks bool
|
||||||
|
Avatar bool
|
||||||
|
Labels bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
|
|
@ -641,6 +641,8 @@ template.git_hooks = Git Hooks
|
||||||
template.git_hooks_tooltip = You are currently unable to modify or remove git hooks once added. Select this only if you trust the template repository.
|
template.git_hooks_tooltip = You are currently unable to modify or remove git hooks once added. Select this only if you trust the template repository.
|
||||||
template.webhooks = Webhooks
|
template.webhooks = Webhooks
|
||||||
template.topics = Topics
|
template.topics = Topics
|
||||||
|
template.avatar = Avatar
|
||||||
|
template.issue_labels = Issue Labels
|
||||||
template.one_item = Must select at least one template item
|
template.one_item = Must select at least one template item
|
||||||
template.invalid = Must select a template repository
|
template.invalid = Must select a template repository
|
||||||
|
|
||||||
|
|
|
@ -190,6 +190,8 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
|
||||||
Topics: form.Topics,
|
Topics: form.Topics,
|
||||||
GitHooks: form.GitHooks,
|
GitHooks: form.GitHooks,
|
||||||
Webhooks: form.Webhooks,
|
Webhooks: form.Webhooks,
|
||||||
|
Avatar: form.Avatar,
|
||||||
|
IssueLabels: form.Labels,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !opts.IsValid() {
|
if !opts.IsValid() {
|
||||||
|
|
|
@ -47,6 +47,20 @@ func GenerateRepository(doer, owner *models.User, templateRepo *models.Repositor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avatar
|
||||||
|
if opts.Avatar && len(templateRepo.Avatar) > 0 {
|
||||||
|
if err = models.GenerateAvatar(ctx, templateRepo, generateRepo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue Labels
|
||||||
|
if opts.IssueLabels {
|
||||||
|
if err = models.GenerateIssueLabels(ctx, templateRepo, generateRepo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
if generateRepo != nil {
|
if generateRepo != nil {
|
||||||
|
|
|
@ -88,6 +88,17 @@
|
||||||
<label>{{.i18n.Tr "repo.template.topics"}}</label>
|
<label>{{.i18n.Tr "repo.template.topics"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="inline field">
|
||||||
|
<label></label>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input class="hidden" name="avatar" type="checkbox" tabindex="0" {{if .avatar}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.template.avatar"}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input class="hidden" name="labels" type="checkbox" tabindex="0" {{if .labels}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.template.issue_labels"}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="non_template">
|
<div id="non_template">
|
||||||
|
|
Reference in a new issue