query and show commits by branch

This allows the same SHA to have different builds on different branches, each
separately viewable. This is useful for expressing a "pipeline" in terms of
branches, e.g. a commit starts on branch A and progress through B and C to
master, with the build script switching on branch name.

Previously viewing each build would arbitrarily choose which branch's commit
to show.
This commit is contained in:
Alex Suraci 2014-03-14 11:34:43 -07:00
parent 2241b5bb81
commit 2d837cc3db
14 changed files with 85 additions and 31 deletions

View file

@ -205,9 +205,9 @@ func setupHandlers() {
m.Post("/install", handler.ErrorHandler(handler.InstallPost))
// handlers for repository, commits and build details
m.Get("/:host/:owner/:name/commit/:commit/build/:label/out.txt", handler.RepoHandler(handler.BuildOut))
m.Get("/:host/:owner/:name/commit/:commit/build/:label", handler.RepoHandler(handler.CommitShow))
m.Get("/:host/:owner/:name/commit/:commit", handler.RepoHandler(handler.CommitShow))
m.Get("/:host/:owner/:name/commit/:branch/:commit/build/:label/out.txt", handler.RepoHandler(handler.BuildOut))
m.Get("/:host/:owner/:name/commit/:branch/:commit/build/:label", handler.RepoHandler(handler.CommitShow))
m.Get("/:host/:owner/:name/commit/:branch/:commit", handler.RepoHandler(handler.CommitShow))
m.Get("/:host/:owner/:name/tree", handler.RepoHandler(handler.RepoDashboard))
m.Get("/:host/:owner/:name/status.png", handler.ErrorHandler(handler.Badge))
m.Get("/:host/:owner/:name/settings", handler.RepoAdminHandler(handler.RepoSettingsForm))

View file

@ -38,7 +38,7 @@ FROM commits
WHERE id = ?
`
// SQL Queries to retrieve a Commit by name and repo id.
// SQL Queries to retrieve a Commit by hash and repo id.
const commitFindHashStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
@ -47,6 +47,15 @@ WHERE hash = ? AND repo_id = ?
LIMIT 1
`
// SQL Queries to retrieve a Commit by branch, hash, and repo id.
const commitFindBranchHashStmt = `
SELECT id, repo_id, status, started, finished, duration,
hash, branch, pull_request, author, gravatar, timestamp, message, created, updated
FROM commits
WHERE branch = ? AND hash = ? AND repo_id = ?
LIMIT 1
`
// SQL Query to retrieve a list of recent commits by user.
const userCommitRecentStmt = `
SELECT r.slug, r.host, r.owner, r.name,
@ -101,7 +110,7 @@ WHERE id IN (
SELECT MAX(id)
FROM commits
WHERE repo_id = ?
AND branch = ?
AND branch = ?
GROUP BY branch)
LIMIT 1
`
@ -120,6 +129,13 @@ func GetCommitHash(hash string, repo int64) (*Commit, error) {
return &commit, err
}
// Returns the Commit on the given branch with the given hash.
func GetCommitBranchHash(branch string, hash string, repo int64) (*Commit, error) {
commit := Commit{}
err := meddler.QueryRow(db, &commit, commitFindBranchHashStmt, branch, hash, repo)
return &commit, err
}
// Returns the most recent Commit for the given branch.
func GetBranch(repo int64, branch string) (*Commit, error) {
commit := Commit{}

View file

@ -44,6 +44,32 @@ func TestGetCommit(t *testing.T) {
}
}
func TestGetCommitBranchHash(t *testing.T) {
Setup()
defer Teardown()
commit, err := database.GetCommitBranchHash("develop", "5f32ec7b08dfe3a097c1a5316de5b5069fb35ff9", 2)
if err != nil {
t.Error(err)
}
if commit.ID != 5 {
t.Errorf("Exepected ID %d, got %d", 5, commit.ID)
}
if commit.Branch != "develop" {
t.Errorf("Exepected Branch %s, got %s", "develop", commit.Branch)
}
if commit.Hash != "5f32ec7b08dfe3a097c1a5316de5b5069fb35ff9" {
t.Errorf("Exepected Hash %s, got %s", "5f32ec7b08dfe3a097c1a5316de5b5069fb35ff9", commit.Hash)
}
if commit.Status != "Success" {
t.Errorf("Exepected Status %s, got %s", "Success", commit.Status)
}
}
func TestGetCommitHash(t *testing.T) {
Setup()
defer Teardown()

View file

@ -191,12 +191,22 @@ func Setup() {
Gravatar: user1.Gravatar,
Message: "commit message",
}
commit5 := Commit{
RepoID: repo2.ID,
Status: "Success",
Hash: "5f32ec7b08dfe3a097c1a5316de5b5069fb35ff9",
Branch: "develop",
Author: user1.Email,
Gravatar: user1.Gravatar,
Message: "commit message",
}
// create dummy commit data
database.SaveCommit(&commit1)
database.SaveCommit(&commit2)
database.SaveCommit(&commit3)
database.SaveCommit(&commit4)
database.SaveCommit(&commit5)
// create dummy build data
database.SaveBuild(&Build{CommitID: commit1.ID, Slug: "node_0.10", Status: "Success", Duration: 60})

View file

@ -9,11 +9,12 @@ import (
// Returns the combined stdout / stderr for an individual Build.
func BuildOut(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
branch := r.FormValue(":branch")
hash := r.FormValue(":commit")
labl := r.FormValue(":label")
// get the commit from the database
commit, err := database.GetCommitHash(hash, repo.ID)
commit, err := database.GetCommitBranchHash(branch, hash, repo.ID)
if err != nil {
return err
}

View file

@ -11,11 +11,12 @@ import (
// Display a specific Commit.
func CommitShow(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) error {
branch := r.FormValue(":branch")
hash := r.FormValue(":commit")
labl := r.FormValue(":label")
// get the commit from the database
commit, err := database.GetCommitHash(hash, repo.ID)
commit, err := database.GetCommitBranchHash(branch, hash, repo.ID)
if err != nil {
return err
}
@ -49,7 +50,7 @@ func CommitShow(w http.ResponseWriter, r *http.Request, u *User, repo *Repo) err
// generate a token to connect with the websocket
// handler and stream output, if the build is running.
data.Token = channel.Token(fmt.Sprintf(
"%s/%s/%s/commit/%s/builds/%s", repo.Host, repo.Owner, repo.Name, commit.Hash, builds[0].Slug))
"%s/%s/%s/commit/%s/%s/builds/%s", repo.Host, repo.Owner, repo.Name, commit.Branch, commit.Hash, builds[0].Slug))
// render the repository template.
return RenderTemplate(w, "repo_commit.html", &data)

View file

@ -74,7 +74,7 @@ func (h *HookHandler) Hook(w http.ResponseWriter, r *http.Request) error {
// Verify that the commit doesn't already exist.
// We should never build the same commit twice.
_, err = database.GetCommitHash(hook.Head.Id, repo.ID)
_, err = database.GetCommitBranchHash(hook.Branch(), hook.Head.Id, repo.ID)
if err != nil && err != sql.ErrNoRows {
println("commit already exists")
return RenderText(w, http.StatusText(http.StatusBadGateway), http.StatusBadGateway)

View file

@ -95,8 +95,8 @@ func (w *worker) execute(task *BuildTask) error {
// make sure a channel exists for the repository,
// the commit, and the commit output (TODO)
reposlug := fmt.Sprintf("%s/%s/%s", task.Repo.Host, task.Repo.Owner, task.Repo.Name)
commitslug := fmt.Sprintf("%s/%s/%s/commit/%s", task.Repo.Host, task.Repo.Owner, task.Repo.Name, task.Commit.Hash)
consoleslug := fmt.Sprintf("%s/%s/%s/commit/%s/builds/%s", task.Repo.Host, task.Repo.Owner, task.Repo.Name, task.Commit.Hash, task.Build.Slug)
commitslug := fmt.Sprintf("%s/%s/%s/commit/%s/%s", task.Repo.Host, task.Repo.Owner, task.Repo.Name, task.Commit.Branch, task.Commit.Hash)
consoleslug := fmt.Sprintf("%s/%s/%s/commit/%s/%s/builds/%s", task.Repo.Host, task.Repo.Owner, task.Repo.Name, task.Commit.Branch, task.Commit.Hash, task.Build.Slug)
channel.Create(reposlug)
channel.Create(commitslug)
channel.CreateStream(consoleslug)
@ -223,7 +223,7 @@ func updateGitHubStatus(repo *Repo, commit *Commit) error {
client.ApiUrl = settings.GitHubApiUrl
var url string
url = settings.URL().String() + "/" + repo.Slug + "/commit/" + commit.Hash
url = settings.URL().String() + "/" + repo.Slug + "/commit/" + commit.Branch + "/" + commit.Hash
return client.Repos.CreateStatus(repo.Owner, repo.Name, status, url, message, commit.Hash)
}

View file

@ -10,7 +10,7 @@
<table class="commit-table" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;">
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;">
<th style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; text-align: left; color: #333; margin: 0; padding: 0 30px 0 20px;" align="left">commit:</th>
<td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 99%; color: #333; margin: 0; padding: 0;"><a href="{{.Host}}/{{.Repo.Slug}}/commit/{{ .Commit.Hash }}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; color: #2a6496; font-weight: normal; margin: 0; padding: 0;">{{ .Commit.HashShort }}</a></td>
<td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 99%; color: #333; margin: 0; padding: 0;"><a href="{{.Host}}/{{.Repo.Slug}}/commit/{{.Commit.Branch}}/{{ .Commit.Hash }}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; color: #2a6496; font-weight: normal; margin: 0; padding: 0;">{{ .Commit.HashShort }}</a></td>
</tr>
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;">
<th style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; text-align: left; color: #333; margin: 0; padding: 0 30px 0 20px;" align="left">branch:</th>
@ -25,4 +25,4 @@
<td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 99%; color: #333; margin: 0; padding: 0;">{{ .Commit.Message }}</td>
</tr>
</table>
{{ end }}
{{ end }}

View file

@ -10,7 +10,7 @@
<table class="commit-table" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 100%; margin: 0; padding: 0;">
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;">
<th style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; text-align: left; color: #333; margin: 0; padding: 0 30px 0 20px;" align="left">commit:</th>
<td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 99%; color: #333; margin: 0; padding: 0;"><a href="{{.Host}}/{{.Repo.Slug}}/commit/{{ .Commit.Hash }}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; color: #2a6496; font-weight: normal; margin: 0; padding: 0;">{{ .Commit.HashShort }}</a></td>
<td style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; width: 99%; color: #333; margin: 0; padding: 0;"><a href="{{.Host}}/{{.Repo.Slug}}/commit/{{ .Commit.Branch }}/{{ .Commit.Hash }}" style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; color: #2a6496; font-weight: normal; margin: 0; padding: 0;">{{ .Commit.HashShort }}</a></td>
</tr>
<tr style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; margin: 0; padding: 0;">
<th style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; text-align: left; color: #333; margin: 0; padding: 0 30px 0 20px;" align="left">branch:</th>

View file

@ -5,7 +5,7 @@
<div class="subhead">
<div class="container">
<ul class="nav nav-tabs pull-right">
<li class="active"><a href="/{{.Repo.Slug}}/commit/{{ .Commit.Hash }}">{{ .Commit.HashShort }}</a></li>
<li class="active"><a href="/{{.Repo.Slug}}/commit/{{ .Commit.Branch }}/{{ .Commit.Hash }}">{{ .Commit.HashShort }}</a></li>
<li><a href="/{{.Repo.Slug}}">Commits</a></li>
<li><a href="/{{.Repo.Slug}}/settings">Settings</a></li>
</ul> <!-- ./nav -->
@ -18,7 +18,7 @@
<div class="container">
<div class="alert alert-build-{{ .Build.Status }}">
<a href="/{{.Repo.Slug}}/commit/{{.Commit.Hash }}" class="btn btn-{{ .Build.Status }}"></a>
<a href="/{{.Repo.Slug}}/{{.Commit.Branch}}/commit/{{ .Commit.Branch }}/{{ .Commit.Hash }}" class="btn btn-{{ .Build.Status }}"></a>
{{ if .Commit.PullRequest }}
<span>opened pull request <span># {{ .Commit.PullRequest }}</span></span>
{{ else }}
@ -78,7 +78,7 @@
});
{{ else }}
$.get("/{{ .Repo.Slug }}/commit/{{ .Commit.Hash }}/build/{{ .Build.Slug }}/out.txt", function( data ) {
$.get("/{{ .Repo.Slug }}/commit/{{ .Commit.Branch }}/{{ .Commit.Hash }}/build/{{ .Build.Slug }}/out.txt", function( data ) {
var lineFormatter = new Drone.LineFormatter();
$( "#stdout" ).html(lineFormatter.format(data));
});

View file

@ -28,12 +28,12 @@
<ul class="commit-list commit-list-alt">
{{ range .Commits }}
<li>
<a href="/{{$repo.Slug}}/commit/{{.Hash}}" class="btn btn-{{.Status}}"></a>
<a href="/{{$repo.Slug}}/commit/{{.Branch}}/{{.Hash}}" class="btn btn-{{.Status}}"></a>
<h3>
<a href="/{{$repo.Slug}}/commit/{{.Hash}}">{{.HashShort}}</a>
<a href="/{{$repo.Slug}}/commit/{{.Branch}}/{{.Hash}}">{{.HashShort}}</a>
<small class="timeago" title="{{.CreatedString}}"></small>
{{ if .PullRequest }}
<p>opened pull request <a href="/{{$repo.Slug}}/commit/{{.Hash}}"># {{.PullRequest}}</a></p>
<p>opened pull request <a href="/{{$repo.Slug}}/commit/{{.Branch}}/{{.Hash}}"># {{.PullRequest}}</a></p>
{{ else }}
<p>{{.Message}} &nbsp;</p>
{{ end }}

View file

@ -45,14 +45,14 @@
<ul class="commit-list">
{{ range $commit := .Commits }}
<li>
<a href="/{{$commit.Slug}}/commit/{{$commit.Hash}}" class="btn btn-{{$commit.Status}}"></a>
<a href="/{{$commit.Slug}}/commit/{{$commit.Branch}}/{{$commit.Hash}}" class="btn btn-{{$commit.Status}}"></a>
<h3>
<a href="/{{$commit.Slug}}">{{$commit.Owner}} / {{$commit.Name}}</a>
<small class="timeago" title="{{$commit.CreatedString}}"></small>
{{ if $commit.PullRequest }}
<p>opened pull request <a href="/{{$commit.Slug}}/commit/{{$commit.Hash}}"># {{$commit.PullRequest}}</a></p>
<p>opened pull request <a href="/{{$commit.Slug}}/commit/{{$commit.Branch}}/{{$commit.Hash}}"># {{$commit.PullRequest}}</a></p>
{{ else }}
<p>commit <a href="/{{$commit.Slug}}/commit/{{$commit.Hash}}">{{$commit.HashShort}}</a> to <a href="/{{$commit.Slug}}?branch={{$commit.Branch}}">{{$commit.Branch}}</a> branch</p>
<p>commit <a href="/{{$commit.Slug}}/commit/{{$commit.Branch}}/{{$commit.Hash}}">{{$commit.HashShort}}</a> to <a href="/{{$commit.Slug}}?branch={{$commit.Branch}}">{{$commit.Branch}}</a> branch</p>
{{ end }}
</h3>
</li>
@ -88,7 +88,7 @@
<script>
if (window.localStorage) {
// get the last visited date from local storage
var lastVisited = localStorage["lastVisited"];
var lastVisited = localStorage["lastVisited"];
if (lastVisited == "null" || lastVisited == NaN || !lastVisited) {
lastVisited = Date.parse("1970-01-01T00:00:00Z");
} else {
@ -108,4 +108,4 @@
});
}
</script>
{{ end }}
{{ end }}

View file

@ -43,14 +43,14 @@
<ul class="commit-list">
{{ range $commit := .Commits }}
<li>
<a href="/{{$commit.Slug}}/commit/{{$commit.Hash}}" class="btn btn-{{$commit.Status}}"></a>
<a href="/{{$commit.Slug}}/commit/{{$commit.Branch}}/{{$commit.Hash}}" class="btn btn-{{$commit.Status}}"></a>
<h3>
<a href="/{{$commit.Slug}}">{{$commit.Owner}} / {{$commit.Name}}</a>
<small class="timeago" title="{{$commit.CreatedString}}"></small>
{{ if $commit.PullRequest }}
<p>opened pull request <a href="/{{$commit.Slug}}/commit/{{$commit.Hash}}"># {{$commit.PullRequest}}</a></p>
<p>opened pull request <a href="/{{$commit.Slug}}/commit/{{$commit.Branch}}/{{$commit.Hash}}"># {{$commit.PullRequest}}</a></p>
{{ else }}
<p>commit <a href="/{{$commit.Slug}}/commit/{{$commit.Hash}}">{{$commit.HashShort}}</a> to <a href="/{{$commit.Slug}}?branch={{$commit.Branch}}">{{$commit.Branch}}</a> branch</p>
<p>commit <a href="/{{$commit.Slug}}/commit/{{$commit.Branch}}/{{$commit.Hash}}">{{$commit.HashShort}}</a> to <a href="/{{$commit.Slug}}?branch={{$commit.Branch}}">{{$commit.Branch}}</a> branch</p>
{{ end }}
</h3>
</li>
@ -86,8 +86,8 @@
<script>
if (window.localStorage) {
// get the last visited date from local storage
var lastVisited = localStorage["lastVisited"];
var lastVisited = localStorage["lastVisited"];
if (lastVisited == "null" || lastVisited == NaN || !lastVisited) {
lastVisited = Date.parse("1970-01-01T00:00:00Z");
} else {