Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add git hooks and webhooks to template repositories; move to services #8926

Merged
merged 29 commits into from
Nov 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
eaa6954
Add git hooks and webhooks to template options
jolheiser Nov 11, 2019
fde853d
Merge branch 'master' into template_hook
jolheiser Nov 12, 2019
f350f49
Update models/repo.go
jolheiser Nov 12, 2019
8da72e1
Add tooltip if the user can't edit git hooks
jolheiser Nov 12, 2019
412a262
Merge branch 'master' into template_hook
jolheiser Nov 12, 2019
2cdb438
Merge branch 'master' into template_hook
jolheiser Nov 13, 2019
eb0cde6
Merge branch 'master' into template_hook
jolheiser Nov 13, 2019
429ebd5
Merge branch 'master' into template_hook
jolheiser Nov 13, 2019
bbc3647
Close repositories after copying git hooks
jolheiser Nov 13, 2019
aca0b6d
Merge branch 'master' into template_hook
jolheiser Nov 13, 2019
fccc473
Wording
jolheiser Nov 13, 2019
0832184
Merge branch 'master' into template_hook
jolheiser Nov 15, 2019
1b9df8e
Merge branch 'master' into template_hook
lunny Nov 16, 2019
a375ce2
Merge branch 'master' into template_hook
jolheiser Nov 18, 2019
1127c15
Merge branch 'master' into template_hook
jolheiser Nov 19, 2019
8f62ef4
Merge branch 'master' into template_hook
jolheiser Nov 20, 2019
6c1f0b7
Merge branch 'master' into template_hook
jolheiser Nov 21, 2019
d5f2247
Restructure for services
jolheiser Nov 22, 2019
8bbccaa
Return errors
jolheiser Nov 22, 2019
faca8ae
Move GenerateRepository to using a DBContext
jolheiser Nov 22, 2019
ecc4559
Wrap with models.WithTx
jolheiser Nov 23, 2019
cc6646e
Remove debug print
jolheiser Nov 23, 2019
ddf89bd
Merge branch 'master' into template_hook
jolheiser Nov 23, 2019
48f10a6
Move if-error-delete-repo outside WithTx
jolheiser Nov 23, 2019
4e6b1ef
Merge branch 'template_hook' of github.com:jolheiser/gitea into templ…
jolheiser Nov 23, 2019
2b4d4fd
Return nil if no repo generated
jolheiser Nov 23, 2019
d87f4f6
Merge branch 'master' into template_hook
jolheiser Nov 24, 2019
55e75bd
Merge branch 'master' into template_hook
lunny Nov 24, 2019
e691245
Merge branch 'master' into template_hook
techknowlogick Nov 24, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 4 additions & 100 deletions models/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import (
"github.com/unknwon/com"
ini "gopkg.in/ini.v1"
"xorm.io/builder"
"xorm.io/xorm"
)

var repoWorkingPool = sync.NewExclusivePool()
Expand Down Expand Up @@ -1265,11 +1264,13 @@ type GenerateRepoOptions struct {
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 // or other items as they are added
return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks // or other items as they are added
}

func getRepoInitFile(tp, name string) ([]byte, error) {
Expand Down Expand Up @@ -1483,37 +1484,6 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C
return nil
}

// generateRepository initializes repository from template
func generateRepository(e Engine, repo, templateRepo *Repository) (err error) {
tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))

if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
return fmt.Errorf("Failed to create dir %s: %v", tmpDir, err)
}

defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
log.Error("RemoveAll: %v", err)
}
}()

if err = generateRepoCommit(e, repo, templateRepo, tmpDir); err != nil {
return fmt.Errorf("generateRepoCommit: %v", err)
}

// re-fetch repo
if repo, err = getRepositoryByID(e, repo.ID); err != nil {
return fmt.Errorf("getRepositoryByID: %v", err)
}

repo.DefaultBranch = "master"
if err = updateRepository(e, repo, false); err != nil {
return fmt.Errorf("updateRepository: %v", err)
}

return nil
}

