Skip to content

Commit

Permalink
Detail view (runatlantis#47)
Browse files Browse the repository at this point in the history
* Adding the ability to get lock data and show it using the detail view in the ui for boltdb

* adding modal style

* Adding new modal based discard ui

* Adding detail view and get lock funtionality with unlocking with the UI

* lots of clean up after review

* using jquery most places now

* missed in merge

* this should cause a build failure

* moving e2e test as part of the test override step so they run if unit tests fail

* fixing boltdb tests

* turns out you can't fail fast in circleci

* don't compare locks
  • Loading branch information
anubhavmishra authored Jun 25, 2017
1 parent 57e1839 commit 7f8f85a
Show file tree
Hide file tree
Showing 14 changed files with 457 additions and 160 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BUILD_ID := $(shell git rev-parse --short HEAD 2>/dev/null || echo no-commit-id)
WORKSPACE := $(shell pwd)
PKG := $(shell go list ./... | grep -v e2e | grep -v vendor)
PKG := $(shell go list ./... | grep -v e2e | grep -v vendor | grep -v static)

.PHONY: test

Expand Down
4 changes: 2 additions & 2 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ test:
override:
# Run tests
- cd "${WORKDIR}" && ./scripts/build.sh

# Run e2e tests

post:
# Run e2e tests
- cd "${WORKDIR}" && ./scripts/e2e-deps.sh
# Start atlantis server
- cd "${WORKDIR}/e2e" && ./atlantis server --gh-user="$GITHUB_USERNAME" --gh-password="$GITHUB_PASSWORD" --data-dir="/tmp" --require-approval=false --plan-backend="file" --log-level="debug" &> /tmp/atlantis-server.log:
Expand Down
29 changes: 25 additions & 4 deletions locking/boltdb/boltdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/boltdb/bolt"
"github.com/hootsuite/atlantis/models"
"github.com/pkg/errors"
"os"
"path"
"time"

"github.com/boltdb/bolt"
"github.com/hootsuite/atlantis/models"
"github.com/pkg/errors"
)

