Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Brad Rydzewski 2015-02-12 23:37:12 -08:00
commit a0aaed0955
16 changed files with 229 additions and 26 deletions

30
cli/delete.go Normal file
View file

@ -0,0 +1,30 @@
package main
import (
"github.com/codegangsta/cli"
"github.com/drone/drone/client"
)
// NewDeleteCommand returns the CLI command for "delete".
func NewDeleteCommand() cli.Command {
return cli.Command{
Name: "delete",
Usage: "delete a repository",
Flags: []cli.Flag{},
Action: func(c *cli.Context) {
handle(c, deleteCommandFunc)
},
}
}
// deleteCommandFunc executes the "delete" command.
func deleteCommandFunc(c *cli.Context, client *client.Client) error {
var host, owner, name string
var args = c.Args()
if len(args) != 0 {
host, owner, name = parseRepo(args[0])
}
return client.Repos.Delete(host, owner, name)
}

View file

@ -1,8 +1,9 @@
package main
import (
"github.com/codegangsta/cli"
"os"
"github.com/codegangsta/cli"
)
var (
@ -40,6 +41,7 @@ func main() {
NewRestartCommand(),
NewWhoamiCommand(),
NewSetKeyCommand(),
NewDeleteCommand(),
}
app.Run(os.Args)

View file

@ -32,8 +32,14 @@ func (s *RepoService) Enable(host, owner, name string) error {
return s.run("POST", path, nil, nil)
}
// DELETE /api/repos/{host}/{owner}/{name}
// POST /api/repos/{host}/{owner}/{name}/deactivate
func (s *RepoService) Disable(host, owner, name string) error {
var path = fmt.Sprintf("/api/repos/%s/%s/%s/deactivate", host, owner, name)
return s.run("POST", path, nil, nil)
}
// DELETE /api/repos/{host}/{owner}/{name}?remove=true
func (s *RepoService) Delete(host, owner, name string) error {
var path = fmt.Sprintf("/api/repos/%s/%s/%s", host, owner, name)
return s.run("DELETE", path, nil, nil)
}

View file

@ -241,6 +241,25 @@ func (r *Bitbucket) Activate(user *model.User, repo *model.Repo, link string) er
return err
}
// Deactivate removes a repository by removing all the post-commit hooks
// which are equal to link and removing the SSH deploy key.
func (r *Bitbucket) Deactivate(user *model.User, repo *model.Repo, link string) error {
var client = bitbucket.New(
r.Client,
r.Secret,
user.Access,
user.Secret,
)
title, err := GetKeyTitle(link)
if err != nil {
return err
}
if err := client.RepoKeys.DeleteName(repo.Owner, repo.Name, title); err != nil {
return err
}
return client.Brokers.DeleteUrl(repo.Owner, repo.Name, link, bitbucket.BrokerTypePost)
}
// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
func (r *Bitbucket) ParseHook(req *http.Request) (*model.Hook, error) {
@ -279,3 +298,13 @@ func (r *Bitbucket) OpenRegistration() bool {
func (r *Bitbucket) GetToken(user *model.User) (*model.Token, error) {
return nil, nil
}
// GetKeyTitle is a helper function that generates a title for the
// RSA public key based on the username and domain name.
func GetKeyTitle(rawurl string) (string, error) {
var uri, err = url.Parse(rawurl)
if err != nil {
return "", err
}
return fmt.Sprintf("drone@%s", uri.Host), nil
}

View file

@ -102,7 +102,7 @@ func (r *GitHub) Authorize(res http.ResponseWriter, req *http.Request) (*model.L
return nil, fmt.Errorf("Could not check org membership. %s", err)
}
if !allowedOrg {
return nil, fmt.Errorf("User does not belong to correct org")
return nil, fmt.Errorf("User does not belong to correct org. Must belong to %v", r.Orgs)
}
}
@ -169,6 +169,7 @@ func (r *GitHub) GetRepos(user *model.User) ([]*model.Repo, error) {
if r.Private || repo.Private {
repo.CloneURL = *item.SSHURL
repo.Private = true
}
// if no permissions we should skip the repository
@ -193,6 +194,23 @@ func (r *GitHub) GetScript(user *model.User, repo *model.Repo, hook *model.Hook)
return GetFile(client, repo.Owner, repo.Name, ".drone.yml", hook.Sha)
}
// Deactivate removes a repository by removing all the post-commit hooks
// which are equal to link and removing the SSH deploy key.
func (r *GitHub) Deactivate(user *model.User, repo *model.Repo, link string) error {
var client = NewClient(r.API, user.Access, r.SkipVerify)
var title, err = GetKeyTitle(link)
if err != nil {
return err
}
// remove the deploy-key if it is installed remote.
if err := DeleteKey(client, repo.Owner, repo.Name, title, repo.PublicKey); err != nil {
return err
}
return DeleteHook(client, repo.Owner, repo.Name, link)
}
// Activate activates a repository by adding a Post-commit hook and
// a Public Deploy key, if applicable.
func (r *GitHub) Activate(user *model.User, repo *model.Repo, link string) error {

View file

@ -173,6 +173,16 @@ func GetHook(client *github.Client, owner, name, url string) (*github.Hook, erro
return nil, nil
}
func DeleteHook(client *github.Client, owner, name, url string) error {
hook, err := GetHook(client, owner, name, url)
if err != nil {
return err
}
_, err = client.Repositories.DeleteHook(owner, name, *hook.ID)
return err
}
// CreateHook is a heper function that creates a post-commit hook
// for the specified repository.
func CreateHook(client *github.Client, owner, name, url string) (*github.Hook, error) {
@ -230,7 +240,18 @@ func GetKeyTitle(rawurl string) (string, error) {
return fmt.Sprintf("drone@%s", uri.Host), nil
}
// CreateKey is a heper function that creates a deploy key
// DeleteKey is a helper function that deletes a deploy key
// for the specified repository.
func DeleteKey(client *github.Client, owner, name, title, key string) error {
var k, err = GetKey(client, owner, name, title)
if err != nil {
return err
}
_, err = client.Repositories.DeleteKey(owner, name, *k.ID)
return err
}
// CreateKey is a helper function that creates a deploy key
// for the specified repository.
func CreateKey(client *github.Client, owner, name, title, key string) (*github.Key, error) {
var k = new(github.Key)
@ -240,7 +261,7 @@ func CreateKey(client *github.Client, owner, name, title, key string) (*github.K
return created, err
}
// CreateUpdateKey is a heper function that creates a deployment key
// CreateUpdateKey is a helper function that creates a deployment key
// for the specified repository if it does not already exist, otherwise
// it updates the existing key
func CreateUpdateKey(client *github.Client, owner, name, title, key string) (*github.Key, error) {

View file

@ -6,6 +6,7 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
"time"
"code.google.com/p/goauth2/oauth"
@ -179,6 +180,41 @@ func (r *Gitlab) Activate(user *model.User, repo *model.Repo, link string) error
return client.AddProjectHook(path, link, true, false, true)
}
// Deactivate removes a repository by removing all the post-commit hooks
// which are equal to link and removing the SSH deploy key.
func (r *Gitlab) Deactivate(user *model.User, repo *model.Repo, link string) error {
var client = NewClient(r.url, user.Access, r.SkipVerify)
var path = ns(repo.Owner, repo.Name)
keys, err := client.ProjectDeployKeys(path)
if err != nil {
return err
}
var pubkey = strings.TrimSpace(repo.PublicKey)
for _, k := range keys {
if pubkey == strings.TrimSpace(k.Key) {
if err := client.RemoveProjectDeployKey(path, strconv.Itoa(k.Id)); err != nil {
return err
}
break
}
}
hooks, err := client.ProjectHooks(path)
if err != nil {
return err
}
link += "?owner=" + repo.Owner + "&name=" + repo.Name
for _, h := range hooks {
if link == h.Url {
if err := client.RemoveProjectHook(path, strconv.Itoa(h.Id)); err != nil {
return err
}
break
}
}
return nil
}
// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
func (r *Gitlab) ParseHook(req *http.Request) (*model.Hook, error) {

View file

@ -153,6 +153,12 @@ func (r *Gogs) Activate(user *model.User, repo *model.Repo, link string) error {
return err
}
// Deactivate removes a repository by removing all the post-commit hooks
// which are equal to link and removing the SSH deploy key.
func (r *Gogs) Deactivate(user *model.User, repo *model.Repo, link string) error {
return fmt.Errorf("Remove %#v in gogs not implemented", *repo)
}
// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
func (r *Gogs) ParseHook(req *http.Request) (*model.Hook, error) {

View file

@ -29,6 +29,10 @@ type Remote interface {
// adding the SSH deploy key, if applicable.
Activate(user *model.User, repo *model.Repo, link string) error
// Deactivate removes a repository by removing all the post-commit hooks
// which are equal to link and removing the SSH deploy key.
Deactivate(user *model.User, repo *model.Repo, link string) error
// ParseHook parses the post-commit hook from the Request body
// and returns the required data in a standard format.
ParseHook(r *http.Request) (*model.Hook, error)

View file

@ -29,6 +29,7 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.8/angular-resource.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.6.0/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-moment/0.9.0/angular-moment.min.js"></script>
<!-- main javascript application -->
<script src="/static/scripts/line_formatter.js"></script>

View file

@ -2,9 +2,14 @@
var app = angular.module('app', [
'ngRoute',
'ui.filters'
'ui.filters',
'angularMoment'
]);
angular.module('app').constant('angularMomentConfig', {
preprocess: 'unix'
});
// First, parse the query string
var params = {}, queryString = location.hash.substring(1),
regex = /([^&=]+)=([^&]*)/g, m;

View file

@ -25,7 +25,7 @@
/**
* toDate is a helper function that returns a human readable
* string gor the given unix date.
* string for the given unix date.
*/
function toDate() {
return function(date) {

View file

@ -8,14 +8,14 @@
</div>
<dl ng-if="commit.duration != 0">
<dd><h1>{{ commit.duration | toDuration}}</h1></dd>
<dd><h1>{{ commit.duration | amDurationFormat:'seconds':false }}</h1></dd>
</dl>
<dl ng-include="'/static/views/commit_detail.html'" ng-show="commit.pull_request.length == 0"></dl>
<dl ng-include="'/static/views/commit_detail_pr.html'" ng-show="commit.pull_request.length != 0"></dl>
<dd ng-if="commit.finished_at != 0">{{ commit.finished_at | fromNow }}</dd>
<dd ng-if="commit.finished_at == 0 && commit.started_at != 0">Started {{ commit.started_at | fromNow }}</dd>
<dd ng-if="commit.finished_at == 0 && commit.started_at == 0">Created {{ commit.created_at}}</dd>
<dd ng-if="commit.finished_at != 0" am-time-ago="{{ commit.finished_at }}"></dd>
<dd ng-if="commit.finished_at == 0 && commit.started_at != 0">Started <span am-time-ago="{{ commit.started_at }}"></span></dd>
<dd ng-if="commit.finished_at == 0 && commit.started_at == 0">Created <span am-time-ago="{{ commit.created_at }}"></span></dd>
</div>
</aside>

View file

@ -70,11 +70,11 @@
<td><a href='{{ repo.url }}/commit/{{ commit.sha }}'>{{ commit.sha | shortHash }}</a> (<a href='{{ repo.url }}/tree/{{ commit.branch }}'>{{ commit.branch }}</a>)</td>
<td>{{ commit.author }}</td>
<td ng-if="commit.finished_at != 0" title="{{ commit.duration }} seconds">{{ commit.duration | toDuration }}</td>
<td ng-if="commit.finished_at == 0 && commit.started_at != 0">{{ commit.started_at | fromNow }}</td>
<td ng-if="commit.finished_at == 0 && commit.started_at == 0">-</td>
<td ng-if="commit.finished_at != 0" title="{{ commit.duration }} seconds">{{ commit.duration | amDurationFormat:'seconds':false }}</td>
<td ng-if="commit.finished_at == 0 && commit.started_at != 0" am-time-ago="{{ commit.started_at }}" am-without-suffix="true"></td>
<td ng-if="commit.finished_at == 0 && commit.started_at == 0" am-time-ago="{{ commit.created_at }}" am-without-suffix="true"></td>
<td ng-if="commit.finished_at != 0" title="{{ commit.finished_at * 1000 | date:'medium' }}">{{ commit.finished_at | fromNow }}</td>
<td ng-if="commit.finished_at != 0" title="{{ commit.finished_at * 1000 | date:'medium' }}" am-time-ago="{{ commit.finished_at }}"></td>
<td ng-if="commit.finished_at == 0">-</td>
</tr>
</tbody>
@ -88,24 +88,24 @@
<a class="pure-u-1 pure-u-md-1-4 pure-u-lg-1-4 pure-u-xl-1-4 card card" ng-href="/{{ repo | fullPath }}/{{ commit.branch }}/{{ commit.sha }}" ng-repeat="commit in commits | filter:{ branch:group.branch }:true | limitTo:4" data-status="{{ commit.status }}">
<div class="l-box">
<h2>{{ commit.message }}</h2>
<em ng-if="commit.finished_at != 0">{{ commit.author }}<br/>{{ commit.finished_at | fromNow }}</em>
<em ng-if="commit.finished_at == 0 && commit.started_at != 0">{{ commit.author }}<br/>Started {{ commit.started_at | fromNow }}</em>
<em ng-if="commit.finished_at == 0 && commit.started_at == 0">{{ commit.author }}<br/>Created {{ commit.created_at}}</em>
<em ng-if="commit.finished_at != 0">{{ commit.author }}<br/><span am-time-ago="{{ commit.finished_at }}"></span></em>
<em ng-if="commit.finished_at == 0 && commit.started_at != 0">{{ commit.author }}<br/>Started <span am-time-ago="{{ commit.started_at }}"></span></em>
<em ng-if="commit.finished_at == 0 && commit.started_at == 0">{{ commit.author }}<br/>Created <span am-time-ago="{{ commit.created_at }}"></span></em>
<img ng-src="{{ commit.gravatar | gravatar }}" />
</div>
</a>
</div>
</section>
<section ng-if="(commits | pullRequests).length!=0 && layout == 'grid'"">
<section ng-if="(commits | pullRequests).length!=0 && layout == 'grid'">
<div class="pure-g cards">
<h2 class="pure-u-1" style="font-size:22px;margin-bottom:20px;"><i class="fa fa-code-fork"></i> Pull Requests</h2>
<a class="pure-u-1 pure-u-md-1-4 pure-u-lg-1-4 pure-u-xl-1-4 card card" ng-href="/{{ repo | fullPath }}/{{ commit.branch }}/{{ commit.sha }}" ng-repeat="commit in commits | pullRequests | limitTo:4" data-status="{{ commit.status }}">
<div class="l-box">
<h2>{{ commit.message }}</h2>
<em ng-if="commit.finished_at != 0">{{ commit.author }}<br/>{{ commit.finished_at | fromNow }}</em>
<em ng-if="commit.finished_at == 0 && commit.started_at != 0">{{ commit.author }}<br/>Started {{ commit.started_at | fromNow }}</em>
<em ng-if="commit.finished_at == 0 && commit.started_at == 0">{{ commit.author }}<br/>Created {{ commit.created_at}}</em>
<em ng-if="commit.finished_at != 0">{{ commit.author }}<br/><span am-time-ago="{{ commit.finished_at }}"></span></em>
<em ng-if="commit.finished_at == 0 && commit.started_at != 0">{{ commit.author }}<br/>Started <span am-time-ago="{{ commit.started_at }}"></span></em>
<em ng-if="commit.finished_at == 0 && commit.started_at == 0">{{ commit.author }}<br/>Created <span am-time-ago="{{ commit.created_at }}"></span></em>
<img ng-src="{{ commit.gravatar | gravatar }}" />
</div>
</a>

View file

@ -3,6 +3,7 @@ package handler
import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/drone/drone/plugin/remote"
@ -42,9 +43,8 @@ func GetRepo(c web.C, w http.ResponseWriter, r *http.Request) {
}{repo, repo.PublicKey, repo.Params, role})
}
// DelRepo accepts a request to inactivate the named
// repository. This will disable all builds in the system
// for this repository.
// DelRepo accepts a request to delete the named
// repository.
//
// DEL /api/repos/:host/:owner/:name
//
@ -52,6 +52,50 @@ func DelRepo(c web.C, w http.ResponseWriter, r *http.Request) {
var ctx = context.FromC(c)
var repo = ToRepo(c)
// completely remove the repository from the database
var user = ToUser(c)
var remote = remote.Lookup(repo.Host)
if remote == nil {
log.Printf("[ERROR] no remote for host '%s' found", repo.Host)
} else {
// Request a new token and update
user_token, err := remote.GetToken(user)
if err != nil {
log.Printf("[ERROR] no token for user '%s' on remote '%s' ", user.Email, repo.Host)
} else {
if user_token != nil {
user.Access = user_token.AccessToken
user.Secret = user_token.RefreshToken
user.TokenExpiry = user_token.Expiry
datastore.PutUser(ctx, user)
}
// setup the post-commit hook with the remote system and
// and deactiveate this hook/user on the remote system
var hook = fmt.Sprintf("%s/api/hook/%s/%s", httputil.GetURL(r), repo.Remote, repo.Token)
if err := remote.Deactivate(user, repo, hook); err != nil {
log.Printf("[ERROR] deactivate on remote '%s' failed: %s", repo.Host, err)
}
}
}
// fail through: if any of the actions on the remote failed
// we try to delete the repo in our datastore anyway
if err := datastore.DelRepo(ctx, repo); err != nil {
w.WriteHeader(http.StatusInternalServerError)
} else {
w.WriteHeader(http.StatusNoContent)
}
}
// DeactivateRepo accepts a request to deactivate the named
// repository. This will disable all builds in the system
// for this repository.
//
// POST /api/repos/:host/:owner/:name/deactivate
//
func DeactivateRepo(c web.C, w http.ResponseWriter, r *http.Request) {
var ctx = context.FromC(c)
var repo = ToRepo(c)
// disable everything
repo.Active = false
repo.PullRequest = false
@ -62,7 +106,7 @@ func DelRepo(c web.C, w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
json.NewEncoder(w).Encode(repo)
}
// PostRepo accapets a request to activate the named repository

View file

@ -46,6 +46,7 @@ func New() *web.Mux {
repos.Put("/api/repos/:host/:owner/:name", handler.PutRepo)
repos.Post("/api/repos/:host/:owner/:name", handler.PostRepo)
repos.Delete("/api/repos/:host/:owner/:name", handler.DelRepo)
repos.Post("/api/repos/:host/:owner/:name/deactivate", handler.DeactivateRepo)
mux.Handle("/api/repos/:host/:owner/:name", repos)
mux.Handle("/api/repos/:host/:owner/:name/*", repos)