var (
reservedRepoNames = []string{".", ".."}
reservedRepoPatterns = []string{"*.git", "*.wiki"}
Expand All @@ -1524,7 +1494,7 @@ func IsUsableRepoName(name string) error {
return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
}

func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err error) {
func createRepository(e Engine, doer, u *User, repo *Repository) (err error) {
if err = IsUsableRepoName(repo.Name); err != nil {
return err
}
Expand Down Expand Up @@ -2771,72 +2741,6 @@ func ForkRepository(doer, owner *User, oldRepo *Repository, name, desc string) (
return repo, CopyLFS(repo, oldRepo)
}

// GenerateRepository generates a repository from a template
func GenerateRepository(doer, owner *User, templateRepo *Repository, opts GenerateRepoOptions) (_ *Repository, err error) {
repo := &Repository{
OwnerID: owner.ID,
Owner: owner,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
Description: opts.Description,
IsPrivate: opts.Private,
IsEmpty: !opts.GitContent || templateRepo.IsEmpty,
IsFsckEnabled: templateRepo.IsFsckEnabled,
TemplateID: templateRepo.ID,
}

createSess := x.NewSession()
defer createSess.Close()
if err = createSess.Begin(); err != nil {
return nil, err
}

if err = createRepository(createSess, doer, owner, repo); err != nil {
return nil, err
}

//Commit repo to get created repo ID
err = createSess.Commit()
if err != nil {
return nil, err
}

sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return repo, err
}

repoPath := RepoPath(owner.Name, repo.Name)
if err = checkInitRepository(repoPath); err != nil {
return repo, err
}

if opts.GitContent && !templateRepo.IsEmpty {
if err = generateRepository(sess, repo, templateRepo); err != nil {
return repo, err
}

if err = repo.updateSize(sess); err != nil {
return repo, fmt.Errorf("failed to update size for repository: %v", err)
}

if err = copyLFS(sess, repo, templateRepo); err != nil {
return repo, fmt.Errorf("failed to copy LFS: %v", err)
}
}

if opts.Topics {
for _, topic := range templateRepo.Topics {
if _, err = addTopicByNameToRepo(sess, repo.ID, topic); err != nil {
return repo, err
}
}
}

return repo, sess.Commit()
}

// GetForks returns all the forks of the repository
func (repo *Repository) GetForks() ([]*Repository, error) {
forks := make([]*Repository, 0, repo.NumForks)
Expand Down
162 changes: 162 additions & 0 deletions models/repo_generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"

"github.com/unknwon/com"
)

// generateRepository initializes repository from template
func generateRepository(e Engine, repo, templateRepo *Repository) (err error) {
tmpDir := filepath.Join(os.TempDir(), "gitea-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))

if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
return fmt.Errorf("Failed to create dir %s: %v", tmpDir, err)
}

defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
log.Error("RemoveAll: %v", err)
}
}()

if err = generateRepoCommit(e, repo, templateRepo, tmpDir); err != nil {
return fmt.Errorf("generateRepoCommit: %v", err)
}

// re-fetch repo
if repo, err = getRepositoryByID(e, repo.ID); err != nil {
return fmt.Errorf("getRepositoryByID: %v", err)
}

repo.DefaultBranch = "master"
if err = updateRepository(e, repo, false); err != nil {
return fmt.Errorf("updateRepository: %v", err)
}

return nil
}

// GenerateRepository generates a repository from a template
func GenerateRepository(ctx DBContext, doer, owner *User, templateRepo *Repository, opts GenerateRepoOptions) (_ *Repository, err error) {
generateRepo := &Repository{
OwnerID: owner.ID,
Owner: owner,
Name: opts.Name,
LowerName: strings.ToLower(opts.Name),
Description: opts.Description,
IsPrivate: opts.Private,
IsEmpty: !opts.GitContent || templateRepo.IsEmpty,
IsFsckEnabled: templateRepo.IsFsckEnabled,
TemplateID: templateRepo.ID,
}

if err = createRepository(ctx.e, doer, owner, generateRepo); err != nil {
return nil, err
}

repoPath := RepoPath(owner.Name, generateRepo.Name)
if err = checkInitRepository(repoPath); err != nil {
return generateRepo, err
}

return generateRepo, nil
}

// GenerateGitContent generates git content from a template repository
func GenerateGitContent(ctx DBContext, templateRepo, generateRepo *Repository) error {
if err := generateRepository(ctx.e, generateRepo, templateRepo); err != nil {
return err
}

if err := generateRepo.updateSize(ctx.e); err != nil {
return fmt.Errorf("failed to update size for repository: %v", err)
}

if err := copyLFS(ctx.e, generateRepo, templateRepo); err != nil {
return fmt.Errorf("failed to copy LFS: %v", err)
}
return nil
}