type Backend struct {
Expand Down Expand Up @@ -139,7 +140,7 @@ func (b Backend) UnlockByPull(repoFullName string, pullNum int) ([]models.Projec
for k, v := c.Seek([]byte(repoFullName)); k != nil && bytes.HasPrefix(k, []byte(repoFullName)); k, v = c.Next() {
var lock models.ProjectLock
if err := json.Unmarshal(v, &lock); err != nil {
return errors.Wrapf(err, "failed to deserialize lock at key %q", string(k))
return errors.Wrapf(err, "deserializing lock at key %q", string(k))
}
if lock.Pull.Num == pullNum {
locks = append(locks, lock)
Expand All @@ -157,6 +158,26 @@ func (b Backend) UnlockByPull(repoFullName string, pullNum int) ([]models.Projec
return locks, nil
}

func (b Backend) GetLock(p models.Project, env string) (models.ProjectLock, error) {
key := b.key(p, env)
var lockBytes []byte
err := b.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(b.bucket)
lockBytes = b.Get([]byte(key))
return nil
})
if err != nil {
return models.ProjectLock{}, errors.Wrap(err, "getting lock data")
}

var lock models.ProjectLock
if err := json.Unmarshal(lockBytes, &lock); err != nil {
return models.ProjectLock{}, errors.Wrapf(err, "deserializing lock at key %q", key)
}

return lock, nil
}

func (b Backend) key(p models.Project, env string) string {
return fmt.Sprintf("%s/%s/%s", p.RepoFullName, p.Path, env)
}
57 changes: 39 additions & 18 deletions locking/boltdb/boltdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ package boltdb_test
import (
. "github.com/hootsuite/atlantis/testing_util"

"github.com/boltdb/bolt"
"github.com/pkg/errors"
"io/ioutil"
"os"
"testing"

"github.com/boltdb/bolt"
"github.com/pkg/errors"

"time"

"github.com/hootsuite/atlantis/locking/boltdb"
"github.com/hootsuite/atlantis/models"
"time"
)

var lockBucket = "bucket"
Expand All @@ -25,9 +27,9 @@ var lock = models.ProjectLock{
User: models.User{
Username: "lkysow",
},
Env: env,
Env: env,
Project: project,
Time: time.Now(),
Time: time.Now(),
}

func TestListNoLocks(t *testing.T) {
Expand Down Expand Up @@ -158,8 +160,9 @@ func TestUnlockingNoLocks(t *testing.T) {
t.Log("unlocking with no locks should succeed")
db, b := newTestDB()
defer cleanupDB(db)
_, err := b.Unlock(project, env)

Ok(t, b.Unlock(project, env))
Ok(t, err)
}

func TestUnlocking(t *testing.T) {
Expand All @@ -168,7 +171,8 @@ func TestUnlocking(t *testing.T) {
defer cleanupDB(db)

b.TryLock(lock)
Ok(t, b.Unlock(project, env))
_, err := b.Unlock(project, env)
Ok(t, err)

// should be no locks listed
ls, err := b.List()
Expand Down Expand Up @@ -204,10 +208,14 @@ func TestUnlockingMultiple(t *testing.T) {
b.TryLock(new3)

// now try and unlock them
Ok(t, b.Unlock(new3.Project, new3.Env))
Ok(t, b.Unlock(new2.Project, env))
Ok(t, b.Unlock(new.Project, env))
Ok(t, b.Unlock(project, env))
_, err := b.Unlock(new3.Project, new3.Env)
Ok(t, err)
_, err = b.Unlock(new2.Project, env)
Ok(t, err)
_, err = b.Unlock(new.Project, env)
Ok(t, err)
_, err = b.Unlock(project, env)
Ok(t, err)

// should be none left
ls, err := b.List()
Expand All @@ -220,7 +228,7 @@ func TestUnlockByPullNone(t *testing.T) {
db, b := newTestDB()
defer cleanupDB(db)

err := b.UnlockByPull("any/repo", 1)
_, err := b.UnlockByPull("any/repo", 1)
Ok(t, err)
}

Expand All @@ -233,23 +241,23 @@ func TestUnlockByPullOne(t *testing.T) {

t.Log("...delete nothing when its the same repo but a different pull")
{
err := b.UnlockByPull(project.RepoFullName, pullNum+1)
_, err := b.UnlockByPull(project.RepoFullName, pullNum+1)
Ok(t, err)
ls, err := b.List()
Ok(t, err)
Equals(t, 1, len(ls))
}
t.Log("...delete nothing when its the same pull but a different repo")
{
err := b.UnlockByPull("different/repo", pullNum)
_, err := b.UnlockByPull("different/repo", pullNum)
Ok(t, err)
ls, err := b.List()
Ok(t, err)
Equals(t, 1, len(ls))
}
t.Log("...delete the lock when its the same repo and pull")
{
err := b.UnlockByPull(project.RepoFullName, pullNum)
_, err := b.UnlockByPull(project.RepoFullName, pullNum)
Ok(t, err)
ls, err := b.List()
Ok(t, err)
Expand All @@ -263,9 +271,10 @@ func TestUnlockByPullAfterUnlock(t *testing.T) {
defer cleanupDB(db)
_, _, err := b.TryLock(lock)
Ok(t, err)
Ok(t, b.Unlock(project, env))
_, err = b.Unlock(project, env)
Ok(t, err)

err = b.UnlockByPull(project.RepoFullName, pullNum)
_, err = b.UnlockByPull(project.RepoFullName, pullNum)
Ok(t, err)
ls, err := b.List()
Ok(t, err)
Expand Down Expand Up @@ -295,13 +304,25 @@ func TestUnlockByPullMatching(t *testing.T) {
Equals(t, 3, len(ls))

// should all be unlocked
err = b.UnlockByPull(project.RepoFullName, pullNum)
_, err = b.UnlockByPull(project.RepoFullName, pullNum)
Ok(t, err)
ls, err = b.List()
Ok(t, err)
Equals(t, 0, len(ls))
}

// todo: Write more tests for getting lock data
func TestGetLock(t *testing.T) {
t.Log("get data for a existing lock")
db, b := newTestDB()
defer cleanupDB(db)
_, _, err := b.TryLock(lock)
Ok(t, err)

_, err = b.GetLock(project, env)
Ok(t, err)
}

// newTestDB returns a TestDB using a temporary path.
func newTestDB() (*bolt.DB, *boltdb.Backend) {
// Retrieve a temporary path.
Expand Down
73 changes: 49 additions & 24 deletions locking/dynamodb/dynamodb.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ package dynamodb

import (
"fmt"
"strconv"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
"github.com/hootsuite/atlantis/models"
"github.com/pkg/errors"
"strconv"
"time"
)

type Backend struct {
Expand All @@ -23,18 +24,18 @@ type Backend struct {
// and also so any changes to models won't affect
// how we're storing our data (or will at least cause a compile error)
type dynamoLock struct {
LockKey string
RepoFullName string
Path string
LockKey string
RepoFullName string
Path string
PullNum int
PullHeadCommit string
PullBaseCommit string
PullURL string
PullBranch string
PullAuthor string
UserUsername string
Env string
Time time.Time
UserUsername string
Env string
Time time.Time
}

func New(lockTable string, p client.ConfigProvider) Backend {
Expand Down Expand Up @@ -142,6 +143,30 @@ func (b Backend) List() ([]models.ProjectLock, error) {
return locks, errors.Wrap(err, "scanning dynamodb")
}

func (b Backend) GetLock(p models.Project, env string) (models.ProjectLock, error) {
key := b.key(p, env)
params := &dynamodb.GetItemInput{
Key: map[string]*dynamodb.AttributeValue{
"LockKey": {
S: aws.String(key),
},
},
TableName: aws.String(b.LockTable),
ConsistentRead: aws.Bool(true),
}
item, err := b.DB.GetItem(params)
if err != nil {
return models.ProjectLock{}, errors.Wrapf(err, "getting item %q", item)
}

var dynamoDBLock dynamoLock
if err := dynamodbattribute.UnmarshalMap(item.Item, &dynamoDBLock); err != nil {
return models.ProjectLock{}, errors.Wrap(err, "found a lock at that key but it could not be deserialized. We suggest manually deleting this key from DynamoDB")
}

return b.fromDynamo(dynamoDBLock), nil
}

func (b Backend) UnlockByPull(repoFullName string, pullNum int) ([]models.ProjectLock, error) {
params := &dynamodb.ScanInput{
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
Expand Down Expand Up @@ -186,39 +211,39 @@ func (b Backend) UnlockByPull(repoFullName string, pullNum int) ([]models.Projec

func (b Backend) toDynamo(key string, l models.ProjectLock) dynamoLock {
return dynamoLock{
LockKey: key,
RepoFullName: l.Project.RepoFullName,
Path: l.Project.Path,
PullNum: l.Pull.Num,
LockKey: key,
RepoFullName: l.Project.RepoFullName,
Path: l.Project.Path,
PullNum: l.Pull.Num,
PullHeadCommit: l.Pull.HeadCommit,
PullBaseCommit: l.Pull.BaseCommit,
PullURL: l.Pull.URL,
PullBranch: l.Pull.Branch,
PullAuthor: l.Pull.Author,
UserUsername: l.User.Username,
Env: l.Env,
Time: time.Now(),
PullURL: l.Pull.URL,
PullBranch: l.Pull.Branch,
PullAuthor: l.Pull.Author,
UserUsername: l.User.Username,
Env: l.Env,
Time: time.Now(),
}
}

func (b Backend) fromDynamo(d dynamoLock) models.ProjectLock {
return models.ProjectLock{
Pull: models.PullRequest{
Author: d.PullAuthor,
Branch: d.PullBranch,
URL: d.PullURL,
Author: d.PullAuthor,
Branch: d.PullBranch,
URL: d.PullURL,
BaseCommit: d.PullBaseCommit,
HeadCommit: d.PullHeadCommit,
Num: d.PullNum,
Num: d.PullNum,
},
User: models.User{
Username: d.UserUsername,
},
Project: models.Project{
RepoFullName: d.RepoFullName,
Path: d.Path,
Path: d.Path,
},
Time: d.Time,
Env: d.Env,
Env: d.Env,
}
}
Loading

0 comments on commit 7f8f85a

Please sign in to comment.