Example #1
0
// runSync returns true if sync finished without error.
func (m *Mirror) runSync() bool {
	repoPath := m.Repo.RepoPath()
	wikiPath := m.Repo.WikiPath()
	timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second

	gitArgs := []string{"remote", "update"}
	if m.EnablePrune {
		gitArgs = append(gitArgs, "--prune")
	}

	if _, stderr, err := process.ExecDir(
		timeout, repoPath, fmt.Sprintf("Mirror.runSync: %s", repoPath),
		"git", gitArgs...); err != nil {
		desc := fmt.Sprintf("Fail to update mirror repository '%s': %s", repoPath, stderr)
		log.Error(4, desc)
		if err = CreateRepositoryNotice(desc); err != nil {
			log.Error(4, "CreateRepositoryNotice: %v", err)
		}
		return false
	}
	if m.Repo.HasWiki() {
		if _, stderr, err := process.ExecDir(
			timeout, wikiPath, fmt.Sprintf("Mirror.runSync: %s", wikiPath),
			"git", "remote", "update", "--prune"); err != nil {
			desc := fmt.Sprintf("Fail to update mirror wiki repository '%s': %s", wikiPath, stderr)
			log.Error(4, desc)
			if err = CreateRepositoryNotice(desc); err != nil {
				log.Error(4, "CreateRepositoryNotice: %v", err)
			}
			return false
		}
	}

	return true
}
Example #2
0
// MigrateRepository migrates a existing repository from other project hosting.
func MigrateRepository(u *User, name, desc string, private, mirror bool, url string) (*Repository, error) {
	repo, err := CreateRepository(u, name, desc, "", "", private, mirror, false)
	if err != nil {
		return nil, err
	}

	// Clone to temprory path and do the init commit.
	tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()))
	os.MkdirAll(tmpDir, os.ModePerm)

	repoPath := RepoPath(u.Name, name)

	if u.IsOrganization() {
		t, err := u.GetOwnerTeam()
		if err != nil {
			return nil, err
		}
		repo.NumWatches = t.NumMembers
	} else {
		repo.NumWatches = 1
	}

	repo.IsBare = false
	if mirror {
		if err = MirrorRepository(repo.Id, u.Name, repo.Name, repoPath, url); err != nil {
			return repo, err
		}
		repo.IsMirror = true
		return repo, UpdateRepository(repo)
	}

	// Clone from local repository.
	_, stderr, err := process.ExecTimeout(10*time.Minute,
		fmt.Sprintf("MigrateRepository(git clone): %s", repoPath),
		"git", "clone", repoPath, tmpDir)
	if err != nil {
		return repo, errors.New("git clone: " + stderr)
	}

	// Add remote and fetch data.
	if _, stderr, err = process.ExecDir(3*time.Minute,
		tmpDir, fmt.Sprintf("MigrateRepository(git pull): %s", repoPath),
		"git", "remote", "add", "-f", "--tags", "upstream", url); err != nil {
		return repo, errors.New("git remote: " + stderr)
	}

	// Push data to local repository.
	if _, stderr, err = process.ExecDir(3*time.Minute,
		tmpDir, fmt.Sprintf("MigrateRepository(git push): %s", repoPath),
		"git", "push", "--tags", "origin", "refs/remotes/upstream/*:refs/heads/*"); err != nil {
		return repo, errors.New("git push: " + stderr)
	}

	return repo, UpdateRepository(repo)
}
Example #3
0
File: pull.go Project: yweber/gogs
// testPatch checks if patch can be merged to base repository without conflit.
// FIXME: make a mechanism to clean up stable local copies.
func (pr *PullRequest) testPatch() (err error) {
	if pr.BaseRepo == nil {
		pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
		if err != nil {
			return fmt.Errorf("GetRepositoryByID: %v", err)
		}
	}

	patchPath, err := pr.BaseRepo.PatchPath(pr.Index)
	if err != nil {
		return fmt.Errorf("BaseRepo.PatchPath: %v", err)
	}

	// Fast fail if patch does not exist, this assumes data is cruppted.
	if !com.IsFile(patchPath) {
		log.Trace("PullRequest[%d].testPatch: ignored cruppted data", pr.ID)
		return nil
	}

	log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)

	if err := pr.BaseRepo.UpdateLocalCopy(); err != nil {
		return fmt.Errorf("UpdateLocalCopy: %v", err)
	}

	// Checkout base branch.
	_, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
		fmt.Sprintf("PullRequest.Merge (git checkout): %v", pr.BaseRepo.ID),
		"git", "checkout", pr.BaseBranch)
	if err != nil {
		return fmt.Errorf("git checkout: %s", stderr)
	}

	pr.Status = PULL_REQUEST_STATUS_CHECKING
	_, stderr, err = process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(),
		fmt.Sprintf("testPatch (git apply --check): %d", pr.BaseRepo.ID),
		"git", "apply", "--check", patchPath)
	if err != nil {
		for i := range patchConflicts {
			if strings.Contains(stderr, patchConflicts[i]) {
				log.Trace("PullRequest[%d].testPatch (apply): has conflit", pr.ID)
				fmt.Println(stderr)
				pr.Status = PULL_REQUEST_STATUS_CONFLICT
				return nil
			}
		}

		return fmt.Errorf("git apply --check: %v - %s", err, stderr)
	}
	return nil
}
Example #4
0
// MigrateRepository migrates a existing repository from other project hosting.
func MigrateRepository(u *User, name, desc string, private, mirror bool, url string) (*Repository, error) {
	repo, err := CreateRepository(u, name, desc, "", "", private, mirror, false)
	if err != nil {
		return nil, err
	}

	// Clone to temprory path and do the init commit.
	tmpDir := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()))
	os.MkdirAll(tmpDir, os.ModePerm)

	repoPath := RepoPath(u.Name, name)

	repo.IsBare = false
	if mirror {
		if err = MirrorRepository(repo.Id, u.Name, repo.Name, repoPath, url); err != nil {
			return repo, err
		}
		repo.IsMirror = true
		return repo, UpdateRepository(repo)
	}

	// TODO: need timeout.
	// Clone from local repository.
	_, stderr, err := process.Exec(
		fmt.Sprintf("MigrateRepository(git clone): %s", repoPath),
		"git", "clone", repoPath, tmpDir)
	if err != nil {
		return repo, errors.New("git clone: " + stderr)
	}

	// TODO: need timeout.
	// Pull data from source.
	if _, stderr, err = process.ExecDir(
		tmpDir, fmt.Sprintf("MigrateRepository(git pull): %s", repoPath),
		"git", "pull", url); err != nil {
		return repo, errors.New("git pull: " + stderr)
	}

	// TODO: need timeout.
	// Push data to local repository.
	if _, stderr, err = process.ExecDir(
		tmpDir, fmt.Sprintf("MigrateRepository(git push): %s", repoPath),
		"git", "push", "origin", "master"); err != nil {
		return repo, errors.New("git push: " + stderr)
	}

	return repo, UpdateRepository(repo)
}
Example #5
0
// GitFsck calls 'git fsck' to check repository health.
func GitFsck() {
	if isGitFscking {
		return
	}
	isGitFscking = true
	defer func() { isGitFscking = false }()

	args := append([]string{"fsck"}, setting.Git.Fsck.Args...)
	if err := x.Where("id > 0").Iterate(new(Repository),
		func(idx int, bean interface{}) error {
			repo := bean.(*Repository)
			if err := repo.GetOwner(); err != nil {
				return err
			}

			repoPath := RepoPath(repo.Owner.Name, repo.Name)
			_, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
			if err != nil {
				desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath)
				log.Warn(desc)
				if err = CreateRepositoryNotice(desc); err != nil {
					log.Error(4, "Fail to add notice: %v", err)
				}
			}
			return nil
		}); err != nil {
		log.Error(4, "repo.Fsck: %v", err)
	}
}
Example #6
0
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
	repo := &Repository{
		OwnerID:       u.Id,
		Owner:         u,
		Name:          name,
		LowerName:     strings.ToLower(name),
		Description:   desc,
		DefaultBranch: oldRepo.DefaultBranch,
		IsPrivate:     oldRepo.IsPrivate,
		IsFork:        true,
		ForkID:        oldRepo.ID,
	}

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

	if err = createRepository(sess, u, repo); err != nil {
		return nil, err
	}

	if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.ID); err != nil {
		return nil, err
	}
	// else if _, err = sess.Insert(&ForkInfo{
	// 	ForkID:        oldRepo.ID,
	// 	RepoID:        repo.ID,
	// 	StartCommitID: "",
	// }); err != nil {
	// 	return nil, fmt.Errorf("insert fork info: %v", err)
	// }

	oldRepoPath, err := oldRepo.RepoPath()
	if err != nil {
		return nil, fmt.Errorf("get old repository path: %v", err)
	}

	repoPath := RepoPath(u.Name, repo.Name)
	_, stderr, err := process.ExecTimeout(10*time.Minute,
		fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
		"git", "clone", "--bare", oldRepoPath, repoPath)
	if err != nil {
		return nil, fmt.Errorf("git clone: %v", stderr)
	}

	_, stderr, err = process.ExecDir(-1,
		repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath),
		"git", "update-server-info")
	if err != nil {
		return nil, fmt.Errorf("git update-server-info: %v", err)
	}

	if err = createUpdateHook(repoPath); err != nil {
		return nil, fmt.Errorf("createUpdateHook: %v", err)
	}

	return repo, sess.Commit()
}
Example #7
0
// GitFsck calls 'git fsck' to check repository health.
func GitFsck() {
	if isGitFscking {
		return
	}
	isGitFscking = true
	defer func() { isGitFscking = false }()

	log.Trace("Doing: GitFsck")

	args := append([]string{"fsck"}, setting.Cron.RepoHealthCheck.Args...)
	if err := x.Where("id>0").Iterate(new(Repository),
		func(idx int, bean interface{}) error {
			repo := bean.(*Repository)
			repoPath, err := repo.RepoPath()
			if err != nil {
				return fmt.Errorf("RepoPath: %v", err)
			}

			_, _, err = process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
			if err != nil {
				desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath)
				log.Warn(desc)
				if err = CreateRepositoryNotice(desc); err != nil {
					log.Error(4, "CreateRepositoryNotice: %v", err)
				}
			}
			return nil
		}); err != nil {
		log.Error(4, "GitFsck: %v", err)
	}
}
Example #8
0
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
func DeleteReleaseByID(id int64) error {
	rel, err := GetReleaseByID(id)
	if err != nil {
		return fmt.Errorf("GetReleaseByID: %v", err)
	}

	repo, err := GetRepositoryByID(rel.RepoID)
	if err != nil {
		return fmt.Errorf("GetRepositoryByID: %v", err)
	}

	repoPath, err := repo.RepoPath()
	if err != nil {
		return fmt.Errorf("RepoPath: %v", err)
	}

	_, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
		"git", "tag", "-d", rel.TagName)
	if err != nil && !strings.Contains(stderr, "not found") {
		return fmt.Errorf("git tag -d: %v - %s", err, stderr)
	}

	if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil {
		return fmt.Errorf("Delete: %v", err)
	}

	return nil
}
Example #9
0
func SaveStuff(ctx *middleware.Context) {
	if ctx.Repo.Owner.Name != ctx.User.Name {
		fmt.Println("not yo repo")
		ctx.JSON(200, "NOT OK")
	} else {
		content := ctx.Query("content")
		fileDir := ctx.Query("fileDir")
		fileName := ctx.Query("fileName")
		fmt.Println(filepath.Join(ctx.Repo.GitRepo.Path+"/"+fileDir, fileName))

		if strings.Contains(fileDir, "..") || strings.Contains(fileName, "..") {
			ctx.JSON(200, "NOT OK WRITE")
		} else {

			err := ioutil.WriteFile(filepath.Join(ctx.Repo.GitRepo.Path+"/"+fileDir, fileName),
				[]byte(content), 0644)

			_, _, _ = process.ExecDir(-1,
				filepath.Join(ctx.Repo.GitRepo.Path), fmt.Sprintf("git add: %s", filepath.Join(ctx.Repo.GitRepo.Path)),
				"git", "add", "*.md")

			sig := ctx.User.NewGitSig()

			if _, stderr, err2 := process.ExecDir(-1,
				filepath.Join(ctx.Repo.GitRepo.Path), fmt.Sprintf("git commit: %s", filepath.Join(ctx.Repo.GitRepo.Path)),
				"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
				"-m", "save"); err2 != nil {
				ctx.JSON(200, "NOT COMMIT")
				fmt.Println("git commit: %s", err2)
				fmt.Println("git commit: %s", stderr)
			} else {
				if err != nil {
					ctx.JSON(200, "OK")
				} else {
					ctx.JSON(200, "NOT OK")
				}
			}
		}
	}
}
Example #10
0
// InitRepository initializes README and .gitignore if needed.
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) error {
	// Somehow the directory could exist.
	if com.IsExist(repoPath) {
		return fmt.Errorf("initRepository: path already exists: %s", repoPath)
	}

	// Init bare new repository.
	os.MkdirAll(repoPath, os.ModePerm)
	_, stderr, err := process.ExecDir(-1, repoPath,
		fmt.Sprintf("initRepository(git init --bare): %s", repoPath), "git", "init", "--bare")
	if err != nil {
		return fmt.Errorf("git init --bare: %v - %s", err, stderr)
	}

	if err := createUpdateHook(repoPath); err != nil {
		return err
	}

	tmpDir := filepath.Join(os.TempDir(), "gogs", repo.Name, com.ToStr(time.Now().Nanosecond()))

	// Initialize repository according to user's choice.
	if opts.AutoInit {
		os.MkdirAll(tmpDir, os.ModePerm)
		defer os.RemoveAll(tmpDir)

		if err = prepareRepoCommit(repo, tmpDir, repoPath, opts); err != nil {
			return fmt.Errorf("prepareRepoCommit: %v", err)
		}

		// Apply changes and commit.
		if err = initRepoCommit(tmpDir, u.NewGitSig()); err != nil {
			return fmt.Errorf("initRepoCommit: %v", err)
		}
	}

	// Re-fetch the repository from database before updating it (else it would
	// override changes that were done earlier with sql)
	if repo, err = getRepositoryByID(e, repo.ID); err != nil {
		return fmt.Errorf("getRepositoryByID: %v", err)
	}

	if !opts.AutoInit {
		repo.IsBare = true
	}

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

	return nil
}
Example #11
0
// initRepoCommit temporarily changes with work directory.
func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
	var stderr string
	if _, stderr, err = process.ExecDir(-1,
		tmpPath, fmt.Sprintf("initRepoCommit(git add): %s", tmpPath),
		"git", "add", "--all"); err != nil {
		return errors.New("git add: " + stderr)
	}

	if _, stderr, err = process.ExecDir(-1,
		tmpPath, fmt.Sprintf("initRepoCommit(git commit): %s", tmpPath),
		"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
		"-m", "initial commit"); err != nil {
		return errors.New("git commit: " + stderr)
	}

	if _, stderr, err = process.ExecDir(-1,
		tmpPath, fmt.Sprintf("initRepoCommit(git push): %s", tmpPath),
		"git", "push", "origin", "master"); err != nil {
		return errors.New("git push: " + stderr)
	}
	return nil
}
Example #12
0
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
	if isMirrorUpdating {
		return
	}
	isMirrorUpdating = true
	defer func() { isMirrorUpdating = false }()

	log.Trace("Doing: MirrorUpdate")

	mirrors := make([]*Mirror, 0, 10)
	if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error {
		m := bean.(*Mirror)
		if m.NextUpdate.After(time.Now()) {
			return nil
		}

		if m.Repo == nil {
			log.Error(4, "Disconnected mirror repository found: %d", m.ID)
			return nil
		}

		repoPath, err := m.Repo.RepoPath()
		if err != nil {
			return fmt.Errorf("Repo.RepoPath: %v", err)
		}

		if _, stderr, err := process.ExecDir(10*time.Minute,
			repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
			"git", "remote", "update", "--prune"); err != nil {
			desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr)
			log.Error(4, desc)
			if err = CreateRepositoryNotice(desc); err != nil {
				log.Error(4, "CreateRepositoryNotice: %v", err)
			}
			return nil
		}

		m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
		mirrors = append(mirrors, m)
		return nil
	}); err != nil {
		log.Error(4, "MirrorUpdate: %v", err)
	}

	for i := range mirrors {
		if err := UpdateMirror(mirrors[i]); err != nil {
			log.Error(4, "UpdateMirror[%d]: %v", mirrors[i].ID, err)
		}
	}
}
Example #13
0
func GitGcRepos() error {
	args := append([]string{"gc"}, setting.Git.GcArgs...)
	return x.Where("id > 0").Iterate(new(Repository),
		func(idx int, bean interface{}) error {
			repo := bean.(*Repository)
			if err := repo.GetOwner(); err != nil {
				return err
			}
			_, stderr, err := process.ExecDir(-1, RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection", "git", args...)
			if err != nil {
				return fmt.Errorf("%v: %v", err, stderr)
			}
			return nil
		})
}
Example #14
0
// CreateRepository creates a repository for given user or organization.
func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error) {
	repo := &Repository{
		OwnerID:     u.Id,
		Owner:       u,
		Name:        opts.Name,
		LowerName:   strings.ToLower(opts.Name),
		Description: opts.Description,
		IsPrivate:   opts.IsPrivate,
	}

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

	if err = createRepository(sess, u, repo); err != nil {
		return nil, err
	}

	// No need for init mirror.
	if !opts.IsMirror {
		repoPath := RepoPath(u.Name, repo.Name)
		if err = initRepository(sess, repoPath, u, repo, opts); err != nil {
			if err2 := os.RemoveAll(repoPath); err2 != nil {
				log.Error(4, "initRepository: %v", err)
				return nil, fmt.Errorf(
					"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
			}
			return nil, fmt.Errorf("initRepository: %v", err)
		}

		_, stderr, err := process.ExecDir(-1,
			repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath),
			"git", "update-server-info")
		if err != nil {
			return nil, errors.New("CreateRepository(git update-server-info): " + stderr)
		}
	}

	return repo, sess.Commit()
}
Example #15
0
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
	if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error {
		m := bean.(*Mirror)
		if m.NextUpdate.After(time.Now()) {
			return nil
		}

		repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git")
		if _, stderr, err := process.ExecDir(10*time.Minute,
			repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
			"git", "remote", "update"); err != nil {
			return errors.New("git remote update: " + stderr)
		}

		m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
		return UpdateMirror(m)
	}); err != nil {
		log.Error(4, "repo.MirrorUpdate: %v", err)
	}
}
Example #16
0
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
	if isMirrorUpdating {
		return
	}
	isMirrorUpdating = true
	defer func() { isMirrorUpdating = false }()

	mirrors := make([]*Mirror, 0, 10)

	if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error {
		m := bean.(*Mirror)
		if m.NextUpdate.After(time.Now()) {
			return nil
		}

		repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git")
		if _, stderr, err := process.ExecDir(10*time.Minute,
			repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
			"git", "remote", "update", "--prune"); err != nil {
			desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr)
			log.Error(4, desc)
			if err = CreateRepositoryNotice(desc); err != nil {
				log.Error(4, "Fail to add notice: %v", err)
			}
			return nil
		}

		m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
		mirrors = append(mirrors, m)
		return nil
	}); err != nil {
		log.Error(4, "MirrorUpdate: %v", err)
	}

	for i := range mirrors {
		if err := UpdateMirror(mirrors[i]); err != nil {
			log.Error(4, "UpdateMirror", fmt.Sprintf("%s: %v", mirrors[i].RepoName, err))
		}
	}
}
Example #17
0
File: pull.go Project: john-hu/gogs
// Merge merges pull request to base repository.
func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) {
	sess := x.NewSession()
	defer sessionRelease(sess)
	if err = sess.Begin(); err != nil {
		return err
	}

	if err = pr.Issue.changeStatus(sess, doer, true); err != nil {
		return fmt.Errorf("Pull.changeStatus: %v", err)
	}

	headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
	headGitRepo, err := git.OpenRepository(headRepoPath)
	if err != nil {
		return fmt.Errorf("OpenRepository: %v", err)
	}
	pr.MergedCommitID, err = headGitRepo.GetCommitIdOfBranch(pr.HeadBranch)
	if err != nil {
		return fmt.Errorf("GetCommitIdOfBranch: %v", err)
	}

	if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil {
		return fmt.Errorf("mergePullRequestAction: %v", err)
	}

	pr.HasMerged = true
	pr.Merged = time.Now()
	pr.MergerID = doer.Id
	if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
		return fmt.Errorf("update pull request: %v", err)
	}

	// Clone base repo.
	tmpBasePath := path.Join("data/tmp/repos", com.ToStr(time.Now().Nanosecond())+".git")
	os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm)
	defer os.RemoveAll(path.Dir(tmpBasePath))

	var stderr string
	if _, stderr, err = process.ExecTimeout(5*time.Minute,
		fmt.Sprintf("PullRequest.Merge(git clone): %s", tmpBasePath),
		"git", "clone", baseGitRepo.Path, tmpBasePath); err != nil {
		return fmt.Errorf("git clone: %s", stderr)
	}

	// Check out base branch.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge(git checkout): %s", tmpBasePath),
		"git", "checkout", pr.BaseBranch); err != nil {
		return fmt.Errorf("git checkout: %s", stderr)
	}

	// Pull commits.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge(git pull): %s", tmpBasePath),
		"git", "pull", headRepoPath, pr.HeadBranch); err != nil {
		return fmt.Errorf("git pull[%s / %s -> %s]: %s", headRepoPath, pr.HeadBranch, tmpBasePath, stderr)
	}

	// Push back to upstream.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge(git push): %s", tmpBasePath),
		"git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
		return fmt.Errorf("git push: %s", stderr)
	}

	return sess.Commit()
}
Example #18
0
File: pull.go Project: john-hu/gogs
// NewPullRequest creates new pull request with labels for repository.
func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte) (err error) {
	sess := x.NewSession()
	defer sessionRelease(sess)
	if err = sess.Begin(); err != nil {
		return err
	}

	if err = newIssue(sess, repo, pull, labelIDs, uuids, true); err != nil {
		return fmt.Errorf("newIssue: %v", err)
	}

	// Notify watchers.
	act := &Action{
		ActUserID:    pull.Poster.Id,
		ActUserName:  pull.Poster.Name,
		ActEmail:     pull.Poster.Email,
		OpType:       CREATE_PULL_REQUEST,
		Content:      fmt.Sprintf("%d|%s", pull.Index, pull.Name),
		RepoID:       repo.ID,
		RepoUserName: repo.Owner.Name,
		RepoName:     repo.Name,
		IsPrivate:    repo.IsPrivate,
	}
	if err = notifyWatchers(sess, act); err != nil {
		return err
	}

	// Test apply patch.
	if err = repo.UpdateLocalCopy(); err != nil {
		return fmt.Errorf("UpdateLocalCopy: %v", err)
	}

	repoPath, err := repo.RepoPath()
	if err != nil {
		return fmt.Errorf("RepoPath: %v", err)
	}
	patchPath := path.Join(repoPath, "pulls", com.ToStr(pull.ID)+".patch")

	os.MkdirAll(path.Dir(patchPath), os.ModePerm)
	if err = ioutil.WriteFile(patchPath, patch, 0644); err != nil {
		return fmt.Errorf("save patch: %v", err)
	}

	pr.Status = PULL_REQUEST_STATUS_MERGEABLE
	_, stderr, err := process.ExecDir(-1, repo.LocalCopyPath(),
		fmt.Sprintf("NewPullRequest(git apply --check): %d", repo.ID),
		"git", "apply", "--check", patchPath)
	if err != nil {
		if strings.Contains(stderr, "patch does not apply") {
			pr.Status = PULL_REQUEST_STATUS_CONFLICT
		} else {
			return fmt.Errorf("git apply --check: %v - %s", err, stderr)
		}
	}

	pr.IssueID = pull.ID
	pr.Index = pull.Index
	if _, err = sess.Insert(pr); err != nil {
		return fmt.Errorf("insert pull repo: %v", err)
	}

	return sess.Commit()
}
Example #19
0
File: pull.go Project: kiliit/gogs
// Merge merges pull request to base repository.
func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) {
	sess := x.NewSession()
	defer sessionRelease(sess)
	if err = sess.Begin(); err != nil {
		return err
	}

	if err = pr.Issue.changeStatus(sess, doer, true); err != nil {
		return fmt.Errorf("Issue.changeStatus: %v", err)
	}

	if err = pr.getHeadRepo(sess); err != nil {
		return fmt.Errorf("getHeadRepo: %v", err)
	}

	headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
	headGitRepo, err := git.OpenRepository(headRepoPath)
	if err != nil {
		return fmt.Errorf("OpenRepository: %v", err)
	}
	pr.MergedCommitID, err = headGitRepo.GetCommitIdOfBranch(pr.HeadBranch)
	if err != nil {
		return fmt.Errorf("GetCommitIdOfBranch: %v", err)
	}

	if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil {
		return fmt.Errorf("mergePullRequestAction: %v", err)
	}

	pr.HasMerged = true
	pr.Merged = time.Now()
	pr.MergerID = doer.Id
	if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
		return fmt.Errorf("update pull request: %v", err)
	}

	// Clone base repo.
	tmpBasePath := path.Join(setting.AppDataPath, "tmp/repos", com.ToStr(time.Now().Nanosecond())+".git")
	os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm)
	defer os.RemoveAll(path.Dir(tmpBasePath))

	var stderr string
	if _, stderr, err = process.ExecTimeout(5*time.Minute,
		fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
		"git", "clone", baseGitRepo.Path, tmpBasePath); err != nil {
		return fmt.Errorf("git clone: %s", stderr)
	}

	// Check out base branch.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
		"git", "checkout", pr.BaseBranch); err != nil {
		return fmt.Errorf("git checkout: %s", stderr)
	}

	// Add head repo remote.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath),
		"git", "remote", "add", "head_repo", headRepoPath); err != nil {
		return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
	}

	// Merge commits.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath),
		"git", "fetch", "head_repo"); err != nil {
		return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
	}

	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath),
		"git", "merge", "--no-ff", "--no-commit", "head_repo/"+pr.HeadBranch); err != nil {
		return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
	}

	sig := doer.NewGitSig()
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
		"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
		"-m", fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch)); err != nil {
		return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr)
	}

	// Push back to upstream.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
		"git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
		return fmt.Errorf("git push: %s", stderr)
	}

	return sess.Commit()
}
Example #20
0
// CreateRepository creates a repository for given user or organization.
func CreateRepository(u *User, name, desc, lang, license string, isPrivate, isMirror, initReadme bool) (_ *Repository, err error) {
	if err = IsUsableName(name); err != nil {
		return nil, err
	}

	has, err := IsRepositoryExist(u, name)
	if err != nil {
		return nil, fmt.Errorf("IsRepositoryExist: %v", err)
	} else if has {
		return nil, ErrRepoAlreadyExist
	}

	repo := &Repository{
		OwnerId:     u.Id,
		Owner:       u,
		Name:        name,
		LowerName:   strings.ToLower(name),
		Description: desc,
		IsPrivate:   isPrivate,
	}

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

	if _, err = sess.Insert(repo); err != nil {
		return nil, err
	} else if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil {
		return nil, err
	}

	// TODO fix code for mirrors?

	// Give access to all members in owner team.
	if u.IsOrganization() {
		t, err := u.getOwnerTeam(sess)
		if err != nil {
			return nil, fmt.Errorf("getOwnerTeam: %v", err)
		} else if err = t.addRepository(sess, repo); err != nil {
			return nil, fmt.Errorf("addRepository: %v", err)
		}
	} else {
		// Organization called this in addRepository method.
		if err = repo.recalculateAccesses(sess); err != nil {
			return nil, fmt.Errorf("recalculateAccesses: %v", err)
		}
	}

	if err = watchRepo(sess, u.Id, repo.Id, true); err != nil {
		return nil, fmt.Errorf("watchRepo: %v", err)
	} else if err = newRepoAction(sess, u, repo); err != nil {
		return nil, fmt.Errorf("newRepoAction: %v", err)
	}

	// No need for init mirror.
	if !isMirror {
		repoPath := RepoPath(u.Name, repo.Name)
		if err = initRepository(sess, repoPath, u, repo, initReadme, lang, license); err != nil {
			if err2 := os.RemoveAll(repoPath); err2 != nil {
				log.Error(4, "initRepository: %v", err)
				return nil, fmt.Errorf(
					"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
			}
			return nil, fmt.Errorf("initRepository: %v", err)
		}

		_, stderr, err := process.ExecDir(-1,
			repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath),
			"git", "update-server-info")
		if err != nil {
			return nil, errors.New("CreateRepository(git update-server-info): " + stderr)
		}
	}

	return repo, sess.Commit()
}
Example #21
0
// CreateRepository creates a repository for given user or organization.
func CreateRepository(u *User, name, desc, lang, license string, private, mirror, initReadme bool) (*Repository, error) {
	if !IsLegalName(name) {
		return nil, ErrRepoNameIllegal
	}

	isExist, err := IsRepositoryExist(u, name)
	if err != nil {
		return nil, err
	} else if isExist {
		return nil, ErrRepoAlreadyExist
	}

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

	repo := &Repository{
		OwnerId:     u.Id,
		Owner:       u,
		Name:        name,
		LowerName:   strings.ToLower(name),
		Description: desc,
		IsPrivate:   private,
	}

	if _, err = sess.Insert(repo); err != nil {
		sess.Rollback()
		return nil, err
	}

	var t *Team // Owner team.

	mode := WRITABLE
	if mirror {
		mode = READABLE
	}
	access := &Access{
		UserName: u.LowerName,
		RepoName: path.Join(u.LowerName, repo.LowerName),
		Mode:     mode,
	}
	// Give access to all members in owner team.
	if u.IsOrganization() {
		t, err = u.GetOwnerTeam()
		if err != nil {
			sess.Rollback()
			return nil, err
		}
		if err = t.GetMembers(); err != nil {
			sess.Rollback()
			return nil, err
		}
		for _, u := range t.Members {
			access.Id = 0
			access.UserName = u.LowerName
			if _, err = sess.Insert(access); err != nil {
				sess.Rollback()
				return nil, err
			}
		}
	} else {
		if _, err = sess.Insert(access); err != nil {
			sess.Rollback()
			return nil, err
		}
	}

	if _, err = sess.Exec(
		"UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil {
		sess.Rollback()
		return nil, err
	}

	// Update owner team info and count.
	if u.IsOrganization() {
		t.RepoIds += "$" + com.ToStr(repo.Id) + "|"
		t.NumRepos++
		if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
			sess.Rollback()
			return nil, err
		}
	}

	if err = sess.Commit(); err != nil {
		return nil, err
	}

	if u.IsOrganization() {
		t, err := u.GetOwnerTeam()
		if err != nil {
			log.Error(4, "GetOwnerTeam: %v", err)
		} else {
			if err = t.GetMembers(); err != nil {
				log.Error(4, "GetMembers: %v", err)
			} else {
				for _, u := range t.Members {
					if err = WatchRepo(u.Id, repo.Id, true); err != nil {
						log.Error(4, "WatchRepo2: %v", err)
					}
				}
			}
		}
	} else {
		if err = WatchRepo(u.Id, repo.Id, true); err != nil {
			log.Error(4, "WatchRepo3: %v", err)
		}
	}

	if err = NewRepoAction(u, repo); err != nil {
		log.Error(4, "NewRepoAction: %v", err)
	}

	// No need for init mirror.
	if mirror {
		return repo, nil
	}

	repoPath := RepoPath(u.Name, repo.Name)
	if err = initRepository(repoPath, u, repo, initReadme, lang, license); err != nil {
		if err2 := os.RemoveAll(repoPath); err2 != nil {
			log.Error(4, "initRepository: %v", err)
			return nil, fmt.Errorf(
				"delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2)
		}
		return nil, fmt.Errorf("initRepository: %v", err)
	}

	_, stderr, err := process.ExecDir(-1,
		repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath),
		"git", "update-server-info")
	if err != nil {
		return nil, errors.New("CreateRepository(git update-server-info): " + stderr)
	}

	return repo, nil
}
Example #22
0
File: pull.go Project: yweber/gogs
// Merge merges pull request to base repository.
func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) {
	if err = pr.GetHeadRepo(); err != nil {
		return fmt.Errorf("GetHeadRepo: %v", err)
	} else if err = pr.GetBaseRepo(); err != nil {
		return fmt.Errorf("GetBaseRepo: %v", err)
	}

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

	if err = pr.Issue.changeStatus(sess, doer, pr.Issue.Repo, true); err != nil {
		return fmt.Errorf("Issue.changeStatus: %v", err)
	}

	headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
	headGitRepo, err := git.OpenRepository(headRepoPath)
	if err != nil {
		return fmt.Errorf("OpenRepository: %v", err)
	}
	pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
	if err != nil {
		return fmt.Errorf("GetBranchCommitID: %v", err)
	}

	if err = mergePullRequestAction(sess, doer, pr.Issue.Repo, pr.Issue); err != nil {
		return fmt.Errorf("mergePullRequestAction: %v", err)
	}

	pr.HasMerged = true
	pr.Merged = time.Now()
	pr.MergerID = doer.ID
	if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
		return fmt.Errorf("update pull request: %v", err)
	}

	// Clone base repo.
	tmpBasePath := path.Join(setting.AppDataPath, "tmp/repos", com.ToStr(time.Now().Nanosecond())+".git")
	os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm)
	defer os.RemoveAll(path.Dir(tmpBasePath))

	var stderr string
	if _, stderr, err = process.ExecTimeout(5*time.Minute,
		fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
		"git", "clone", baseGitRepo.Path, tmpBasePath); err != nil {
		return fmt.Errorf("git clone: %s", stderr)
	}

	// Check out base branch.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
		"git", "checkout", pr.BaseBranch); err != nil {
		return fmt.Errorf("git checkout: %s", stderr)
	}

	// Add head repo remote.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath),
		"git", "remote", "add", "head_repo", headRepoPath); err != nil {
		return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
	}

	// Merge commits.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath),
		"git", "fetch", "head_repo"); err != nil {
		return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
	}

	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath),
		"git", "merge", "--no-ff", "--no-commit", "head_repo/"+pr.HeadBranch); err != nil {
		return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
	}

	sig := doer.NewGitSig()
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
		"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
		"-m", fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch)); err != nil {
		return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr)
	}

	// Push back to upstream.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
		"git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
		return fmt.Errorf("git push: %s", stderr)
	}

	if err = sess.Commit(); err != nil {
		return fmt.Errorf("Commit: %v", err)
	}

	// Compose commit repository action
	l, err := headGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
	if err != nil {
		return fmt.Errorf("CommitsBetween: %v", err)
	}
	p := &api.PushPayload{
		Ref:        "refs/heads/" + pr.BaseBranch,
		Before:     pr.MergeBase,
		After:      pr.MergedCommitID,
		CompareUrl: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
		Commits:    ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.FullLink()),
		Repo:       pr.BaseRepo.ComposePayload(),
		Pusher: &api.PayloadAuthor{
			Name:     pr.HeadRepo.MustOwner().DisplayName(),
			Email:    pr.HeadRepo.MustOwner().Email,
			UserName: pr.HeadRepo.MustOwner().Name,
		},
		Sender: &api.PayloadUser{
			UserName:  doer.Name,
			ID:        doer.ID,
			AvatarUrl: setting.AppUrl + doer.RelAvatarLink(),
		},
	}
	if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
		return fmt.Errorf("PrepareWebhooks: %v", err)
	}
	go HookQueue.Add(pr.BaseRepo.ID)
	return nil
}
Example #23
0
// InitRepository initializes README and .gitignore if needed.
func initRepository(e Engine, repoPath string, u *User, repo *Repository, initReadme bool, repoLang, license string) error {
	// Somehow the directory could exist.
	if com.IsExist(repoPath) {
		return fmt.Errorf("initRepository: path already exists: %s", repoPath)
	}

	// Init bare new repository.
	os.MkdirAll(repoPath, os.ModePerm)
	_, stderr, err := process.ExecDir(-1, repoPath,
		fmt.Sprintf("initRepository(git init --bare): %s", repoPath),
		"git", "init", "--bare")
	if err != nil {
		return fmt.Errorf("git init --bare: %s", err)
	}

	if err := createUpdateHook(repoPath); err != nil {
		return err
	}

	// Initialize repository according to user's choice.
	fileName := map[string]string{}
	if initReadme {
		fileName["readme"] = "README.md"
	}
	if repoLang != "" {
		fileName["gitign"] = ".gitignore"
	}
	if license != "" {
		fileName["license"] = "LICENSE"
	}

	// Clone to temprory path and do the init commit.
	tmpDir := filepath.Join(os.TempDir(), com.ToStr(time.Now().Nanosecond()))
	os.MkdirAll(tmpDir, os.ModePerm)
	defer os.RemoveAll(tmpDir)

	_, stderr, err = process.Exec(
		fmt.Sprintf("initRepository(git clone): %s", repoPath),
		"git", "clone", repoPath, tmpDir)
	if err != nil {
		return errors.New("git clone: " + stderr)
	}

	// README
	if initReadme {
		defaultReadme := repo.Name + "\n" + strings.Repeat("=",
			utf8.RuneCountInString(repo.Name)) + "\n\n" + repo.Description
		if err := ioutil.WriteFile(filepath.Join(tmpDir, fileName["readme"]),
			[]byte(defaultReadme), 0644); err != nil {
			return err
		}
	}

	// FIXME: following two can be merged.

	// .gitignore
	// Copy custom file when available.
	customPath := path.Join(setting.CustomPath, "conf/gitignore", repoLang)
	targetPath := path.Join(tmpDir, fileName["gitign"])
	if com.IsFile(customPath) {
		if err := com.Copy(customPath, targetPath); err != nil {
			return fmt.Errorf("copy gitignore: %v", err)
		}
	} else if com.IsSliceContainsStr(Gitignores, repoLang) {
		if err = ioutil.WriteFile(targetPath,
			bindata.MustAsset(path.Join("conf/gitignore", repoLang)), 0644); err != nil {
			return fmt.Errorf("generate gitignore: %v", err)
		}
	} else {
		delete(fileName, "gitign")
	}

	// LICENSE
	customPath = path.Join(setting.CustomPath, "conf/license", license)
	targetPath = path.Join(tmpDir, fileName["license"])
	if com.IsFile(customPath) {
		if err = com.Copy(customPath, targetPath); err != nil {
			return fmt.Errorf("copy license: %v", err)
		}
	} else if com.IsSliceContainsStr(Licenses, license) {
		if err = ioutil.WriteFile(targetPath,
			bindata.MustAsset(path.Join("conf/license", license)), 0644); err != nil {
			return fmt.Errorf("generate license: %v", err)
		}
	} else {
		delete(fileName, "license")
	}

	if len(fileName) == 0 {
		// Re-fetch the repository from database before updating it (else it would
		// override changes that were done earlier with sql)
		if repo, err = getRepositoryById(e, repo.Id); err != nil {
			return err
		}
		repo.IsBare = true
		repo.DefaultBranch = "master"
		return updateRepository(e, repo, false)
	}

	// Apply changes and commit.
	return initRepoCommit(tmpDir, u.NewGitSig())
}
Example #24
0
func ForkRepository(u *User, oldRepo *Repository) (*Repository, error) {
	isExist, err := IsRepositoryExist(u, oldRepo.Name)
	if err != nil {
		return nil, err
	} else if isExist {
		return nil, ErrRepoAlreadyExist
	}

	// In case the old repository is a fork.
	if oldRepo.IsFork {
		oldRepo, err = GetRepositoryById(oldRepo.ForkId)
		if err != nil {
			return nil, err
		}
	}

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

	repo := &Repository{
		OwnerId:     u.Id,
		Owner:       u,
		Name:        oldRepo.Name,
		LowerName:   oldRepo.LowerName,
		Description: oldRepo.Description,
		IsPrivate:   oldRepo.IsPrivate,
		IsFork:      true,
		ForkId:      oldRepo.Id,
	}

	if _, err = sess.Insert(repo); err != nil {
		sess.Rollback()
		return nil, err
	}

	var t *Team // Owner team.

	mode := WRITABLE

	access := &Access{
		UserName: u.LowerName,
		RepoName: path.Join(u.LowerName, repo.LowerName),
		Mode:     mode,
	}
	// Give access to all members in owner team.
	if u.IsOrganization() {
		t, err = u.GetOwnerTeam()
		if err != nil {
			sess.Rollback()
			return nil, err
		}
		if err = t.GetMembers(); err != nil {
			sess.Rollback()
			return nil, err
		}
		for _, u := range t.Members {
			access.Id = 0
			access.UserName = u.LowerName
			if _, err = sess.Insert(access); err != nil {
				sess.Rollback()
				return nil, err
			}
		}
	} else {
		if _, err = sess.Insert(access); err != nil {
			sess.Rollback()
			return nil, err
		}
	}

	if _, err = sess.Exec(
		"UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil {
		sess.Rollback()
		return nil, err
	}

	// Update owner team info and count.
	if u.IsOrganization() {
		t.RepoIds += "$" + com.ToStr(repo.Id) + "|"
		t.NumRepos++
		if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
			sess.Rollback()
			return nil, err
		}
	}

	if u.IsOrganization() {
		t, err := u.GetOwnerTeam()
		if err != nil {
			log.Error(4, "GetOwnerTeam: %v", err)
		} else {
			if err = t.GetMembers(); err != nil {
				log.Error(4, "GetMembers: %v", err)
			} else {
				for _, u := range t.Members {
					if err = watchRepoWithEngine(sess, u.Id, repo.Id, true); err != nil {
						log.Error(4, "WatchRepo2: %v", err)
					}
				}
			}
		}
	} else {
		if err = watchRepoWithEngine(sess, u.Id, repo.Id, true); err != nil {
			log.Error(4, "WatchRepo3: %v", err)
		}
	}

	if err = NewRepoAction(u, repo); err != nil {
		log.Error(4, "NewRepoAction: %v", err)
	}

	if _, err = sess.Exec(
		"UPDATE `repository` SET num_forks = num_forks + 1 WHERE id = ?", oldRepo.Id); err != nil {
		sess.Rollback()
		return nil, err
	}

	oldRepoPath, err := oldRepo.RepoPath()
	if err != nil {
		sess.Rollback()
		return nil, fmt.Errorf("fail to get repo path(%s): %v", oldRepo.Name, err)
	}

	if err = sess.Commit(); err != nil {
		return nil, err
	}

	repoPath := RepoPath(u.Name, repo.Name)
	_, stderr, err := process.ExecTimeout(10*time.Minute,
		fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
		"git", "clone", "--bare", oldRepoPath, repoPath)
	if err != nil {
		return nil, errors.New("ForkRepository(git clone): " + stderr)
	}

	_, stderr, err = process.ExecDir(-1,
		repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath),
		"git", "update-server-info")
	if err != nil {
		return nil, errors.New("ForkRepository(git update-server-info): " + stderr)
	}

	return repo, nil
}
Example #25
0
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
	has, err := IsRepositoryExist(u, name)
	if err != nil {
		return nil, fmt.Errorf("IsRepositoryExist: %v", err)
	} else if has {
		return nil, ErrRepoAlreadyExist
	}

	// In case the old repository is a fork.
	if oldRepo.IsFork {
		oldRepo, err = GetRepositoryById(oldRepo.ForkId)
		if err != nil {
			return nil, err
		}
	}

	repo := &Repository{
		OwnerId:     u.Id,
		Owner:       u,
		Name:        name,
		LowerName:   strings.ToLower(name),
		Description: desc,
		IsPrivate:   oldRepo.IsPrivate,
		IsFork:      true,
		ForkId:      oldRepo.Id,
	}

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

	if _, err = sess.Insert(repo); err != nil {
		return nil, err
	}

	if err = repo.recalculateAccesses(sess); err != nil {
		return nil, err
	} else if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil {
		return nil, err
	}

	if u.IsOrganization() {
		// Update owner team info and count.
		t, err := u.getOwnerTeam(sess)
		if err != nil {
			return nil, fmt.Errorf("getOwnerTeam: %v", err)
		} else if err = t.addRepository(sess, repo); err != nil {
			return nil, fmt.Errorf("addRepository: %v", err)
		}
	} else {
		if err = watchRepo(sess, u.Id, repo.Id, true); err != nil {
			return nil, fmt.Errorf("watchRepo: %v", err)
		}
	}

	if err = newRepoAction(sess, u, repo); err != nil {
		return nil, fmt.Errorf("newRepoAction: %v", err)
	}

	if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.Id); err != nil {
		return nil, err
	}

	oldRepoPath, err := oldRepo.RepoPath()
	if err != nil {
		return nil, fmt.Errorf("get old repository path: %v", err)
	}

	repoPath := RepoPath(u.Name, repo.Name)
	_, stderr, err := process.ExecTimeout(10*time.Minute,
		fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
		"git", "clone", "--bare", oldRepoPath, repoPath)
	if err != nil {
		return nil, fmt.Errorf("git clone: %v", stderr)
	}

	_, stderr, err = process.ExecDir(-1,
		repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath),
		"git", "update-server-info")
	if err != nil {
		return nil, fmt.Errorf("git update-server-info: %v", err)
	}

	if err = createUpdateHook(repoPath); err != nil {
		return nil, fmt.Errorf("createUpdateHook: %v", err)
	}

	return repo, sess.Commit()
}
Example #26
0
// Merge merges pull request to base repository.
// FIXME: add repoWorkingPull make sure two merges does not happen at same time.
func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error) {
	if err = pr.GetHeadRepo(); err != nil {
		return fmt.Errorf("GetHeadRepo: %v", err)
	} else if err = pr.GetBaseRepo(); err != nil {
		return fmt.Errorf("GetBaseRepo: %v", err)
	}

	defer func() {
		go HookQueue.Add(pr.BaseRepo.ID)
		go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
	}()

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

	if err = pr.Issue.changeStatus(sess, doer, pr.Issue.Repo, true); err != nil {
		return fmt.Errorf("Issue.changeStatus: %v", err)
	}

	headRepoPath := RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
	headGitRepo, err := git.OpenRepository(headRepoPath)
	if err != nil {
		return fmt.Errorf("OpenRepository: %v", err)
	}

	// Clone base repo.
	tmpBasePath := path.Join(setting.AppDataPath, "tmp/repos", com.ToStr(time.Now().Nanosecond())+".git")
	os.MkdirAll(path.Dir(tmpBasePath), os.ModePerm)
	defer os.RemoveAll(path.Dir(tmpBasePath))

	var stderr string
	if _, stderr, err = process.ExecTimeout(5*time.Minute,
		fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath),
		"git", "clone", baseGitRepo.Path, tmpBasePath); err != nil {
		return fmt.Errorf("git clone: %s", stderr)
	}

	// Check out base branch.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
		"git", "checkout", pr.BaseBranch); err != nil {
		return fmt.Errorf("git checkout: %s", stderr)
	}

	// Add head repo remote.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath),
		"git", "remote", "add", "head_repo", headRepoPath); err != nil {
		return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
	}

	// Merge commits.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath),
		"git", "fetch", "head_repo"); err != nil {
		return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
	}

	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath),
		"git", "merge", "--no-ff", "--no-commit", "head_repo/"+pr.HeadBranch); err != nil {
		return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr)
	}

	sig := doer.NewGitSig()
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
		"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
		"-m", fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch)); err != nil {
		return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr)
	}

	// Push back to upstream.
	if _, stderr, err = process.ExecDir(-1, tmpBasePath,
		fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath),
		"git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil {
		return fmt.Errorf("git push: %s", stderr)
	}

	pr.MergedCommitID, err = headGitRepo.GetBranchCommitID(pr.HeadBranch)
	if err != nil {
		return fmt.Errorf("GetBranchCommit: %v", err)
	}

	pr.HasMerged = true
	pr.Merged = time.Now()
	pr.MergerID = doer.ID
	if _, err = sess.Id(pr.ID).AllCols().Update(pr); err != nil {
		return fmt.Errorf("update pull request: %v", err)
	}

	if err = sess.Commit(); err != nil {
		return fmt.Errorf("Commit: %v", err)
	}

	if err = MergePullRequestAction(doer, pr.Issue.Repo, pr.Issue); err != nil {
		log.Error(4, "MergePullRequestAction [%d]: %v", pr.ID, err)
	}

	// Reload pull request information.
	if err = pr.LoadAttributes(); err != nil {
		log.Error(4, "LoadAttributes: %v", err)
		return nil
	}
	if err = PrepareWebhooks(pr.Issue.Repo, HOOK_EVENT_PULL_REQUEST, &api.PullRequestPayload{
		Action:      api.HOOK_ISSUE_CLOSED,
		Index:       pr.Index,
		PullRequest: pr.APIFormat(),
		Repository:  pr.Issue.Repo.APIFormat(nil),
		Sender:      doer.APIFormat(),
	}); err != nil {
		log.Error(4, "PrepareWebhooks: %v", err)
		return nil
	}

	l, err := headGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
	if err != nil {
		log.Error(4, "CommitsBetweenIDs: %v", err)
		return nil
	}

	// TODO: when squash commits, no need to append merge commit.
	// It is possible that head branch is not fully sync with base branch for merge commits,
	// so we need to get latest head commit and append merge commit manully
	// to avoid strange diff commits produced.
	mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
	if err != nil {
		log.Error(4, "GetBranchCommit: %v", err)
		return nil
	}
	l.PushFront(mergeCommit)

	p := &api.PushPayload{
		Ref:        git.BRANCH_PREFIX + pr.BaseBranch,
		Before:     pr.MergeBase,
		After:      pr.MergedCommitID,
		CompareURL: setting.AppUrl + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
		Commits:    ListToPushCommits(l).ToApiPayloadCommits(pr.BaseRepo.HTMLURL()),
		Repo:       pr.BaseRepo.APIFormat(nil),
		Pusher:     pr.HeadRepo.MustOwner().APIFormat(),
		Sender:     doer.APIFormat(),
	}
	if err = PrepareWebhooks(pr.BaseRepo, HOOK_EVENT_PUSH, p); err != nil {
		return fmt.Errorf("PrepareWebhooks: %v", err)
	}
	return nil
}