// GenerateTopics generates topics from a template repository
func GenerateTopics(ctx DBContext, templateRepo, generateRepo *Repository) error {
for _, topic := range templateRepo.Topics {
if _, err := addTopicByNameToRepo(ctx.e, generateRepo.ID, topic); err != nil {
return err
}
}
return nil
}

// GenerateGitHooks generates git hooks from a template repository
func GenerateGitHooks(ctx DBContext, templateRepo, generateRepo *Repository) error {
generateGitRepo, err := git.OpenRepository(generateRepo.repoPath(ctx.e))
if err != nil {
return err
}
defer generateGitRepo.Close()

templateGitRepo, err := git.OpenRepository(templateRepo.repoPath(ctx.e))
if err != nil {
return err
}
defer templateGitRepo.Close()

templateHooks, err := templateGitRepo.Hooks()
if err != nil {
return err
}

for _, templateHook := range templateHooks {
generateHook, err := generateGitRepo.GetHook(templateHook.Name())
if err != nil {
return err
}

generateHook.Content = templateHook.Content
if err := generateHook.Update(); err != nil {
return err
}
}
return nil
}

// GenerateWebhooks generates webhooks from a template repository
func GenerateWebhooks(ctx DBContext, templateRepo, generateRepo *Repository) error {
templateWebhooks, err := GetWebhooksByRepoID(templateRepo.ID)
if err != nil {
return err
}

for _, templateWebhook := range templateWebhooks {
generateWebhook := &Webhook{
RepoID: generateRepo.ID,
URL: templateWebhook.URL,
HTTPMethod: templateWebhook.HTTPMethod,
ContentType: templateWebhook.ContentType,
Secret: templateWebhook.Secret,
HookEvent: templateWebhook.HookEvent,
IsActive: templateWebhook.IsActive,
HookTaskType: templateWebhook.HookTaskType,
OrgID: templateWebhook.OrgID,
Events: templateWebhook.Events,
Meta: templateWebhook.Meta,
}
if err := createWebhook(ctx.e, generateWebhook); err != nil {
return err
}
}
return nil
}
2 changes: 2 additions & 0 deletions modules/auth/repo_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type CreateRepoForm struct {
RepoTemplate int64
GitContent bool
Topics bool
GitHooks bool
Webhooks bool
}

// Validate validates the fields
Expand Down
3 changes: 3 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,9 @@ reactions_more = and %d more

template.items = Template Items
template.git_content = Git Content (Default Branch)
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.webhooks = Webhooks
template.topics = Topics
template.one_item = Must select at least one template item
template.invalid = Must select a template repository
Expand Down
2 changes: 2 additions & 0 deletions routers/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
Private: form.Private,
GitContent: form.GitContent,
Topics: form.Topics,
GitHooks: form.GitHooks,
Webhooks: form.Webhooks,
}

if !opts.IsValid() {
Expand Down
63 changes: 63 additions & 0 deletions services/repository/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package repository

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
)

// GenerateRepository generates a repository from a template
func GenerateRepository(doer, owner *models.User, templateRepo *models.Repository, opts models.GenerateRepoOptions) (_ *models.Repository, err error) {
var generateRepo *models.Repository
if err = models.WithTx(func(ctx models.DBContext) error {
generateRepo, err = models.GenerateRepository(ctx, doer, owner, templateRepo, opts)
if err != nil {
return err
}

// Git Content
if opts.GitContent && !templateRepo.IsEmpty {
if err = models.GenerateGitContent(ctx, templateRepo, generateRepo); err != nil {
return err
}
}

// Topics
if opts.Topics {
if err = models.GenerateTopics(ctx, templateRepo, generateRepo); err != nil {
return err
}
}

// Git Hooks
if opts.GitHooks {
if err = models.GenerateGitHooks(ctx, templateRepo, generateRepo); err != nil {
return err
}
}

// Webhooks
if opts.Webhooks {
if err = models.GenerateWebhooks(ctx, templateRepo, generateRepo); err != nil {
return err
}
}

return nil
}); err != nil {
if generateRepo != nil {
if errDelete := models.DeleteRepository(doer, owner.ID, generateRepo.ID); errDelete != nil {
log.Error("Rollback deleteRepository: %v", errDelete)
}
}
return nil, err
}

notification.NotifyCreateRepository(doer, owner, generateRepo)

return generateRepo, nil
}
Loading