2014-02-07 13:10:01 +03:00
|
|
|
package handler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"github.com/drone/drone/pkg/channel"
|
|
|
|
"github.com/drone/drone/pkg/database"
|
|
|
|
. "github.com/drone/drone/pkg/model"
|
2014-03-28 21:40:26 +03:00
|
|
|
"github.com/drone/go-bitbucket/bitbucket"
|
2014-03-29 14:51:02 +03:00
|
|
|
"github.com/drone/go-github/github"
|
2014-02-07 13:10:01 +03:00
|
|
|
|
|
|
|
"launchpad.net/goyaml"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Display a Repository dashboard.
|
|
|
|
func RepoDashboard(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
2014-02-12 22:22:56 +03:00
|
|
|
branch := r.FormValue("branch")
|
2014-02-07 13:10:01 +03:00
|
|
|
|
|
|
|
// get a list of all branches
|
|
|
|
branches, err := database.ListBranches(repo.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no branch is provided then we'll
|
|
|
|
// want to use a default value.
|
|
|
|
if len(branch) == 0 {
|
|
|
|
branch = repo.DefaultBranch()
|
|
|
|
}
|
|
|
|
|
|
|
|
// get a list of recent commits for the
|
|
|
|
// repository and specific branch
|
|
|
|
commits, err := database.ListCommits(repo.ID, branch)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// get a token that can be exchanged with the
|
|
|
|
// websocket handler to authorize listening
|
|
|
|
// for a stream of changes for this repository
|
|
|
|
token := channel.Create(repo.Slug)
|
|
|
|
|
|
|
|
data := struct {
|
|
|
|
User *User
|
|
|
|
Repo *Repo
|
|
|
|
Branches []*Commit
|
|
|
|
Commits []*Commit
|
|
|
|
Branch string
|
|
|
|
Token string
|
|
|
|
}{u, repo, branches, commits, branch, token}
|
|
|
|
|
|
|
|
return RenderTemplate(w, "repo_dashboard.html", &data)
|
|
|
|
}
|
|
|
|
|
2014-03-28 21:40:26 +03:00
|
|
|
func RepoAddGithub(w http.ResponseWriter, r *http.Request, u *User) error {
|
2014-02-09 17:09:38 +03:00
|
|
|
settings := database.SettingsMust()
|
2014-02-07 13:10:01 +03:00
|
|
|
teams, err := database.ListTeams(u.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
data := struct {
|
2014-03-06 21:45:21 +03:00
|
|
|
User *User
|
|
|
|
Teams []*Team
|
2014-02-09 17:09:38 +03:00
|
|
|
Settings *Settings
|
|
|
|
}{u, teams, settings}
|
2014-02-07 13:10:01 +03:00
|
|
|
// if the user hasn't linked their GitHub account
|
|
|
|
// render a different template
|
|
|
|
if len(u.GithubToken) == 0 {
|
|
|
|
return RenderTemplate(w, "github_link.html", &data)
|
|
|
|
}
|
|
|
|
// otherwise display the template for adding
|
|
|
|
// a new GitHub repository.
|
|
|
|
return RenderTemplate(w, "github_add.html", &data)
|
|
|
|
}
|
|
|
|
|
2014-03-28 21:40:26 +03:00
|
|
|
func RepoAddBitbucket(w http.ResponseWriter, r *http.Request, u *User) error {
|
|
|
|
settings := database.SettingsMust()
|
|
|
|
teams, err := database.ListTeams(u.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
data := struct {
|
|
|
|
User *User
|
|
|
|
Teams []*Team
|
|
|
|
Settings *Settings
|
|
|
|
}{u, teams, settings}
|
|
|
|
// if the user hasn't linked their Bitbucket account
|
|
|
|
// render a different template
|
|
|
|
if len(u.BitbucketToken) == 0 {
|
|
|
|
return RenderTemplate(w, "bitbucket_link.html", &data)
|
|
|
|
}
|
|
|
|
// otherwise display the template for adding
|
|
|
|
// a new Bitbucket repository.
|
|
|
|
return RenderTemplate(w, "bitbucket_add.html", &data)
|
|
|
|
}
|
|
|
|
|
2014-02-07 13:10:01 +03:00
|
|
|
func RepoCreateGithub(w http.ResponseWriter, r *http.Request, u *User) error {
|
|
|
|
teamName := r.FormValue("team")
|
|
|
|
owner := r.FormValue("owner")
|
|
|
|
name := r.FormValue("name")
|
|
|
|
|
|
|
|
// get the github settings from the database
|
|
|
|
settings := database.SettingsMust()
|
|
|
|
|
|
|
|
// create the GitHub client
|
|
|
|
client := github.New(u.GithubToken)
|
2014-02-09 16:59:51 +03:00
|
|
|
client.ApiUrl = settings.GitHubApiUrl
|
2014-02-07 13:10:01 +03:00
|
|
|
githubRepo, err := client.Repos.Find(owner, name)
|
|
|
|
if err != nil {
|
2014-03-12 09:00:06 +03:00
|
|
|
return fmt.Errorf("Unable to find GitHub repository %s/%s.", owner, name)
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
|
|
|
|
2014-02-09 16:45:15 +03:00
|
|
|
repo, err := NewGitHubRepo(settings.GitHubDomain, owner, name, githubRepo.Private)
|
2014-02-07 13:10:01 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
repo.UserID = u.ID
|
2014-02-07 13:35:27 +03:00
|
|
|
repo.Private = githubRepo.Private
|
2014-02-07 13:10:01 +03:00
|
|
|
|
|
|
|
// if the user chose to assign to a team account
|
|
|
|
// we need to retrieve the team, verify the user
|
|
|
|
// has access, and then set the team id.
|
|
|
|
if len(teamName) > 0 {
|
|
|
|
team, err := database.GetTeamSlug(teamName)
|
|
|
|
if err != nil {
|
2014-03-12 09:00:06 +03:00
|
|
|
return fmt.Errorf("Unable to find Team %s.", teamName)
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// user must be an admin member of the team
|
|
|
|
if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok {
|
2014-03-12 09:00:06 +03:00
|
|
|
return fmt.Errorf("Invalid permission to access Team %s.", teamName)
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
repo.TeamID = team.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the repository is private we'll need
|
|
|
|
// to upload a github key to the repository
|
|
|
|
if repo.Private {
|
|
|
|
// name the key
|
|
|
|
keyName := fmt.Sprintf("%s@%s", repo.Owner, settings.Domain)
|
|
|
|
|
|
|
|
// create the github key, or update if one already exists
|
|
|
|
_, err := client.RepoKeys.CreateUpdate(owner, name, repo.PublicKey, keyName)
|
|
|
|
if err != nil {
|
2014-03-12 09:00:06 +03:00
|
|
|
return fmt.Errorf("Unable to add Public Key to your GitHub repository.")
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
2014-02-07 13:35:27 +03:00
|
|
|
} else {
|
|
|
|
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// create a hook so that we get notified when code
|
|
|
|
// is pushed to the repository and can execute a build.
|
|
|
|
link := fmt.Sprintf("%s://%s/hook/github.com?id=%s", settings.Scheme, settings.Domain, repo.Slug)
|
|
|
|
|
|
|
|
// add the hook
|
|
|
|
if _, err := client.Hooks.CreateUpdate(owner, name, link); err != nil {
|
2014-03-12 09:00:06 +03:00
|
|
|
return fmt.Errorf("Unable to add Hook to your GitHub repository.")
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Save to the database
|
|
|
|
if err := database.SaveRepo(repo); err != nil {
|
2014-03-12 09:00:06 +03:00
|
|
|
return fmt.Errorf("Error saving repository to the database. %s", err)
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
|
|
|
|
}
|
|
|
|
|
2014-03-28 21:40:26 +03:00
|
|
|
func RepoCreateBitbucket(w http.ResponseWriter, r *http.Request, u *User) error {
|
|
|
|
teamName := r.FormValue("team")
|
|
|
|
owner := r.FormValue("owner")
|
|
|
|
name := r.FormValue("name")
|
|
|
|
|
|
|
|
// get the bitbucket settings from the database
|
|
|
|
settings := database.SettingsMust()
|
|
|
|
|
|
|
|
// create the Bitbucket client
|
|
|
|
client := bitbucket.New(
|
|
|
|
settings.BitbucketKey,
|
|
|
|
settings.BitbucketSecret,
|
|
|
|
u.BitbucketToken,
|
|
|
|
u.BitbucketSecret,
|
|
|
|
)
|
|
|
|
|
|
|
|
bitbucketRepo, err := client.Repos.Find(owner, name)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Unable to find Bitbucket repository %s/%s.", owner, name)
|
|
|
|
}
|
|
|
|
|
|
|
|
repo, err := NewBitbucketRepo(owner, name, bitbucketRepo.Private)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
repo.UserID = u.ID
|
|
|
|
repo.Private = bitbucketRepo.Private
|
|
|
|
|
|
|
|
// if the user chose to assign to a team account
|
|
|
|
// we need to retrieve the team, verify the user
|
|
|
|
// has access, and then set the team id.
|
|
|
|
if len(teamName) > 0 {
|
|
|
|
team, err := database.GetTeamSlug(teamName)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Unable to find Team %s.", teamName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// user must be an admin member of the team
|
|
|
|
if ok, _ := database.IsMemberAdmin(u.ID, team.ID); !ok {
|
|
|
|
return fmt.Errorf("Invalid permission to access Team %s.", teamName)
|
|
|
|
}
|
|
|
|
|
|
|
|
repo.TeamID = team.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the repository is private we'll need
|
|
|
|
// to upload a bitbucket key to the repository
|
|
|
|
if repo.Private {
|
|
|
|
// name the key
|
|
|
|
keyName := fmt.Sprintf("%s@%s", repo.Owner, settings.Domain)
|
|
|
|
|
|
|
|
// create the bitbucket key, or update if one already exists
|
|
|
|
_, err := client.RepoKeys.CreateUpdate(owner, name, repo.PublicKey, keyName)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Unable to add Public Key to your Bitbucket repository: %s", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// create a hook so that we get notified when code
|
|
|
|
// is pushed to the repository and can execute a build.
|
|
|
|
link := fmt.Sprintf("%s://%s/hook/bitbucket.org?id=%s", settings.Scheme, settings.Domain, repo.Slug)
|
|
|
|
|
|
|
|
// add the hook
|
|
|
|
if _, err := client.Brokers.CreateUpdate(owner, name, link, bitbucket.BrokerTypePost); err != nil {
|
|
|
|
return fmt.Errorf("Unable to add Hook to your Bitbucket repository. %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save to the database
|
|
|
|
if err := database.SaveRepo(repo); err != nil {
|
|
|
|
return fmt.Errorf("Error saving repository to the database. %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
|
|
|
|
}
|
|
|
|
|
2014-02-07 13:10:01 +03:00
|
|
|
// Repository Settings
|
|
|
|
func RepoSettingsForm(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
|
|
|
|
|
|
|
// get the list of teams
|
|
|
|
teams, err := database.ListTeams(u.ID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
data := struct {
|
|
|
|
Repo *Repo
|
|
|
|
User *User
|
|
|
|
Teams []*Team
|
|
|
|
Owner *User
|
|
|
|
Team *Team
|
|
|
|
}{Repo: repo, User: u, Teams: teams}
|
|
|
|
|
|
|
|
// get the repo owner
|
|
|
|
if repo.TeamID > 0 {
|
|
|
|
data.Team, err = database.GetTeam(repo.TeamID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the team owner
|
|
|
|
data.Owner, err = database.GetUser(repo.UserID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return RenderTemplate(w, "repo_settings.html", &data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Repository Params (YAML parameters) Form
|
|
|
|
func RepoParamsForm(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
|
|
|
|
|
|
|
data := struct {
|
|
|
|
Repo *Repo
|
|
|
|
User *User
|
|
|
|
Textarea string
|
|
|
|
}{repo, u, ""}
|
|
|
|
|
|
|
|
if repo.Params != nil && len(repo.Params) != 0 {
|
|
|
|
raw, _ := goyaml.Marshal(&repo.Params)
|
|
|
|
data.Textarea = string(raw)
|
|
|
|
}
|
|
|
|
|
|
|
|
return RenderTemplate(w, "repo_params.html", &data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func RepoBadges(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
|
|
|
// hostname from settings
|
|
|
|
hostname := database.SettingsMust().URL().String()
|
|
|
|
|
|
|
|
data := struct {
|
|
|
|
Repo *Repo
|
|
|
|
User *User
|
|
|
|
Host string
|
|
|
|
}{repo, u, hostname}
|
|
|
|
return RenderTemplate(w, "repo_badges.html", &data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func RepoKeys(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
|
|
|
data := struct {
|
|
|
|
Repo *Repo
|
|
|
|
User *User
|
|
|
|
}{repo, u}
|
|
|
|
return RenderTemplate(w, "repo_keys.html", &data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Updates an existing repository.
|
|
|
|
func RepoUpdate(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
|
|
|
switch r.FormValue("action") {
|
|
|
|
case "params":
|
|
|
|
repo.Params = map[string]string{}
|
|
|
|
if err := goyaml.Unmarshal([]byte(r.FormValue("params")), &repo.Params); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
repo.Disabled = len(r.FormValue("Disabled")) == 0
|
|
|
|
repo.DisabledPullRequest = len(r.FormValue("DisabledPullRequest")) == 0
|
|
|
|
|
2014-02-17 21:48:43 +03:00
|
|
|
repo.Privileged = u.Admin && len(r.FormValue("Privileged")) > 0
|
|
|
|
|
2014-02-07 13:10:01 +03:00
|
|
|
// value of "" indicates the currently authenticated user
|
|
|
|
// should be set as the administrator.
|
|
|
|
if len(r.FormValue("Owner")) == 0 {
|
|
|
|
repo.UserID = u.ID
|
|
|
|
repo.TeamID = 0
|
|
|
|
} else {
|
|
|
|
// else the user has chosen a team
|
|
|
|
team, err := database.GetTeamSlug(r.FormValue("Owner"))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify the user is a member of the team
|
|
|
|
if member, _ := database.IsMemberAdmin(u.ID, team.ID); !member {
|
|
|
|
return fmt.Errorf("Forbidden")
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the team ID
|
|
|
|
repo.TeamID = team.ID
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// save the page
|
|
|
|
if err := database.SaveRepo(repo); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
http.Redirect(w, r, r.URL.Path, http.StatusSeeOther)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deletes a specific repository.
|
|
|
|
func RepoDeleteForm(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
|
|
|
data := struct {
|
|
|
|
Repo *Repo
|
|
|
|
User *User
|
|
|
|
}{repo, u}
|
|
|
|
return RenderTemplate(w, "repo_delete.html", &data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deletes a specific repository.
|
|
|
|
func RepoDelete(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
|
|
|
|
// the user must confirm their password before deleting
|
|
|
|
password := r.FormValue("password")
|
|
|
|
if err := u.ComparePassword(password); err != nil {
|
2014-02-10 05:09:42 +03:00
|
|
|
return RenderError(w, err, http.StatusBadRequest)
|
2014-02-07 13:10:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// delete the repo
|
|
|
|
if err := database.DeleteRepo(repo.ID); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
|
|
|
|
return nil
|
|
|
|
}
|