From 4d1df2924cc34f0aef99894ceaeaa9a5c8f9b506 Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Fri, 8 Jul 2016 15:40:29 -0700 Subject: [PATCH] replace UI with single page application (#1704) --- .drone.yml | 14 +- .drone.yml.sig | 2 +- .gitignore | 3 +- Makefile | 18 +- cache/helper.go | 14 + client/client.go | 3 + client/client_impl.go | 9 + contrib/debian/drone/DEBIAN/conffiles | 2 - contrib/debian/drone/DEBIAN/control | 7 - contrib/debian/drone/DEBIAN/postinst | 24 - contrib/debian/drone/DEBIAN/prerm | 26 - contrib/debian/drone/etc/drone/dronerc | 31 -- contrib/debian/drone/etc/init/drone.conf | 12 - contrib/docker/etc/nsswitch.conf | 19 - contrib/generate-amber.go | 6 - contrib/generate-js.go | 60 -- contrib/setup-sassc.sh | 21 - contrib/setup-sqlite.sh | 18 - router/router.go | 76 +-- server/login.go | 6 +- server/pages.go | 201 +------ server/stream.go | 188 ++++++- server/template/files/index.html | 22 + server/template/files/login.html | 20 + server/template/files/logout.html | 1 + server/template/template.go | 31 ++ static/images/docker.svg | 70 --- static/images/docker_blue.svg | 70 --- static/images/docker_white.svg | 13 - static/images/dummy.png | Bin 5376 -> 0 bytes static/images/favicon.ico | Bin 1150 -> 0 bytes static/images/favicon.png | Bin 366 -> 0 bytes static/images/logo_dark.svg | 93 ---- static/images/logo_light.svg | 93 ---- static/images/ubuntu.svg | 7 - static/scripts/build.js | 200 ------- static/scripts/csrf.js | 11 - static/scripts/models.js | 90 --- static/scripts/nodes.js | 74 --- static/scripts/repo.js | 155 ------ static/scripts/repos.js | 31 -- static/scripts/search.js | 66 --- static/scripts/term.js | 397 -------------- static/scripts/term_buf.js | 52 -- static/scripts/users.js | 78 --- static/scripts/utils.js | 15 - static/scripts/vendor/livestamp.js | 138 ----- static/scripts/vendor/plates.js | 666 ----------------------- static/scripts_gen/.gitkeep | 0 static/static.go | 27 - static/styles/header.sass | 0 static/styles/modules/badges.sass | 2 - static/styles/modules/navbar.sass | 56 -- static/styles/modules/range.sass | 95 ---- static/styles/modules/status.sass | 46 -- static/styles/modules/subnav.sass | 95 ---- static/styles/modules/switch.sass | 43 -- static/styles/modules/timeline.sass | 86 --- static/styles/pages/build.sass | 195 ------- static/styles/pages/docs.sass | 331 ----------- static/styles/pages/feed.sass | 57 -- static/styles/pages/login.sass | 120 ---- static/styles/pages/repo.sass | 101 ---- static/styles/pages/user.sass | 44 -- static/styles/pages/users.sass | 71 --- static/styles/search.sass | 56 -- static/styles/style.sass | 108 ---- static/styles_gen/.gitkeep | 0 static/styles_gen/style.css | 492 ----------------- template/amber/400.amber | 8 - template/amber/401.amber | 8 - template/amber/403.amber | 8 - template/amber/404.amber | 8 - template/amber/500.amber | 8 - template/amber/_feed.amber | 71 --- template/amber/_users.amber | 97 ---- template/amber/base.amber | 54 -- template/amber/build.amber | 99 ---- template/amber/docs.amber | 40 -- template/amber/index.amber | 46 -- template/amber/login.amber | 35 -- template/amber/login_form.amber | 24 - template/amber/nodes.amber | 52 -- template/amber/repo.amber | 59 -- template/amber/repo_activate.amber | 33 -- template/amber/repo_badge.amber | 37 -- template/amber/repo_config.amber | 77 --- template/amber/repo_secret.amber | 45 -- template/amber/repos.amber | 47 -- template/amber/swagger.amber | 76 --- template/amber/user.amber | 33 -- template/amber/users.amber | 40 -- template/amber_gen/.gitkeep | 0 template/template.go | 59 -- 94 files changed, 330 insertions(+), 5912 deletions(-) delete mode 100644 contrib/debian/drone/DEBIAN/conffiles delete mode 100644 contrib/debian/drone/DEBIAN/control delete mode 100755 contrib/debian/drone/DEBIAN/postinst delete mode 100755 contrib/debian/drone/DEBIAN/prerm delete mode 100644 contrib/debian/drone/etc/drone/dronerc delete mode 100644 contrib/debian/drone/etc/init/drone.conf delete mode 100644 contrib/docker/etc/nsswitch.conf delete mode 100644 contrib/generate-amber.go delete mode 100644 contrib/generate-js.go delete mode 100755 contrib/setup-sassc.sh delete mode 100755 contrib/setup-sqlite.sh create mode 100644 server/template/files/index.html create mode 100644 server/template/files/login.html create mode 100644 server/template/files/logout.html create mode 100644 server/template/template.go delete mode 100644 static/images/docker.svg delete mode 100644 static/images/docker_blue.svg delete mode 100644 static/images/docker_white.svg delete mode 100644 static/images/dummy.png delete mode 100644 static/images/favicon.ico delete mode 100644 static/images/favicon.png delete mode 100644 static/images/logo_dark.svg delete mode 100644 static/images/logo_light.svg delete mode 100644 static/images/ubuntu.svg delete mode 100644 static/scripts/build.js delete mode 100644 static/scripts/csrf.js delete mode 100644 static/scripts/models.js delete mode 100644 static/scripts/nodes.js delete mode 100644 static/scripts/repo.js delete mode 100644 static/scripts/repos.js delete mode 100644 static/scripts/search.js delete mode 100644 static/scripts/term.js delete mode 100644 static/scripts/term_buf.js delete mode 100644 static/scripts/users.js delete mode 100644 static/scripts/utils.js delete mode 100644 static/scripts/vendor/livestamp.js delete mode 100644 static/scripts/vendor/plates.js delete mode 100644 static/scripts_gen/.gitkeep delete mode 100644 static/static.go delete mode 100644 static/styles/header.sass delete mode 100644 static/styles/modules/badges.sass delete mode 100644 static/styles/modules/navbar.sass delete mode 100644 static/styles/modules/range.sass delete mode 100644 static/styles/modules/status.sass delete mode 100644 static/styles/modules/subnav.sass delete mode 100644 static/styles/modules/switch.sass delete mode 100644 static/styles/modules/timeline.sass delete mode 100644 static/styles/pages/build.sass delete mode 100644 static/styles/pages/docs.sass delete mode 100644 static/styles/pages/feed.sass delete mode 100644 static/styles/pages/login.sass delete mode 100644 static/styles/pages/repo.sass delete mode 100644 static/styles/pages/user.sass delete mode 100644 static/styles/pages/users.sass delete mode 100644 static/styles/search.sass delete mode 100644 static/styles/style.sass delete mode 100644 static/styles_gen/.gitkeep delete mode 100644 static/styles_gen/style.css delete mode 100644 template/amber/400.amber delete mode 100644 template/amber/401.amber delete mode 100644 template/amber/403.amber delete mode 100644 template/amber/404.amber delete mode 100644 template/amber/500.amber delete mode 100644 template/amber/_feed.amber delete mode 100644 template/amber/_users.amber delete mode 100644 template/amber/base.amber delete mode 100644 template/amber/build.amber delete mode 100644 template/amber/docs.amber delete mode 100644 template/amber/index.amber delete mode 100644 template/amber/login.amber delete mode 100644 template/amber/login_form.amber delete mode 100644 template/amber/nodes.amber delete mode 100644 template/amber/repo.amber delete mode 100644 template/amber/repo_activate.amber delete mode 100644 template/amber/repo_badge.amber delete mode 100644 template/amber/repo_config.amber delete mode 100644 template/amber/repo_secret.amber delete mode 100644 template/amber/repos.amber delete mode 100644 template/amber/swagger.amber delete mode 100644 template/amber/user.amber delete mode 100644 template/amber/users.amber delete mode 100644 template/amber_gen/.gitkeep delete mode 100644 template/template.go diff --git a/.drone.yml b/.drone.yml index 6dbe2be95..b00d04a34 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,23 +1,21 @@ workspace: - base: /drone + base: /go path: src/github.com/drone/drone pipeline: - test: - image: drone/golang:1.5 + backend: + image: golang:1.6 environment: - GO15VENDOREXPERIMENT=1 - - GOPATH=/drone commands: - - export PATH=$PATH:$GOPATH/bin - make deps gen - make test test_postgres test_mysql - build: - image: drone/golang:1.5 + compile: + image: golang:1.6 environment: - GO15VENDOREXPERIMENT=1 - - GOPATH=/drone + - GOPATH=/go commands: - export PATH=$PATH:$GOPATH/bin - make build diff --git a/.drone.yml.sig b/.drone.yml.sig index 3b267ac3e..4f1196374 100644 --- a/.drone.yml.sig +++ b/.drone.yml.sig @@ -1 +1 @@ -eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9kcm9uZQogIHBhdGg6IHNyYy9naXRodWIuY29tL2Ryb25lL2Ryb25lCgpwaXBlbGluZToKICB0ZXN0OgogICAgaW1hZ2U6IGRyb25lL2dvbGFuZzoxLjUKICAgIGVudmlyb25tZW50OgogICAgICAtIEdPMTVWRU5ET1JFWFBFUklNRU5UPTEKICAgICAgLSBHT1BBVEg9L2Ryb25lCiAgICBjb21tYW5kczoKICAgICAgLSBleHBvcnQgUEFUSD0kUEFUSDokR09QQVRIL2JpbgogICAgICAtIG1ha2UgZGVwcyBnZW4KICAgICAgLSBtYWtlIHRlc3QgdGVzdF9wb3N0Z3JlcyB0ZXN0X215c3FsCgogIGJ1aWxkOgogICAgaW1hZ2U6IGRyb25lL2dvbGFuZzoxLjUKICAgIGVudmlyb25tZW50OgogICAgICAtIEdPMTVWRU5ET1JFWFBFUklNRU5UPTEKICAgICAgLSBHT1BBVEg9L2Ryb25lCiAgICBjb21tYW5kczoKICAgICAgLSBleHBvcnQgUEFUSD0kUEFUSDokR09QQVRIL2JpbgogICAgICAtIG1ha2UgYnVpbGQKICAgIHdoZW46CiAgICAgIGV2ZW50OiBwdXNoCgogIHB1Ymxpc2g6CiAgICBpbWFnZTogczMKICAgIGFjbDogcHVibGljLXJlYWQKICAgIGJ1Y2tldDogZG93bmxvYWRzLmRyb25lLmlvCiAgICBzb3VyY2U6IHJlbGVhc2UvKiovKi4qCiAgICB3aGVuOgogICAgICBldmVudDogcHVzaAogICAgICBicmFuY2g6IG1hc3RlcgoKICBkb2NrZXI6CiAgICByZXBvOiBkcm9uZS9kcm9uZQogICAgdGFnOiBbICIwLjUuMCIsICIwLjUiIF0KICAgIHN0b3JhZ2VfZHJpdmVyOiBvdmVybGF5CiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3RlcgogICAgICBldmVudDogcHVzaAoKc2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogcG9zdGdyZXM6OS40LjUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9cG9zdGdyZXMKICBteXNxbDoKICAgIGltYWdlOiBteXNxbDo1LjYuMjcKICAgIGVudmlyb25tZW50OgogICAgICAtIE1ZU1FMX0RBVEFCQVNFPXRlc3QKICAgICAgLSBNWVNRTF9BTExPV19FTVBUWV9QQVNTV09SRD15ZXMK.PFyNsvPRNRtL_9Tlgsqa0IDMIgzUrlk53eV4QJjZ3hU \ No newline at end of file +eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9nbwogIHBhdGg6IHNyYy9naXRodWIuY29tL2Ryb25lL2Ryb25lCgpwaXBlbGluZToKICBiYWNrZW5kOgogICAgaW1hZ2U6IGdvbGFuZzoxLjYKICAgIGVudmlyb25tZW50OgogICAgICAtIEdPMTVWRU5ET1JFWFBFUklNRU5UPTEKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgZGVwcyBnZW4KICAgICAgLSBtYWtlIHRlc3QgdGVzdF9wb3N0Z3JlcyB0ZXN0X215c3FsCgogIGNvbXBpbGU6CiAgICBpbWFnZTogZ29sYW5nOjEuNgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gR08xNVZFTkRPUkVYUEVSSU1FTlQ9MQogICAgICAtIEdPUEFUSD0vZ28KICAgIGNvbW1hbmRzOgogICAgICAtIGV4cG9ydCBQQVRIPSRQQVRIOiRHT1BBVEgvYmluCiAgICAgIC0gbWFrZSBidWlsZAogICAgd2hlbjoKICAgICAgZXZlbnQ6IHB1c2gKCiAgcHVibGlzaDoKICAgIGltYWdlOiBzMwogICAgYWNsOiBwdWJsaWMtcmVhZAogICAgYnVja2V0OiBkb3dubG9hZHMuZHJvbmUuaW8KICAgIHNvdXJjZTogcmVsZWFzZS8qKi8qLioKICAgIHdoZW46CiAgICAgIGV2ZW50OiBwdXNoCiAgICAgIGJyYW5jaDogbWFzdGVyCgogIGRvY2tlcjoKICAgIHJlcG86IGRyb25lL2Ryb25lCiAgICB0YWc6IFsgIjAuNS4wIiwgIjAuNSIgXQogICAgc3RvcmFnZV9kcml2ZXI6IG92ZXJsYXkKICAgIHdoZW46CiAgICAgIGJyYW5jaDogbWFzdGVyCiAgICAgIGV2ZW50OiBwdXNoCgpzZXJ2aWNlczoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3Jlczo5LjQuNQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj1wb3N0Z3JlcwogIG15c3FsOgogICAgaW1hZ2U6IG15c3FsOjUuNi4yNwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTVlTUUxfREFUQUJBU0U9dGVzdAogICAgICAtIE1ZU1FMX0FMTE9XX0VNUFRZX1BBU1NXT1JEPXllcwo.kQIwqIgs7PnoKIGmzJ6hlbWTbV5zK0w4HVWsux79P3s \ No newline at end of file diff --git a/.gitignore b/.gitignore index 229b1e184..0166e230d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ drone/drone *.sqlite *_gen.go -*.html #*.css *.txt *.zip @@ -13,6 +12,8 @@ drone/drone temp/ release/ +server/frontend/bower_components +server/frontend/build server/swagger/files/*.json # vendored repositories that we don't actually need diff --git a/Makefile b/Makefile index 41282b7b7..6ae874ea5 100644 --- a/Makefile +++ b/Makefile @@ -10,22 +10,20 @@ endif all: gen build_static -deps: +deps: deps_backend deps_frontend + +deps_frontend: + go get -u github.com/drone/drone-ui/dist + +deps_backend: go get -u golang.org/x/tools/cmd/cover - go get -u github.com/eknkc/amber/... - go get -u github.com/eknkc/amber go get -u github.com/jteeuwen/go-bindata/... go get -u github.com/elazarl/go-bindata-assetfs/... - go get -u github.com/dchest/jsmin - go get -u github.com/franela/goblin -gen: gen_static gen_template gen_migrations - -gen_static: - go generate github.com/drone/drone/static +gen: gen_template gen_migrations gen_template: - go generate github.com/drone/drone/template + go generate github.com/drone/drone/server/template gen_migrations: go generate github.com/drone/drone/store/datastore/ddl diff --git a/cache/helper.go b/cache/helper.go index abf1d91c9..f4def328e 100644 --- a/cache/helper.go +++ b/cache/helper.go @@ -53,6 +53,20 @@ func GetRepos(c context.Context, user *model.User) ([]*model.RepoLite, error) { return repos, nil } +// GetRepoMap returns the list of user repositories from the cache +// associated with the current context in a map structure. +func GetRepoMap(c context.Context, user *model.User) (map[string]bool, error) { + repos, err := GetRepos(c, user) + if err != nil { + return nil, err + } + repom := map[string]bool{} + for _, repo := range repos { + repom[repo.FullName] = true + } + return repom, nil +} + // DeleteRepos evicts the cached user repositories from the cache associated // with the current context. func DeleteRepos(c context.Context, user *model.User) error { diff --git a/client/client.go b/client/client.go index bf1ea1553..c1f4834bd 100644 --- a/client/client.go +++ b/client/client.go @@ -43,6 +43,9 @@ type Client interface { // RepoPatch updates a repository. RepoPatch(*model.Repo) (*model.Repo, error) + // RepoChown updates a repository owner. + RepoChown(string, string) (*model.Repo, error) + // RepoDel deletes a repository. RepoDel(string, string) error diff --git a/client/client_impl.go b/client/client_impl.go index 7fa3099c7..ac6b42513 100644 --- a/client/client_impl.go +++ b/client/client_impl.go @@ -32,6 +32,7 @@ const ( pathFeed = "%s/api/user/feed" pathRepos = "%s/api/user/repos" pathRepo = "%s/api/repos/%s/%s" + pathChown = "%s/api/repos/%s/%s/chown" pathEncrypt = "%s/api/repos/%s/%s/encrypt" pathBuilds = "%s/api/repos/%s/%s/builds" pathBuild = "%s/api/repos/%s/%s/builds/%v" @@ -153,6 +154,14 @@ func (c *client) RepoPost(owner string, name string) (*model.Repo, error) { return out, err } +// RepoChow updates a repository owner. +func (c *client) RepoChown(owner string, name string) (*model.Repo, error) { + out := new(model.Repo) + uri := fmt.Sprintf(pathChown, c.base, owner, name) + err := c.post(uri, nil, out) + return out, err +} + // RepoPatch updates a repository. func (c *client) RepoPatch(in *model.Repo) (*model.Repo, error) { out := new(model.Repo) diff --git a/contrib/debian/drone/DEBIAN/conffiles b/contrib/debian/drone/DEBIAN/conffiles deleted file mode 100644 index 91e7ed3c9..000000000 --- a/contrib/debian/drone/DEBIAN/conffiles +++ /dev/null @@ -1,2 +0,0 @@ -/etc/init/drone.conf -/etc/drone/dronerc diff --git a/contrib/debian/drone/DEBIAN/control b/contrib/debian/drone/DEBIAN/control deleted file mode 100644 index 3f0a756a6..000000000 --- a/contrib/debian/drone/DEBIAN/control +++ /dev/null @@ -1,7 +0,0 @@ -Package: drone -Version: 0.4 -Section: base -Priority: optional -Architecture: amd64 -Maintainer: Brad Rydzewski -Description: Drone continuous integration server diff --git a/contrib/debian/drone/DEBIAN/postinst b/contrib/debian/drone/DEBIAN/postinst deleted file mode 100755 index fd835bb8a..000000000 --- a/contrib/debian/drone/DEBIAN/postinst +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -set -e - -case "$1" in - abort-upgrade|abort-remove|abort-deconfigure|configure) - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -echo "Starting drone ..." -if [ -f /etc/init/drone.conf ]; then - if pidof /usr/local/bin/drone >/dev/null; then - service drone stop || exit $? - fi - service drone start && echo "Drone started." -fi - -#DEBHELPER# - -exit 0 diff --git a/contrib/debian/drone/DEBIAN/prerm b/contrib/debian/drone/DEBIAN/prerm deleted file mode 100755 index a0f7be8cb..000000000 --- a/contrib/debian/drone/DEBIAN/prerm +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -set -e -set -u - -case "$1" in - remove|remove-in-favour|deconfigure|deconfigure-in-favour) - if [ -f /etc/init/drone.conf ]; then - echo "Stopping drone ..." - service drone stop || exit $? - echo "Drone Stopped." - fi - ;; - - upgrade|failed-upgrade) - ;; - - *) - echo "prerm called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -#DEBHELPER# - -exit 0 diff --git a/contrib/debian/drone/etc/drone/dronerc b/contrib/debian/drone/etc/drone/dronerc deleted file mode 100644 index b20198427..000000000 --- a/contrib/debian/drone/etc/drone/dronerc +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# server configuration - -SERVER_ADDR=":80" -#SERVER_CERT="" -#SERVER_KEY="" - -# database configuration - -DATABASE_DRIVER="sqlite3" -DATABASE_CONFIG="/var/lib/drone/drone.sqlite" - -# remote configuration - -CLIENT="" # oauth2 client. REQUIRED -SECRET="" # oauth2 secret. REQUIRED - -REMOTE_DRIVER="github" -REMOTE_CONFIG="https://github.com?client_id=$CLIENT&client_secret=$SECRET" - -# docker configuration - -DOCKER_HOST="unix:///var/run/docker.sock" -#DOCKER_CERT="" -#DOCKER_KEY="" -#DOCKER_CA="" - -# plugin configuration - -PLUGIN_FILTER="plugins/*" diff --git a/contrib/debian/drone/etc/init/drone.conf b/contrib/debian/drone/etc/init/drone.conf deleted file mode 100644 index 7ca816794..000000000 --- a/contrib/debian/drone/etc/init/drone.conf +++ /dev/null @@ -1,12 +0,0 @@ -start on (filesystem and net-device-up) - -chdir /var/lib/drone -console log - -script - set -a - if [ -f /etc/drone/dronerc ]; then - . /etc/drone/dronerc - fi - /usr/local/bin/drone -end script diff --git a/contrib/docker/etc/nsswitch.conf b/contrib/docker/etc/nsswitch.conf deleted file mode 100644 index cb918b774..000000000 --- a/contrib/docker/etc/nsswitch.conf +++ /dev/null @@ -1,19 +0,0 @@ -# /etc/nsswitch.conf -# -# Example configuration of GNU Name Service Switch functionality. -# If you have the `glibc-doc-reference' and `info' packages installed, try: -# `info libc "Name Service Switch"' for information about this file. - -passwd: compat -group: compat -shadow: compat - -hosts: files dns -networks: files - -protocols: files -services: files -ethers: files -rpc: files - -netgroup: nis diff --git a/contrib/generate-amber.go b/contrib/generate-amber.go deleted file mode 100644 index 8e6175469..000000000 --- a/contrib/generate-amber.go +++ /dev/null @@ -1,6 +0,0 @@ -// +build ignore - -// This program converts amber templates to standard -// Go template files. - -package main diff --git a/contrib/generate-js.go b/contrib/generate-js.go deleted file mode 100644 index 7e77d3260..000000000 --- a/contrib/generate-js.go +++ /dev/null @@ -1,60 +0,0 @@ -// +build ignore - -// This program minifies JavaScript files -// $ go run generate-js.go -dir scripts/ -out scripts/drone.min.js - -package main - -import ( - "bytes" - "flag" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - - "github.com/dchest/jsmin" -) - -var ( - dir = flag.String("dir", "scripts/", "") - out = flag.String("o", "scripts/drone.min.js", "") -) - -func main() { - flag.Parse() - - var buf bytes.Buffer - - // walk the directory tree and write all - // javascript files to the buffer. - filepath.Walk(*dir, func(path string, info os.FileInfo, err error) error { - if filepath.Ext(path) != ".js" { - return nil - } - - f, err := os.Open(path) - if err != nil { - return nil - } - defer f.Close() - - // write the file name to the minified output - fmt.Fprintf(&buf, "// %s\n", path) - - // copy the file to the buffer - _, err = io.Copy(&buf, f) - return err - }) - - // minifies the javascript - data, err := jsmin.Minify(buf.Bytes()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - // write the minified output - ioutil.WriteFile(*out, data, 0700) -} diff --git a/contrib/setup-sassc.sh b/contrib/setup-sassc.sh deleted file mode 100755 index 85659f90c..000000000 --- a/contrib/setup-sassc.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -set -e - -cd /tmp - -# cleanup previously downloaded and unpacked files. -rm -rf libsass -rm -rf sassc - -# download the latest build of sassc -git clone --depth=1 git://github.com/sass/libsass.git -git clone --depth=1 git://github.com/sass/sassc.git - -export SASS_LIBSASS_PATH=/tmp/libsass - -# build the sassc binary -cd sassc -make - -# isntall the sassc binary -install -t /usr/local/bin bin/sassc diff --git a/contrib/setup-sqlite.sh b/contrib/setup-sqlite.sh deleted file mode 100755 index f68eba117..000000000 --- a/contrib/setup-sqlite.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -e - -cd /tmp - -# cleanup previously downloaded and unpacked files. -rm -rf sqlite-autoconf-3081101.tar.gz -rm -rf sqlite-autoconf-3081101 - -# download sqlite -curl -O https://www.sqlite.org/2015/sqlite-autoconf-3081101.tar.gz -tar xzf sqlite-autoconf-3081101.tar.gz - -# build and install -cd sqlite-autoconf-3081101 -./configure -prefix=/scratch/usr/local -make -make install diff --git a/router/router.go b/router/router.go index a6f89f2bf..84410dfc8 100644 --- a/router/router.go +++ b/router/router.go @@ -2,7 +2,6 @@ package router import ( "net/http" - "strings" "github.com/gin-gonic/gin" @@ -10,17 +9,19 @@ import ( "github.com/drone/drone/router/middleware/session" "github.com/drone/drone/router/middleware/token" "github.com/drone/drone/server" - "github.com/drone/drone/static" - "github.com/drone/drone/template" + "github.com/drone/drone/server/template" + + "github.com/drone/drone-ui/dist" ) +// Load loads the router func Load(middleware ...gin.HandlerFunc) http.Handler { e := gin.New() e.Use(gin.Recovery()) e.SetHTMLTemplate(template.Load()) - e.StaticFS("/static", static.FileSystem()) + e.StaticFS("/static", dist.AssetFS()) e.Use(header.NoCache) e.Use(header.Options) @@ -29,35 +30,11 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { e.Use(session.SetUser()) e.Use(token.Refresh) - e.GET("/", server.ShowIndex) - e.GET("/repos", server.ShowAllRepos) e.GET("/login", server.ShowLogin) e.GET("/login/form", server.ShowLoginForm) e.GET("/logout", server.GetLogout) + e.NoRoute(server.ShowIndex) - // TODO below will Go away with React UI - settings := e.Group("/settings") - { - settings.Use(session.MustUser()) - settings.GET("/profile", server.ShowUser) - } - repo := e.Group("/repos/:owner/:name") - { - repo.Use(session.SetRepo()) - repo.Use(session.SetPerm()) - repo.Use(session.MustPull) - - repo.GET("", server.ShowRepo) - repo.GET("/builds/:number", server.ShowBuild) - repo.GET("/builds/:number/:job", server.ShowBuild) - - repo_settings := repo.Group("/settings") - { - repo_settings.GET("", session.MustPush, server.ShowRepoConf) - repo_settings.GET("/encrypt", session.MustPush, server.ShowRepoEncrypt) - repo_settings.GET("/badges", server.ShowRepoBadges) - } - } // TODO above will Go away with React UI user := e.Group("/api/user") @@ -129,6 +106,16 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { stream.GET("/:owner/:name", server.GetRepoEvents) stream.GET("/:owner/:name/:build/:number", server.GetStream) } + ws := e.Group("/ws") + { + ws.GET("/feed", server.EventStream) + ws.GET("/logs/:owner/:name/:build/:number", + session.SetRepo(), + session.SetPerm(), + session.MustPull, + server.LogStream, + ) + } auth := e.Group("/authorize") { @@ -184,34 +171,5 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { // bots.POST("/slack/:command", Slack) // } - return normalize(e) -} - -// THIS HACK JOB IS GOING AWAY SOON. -// -// normalize is a helper function to work around the following -// issue with gin. https://github.com/gin-gonic/gin/issues/388 -func normalize(h http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - parts := strings.Split(r.URL.Path, "/")[1:] - switch parts[0] { - case "settings", "bots", "repos", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab": - // no-op - default: - - if len(parts) > 2 && parts[2] != "settings" { - parts = append(parts[:2], append([]string{"builds"}, parts[2:]...)...) - } - - // prefix the URL with /repo so that it - // can be effectively routed. - parts = append([]string{"", "repos"}, parts...) - - // reconstruct the path - r.URL.Path = strings.Join(parts, "/") - } - - h.ServeHTTP(w, r) - }) + return e } diff --git a/server/login.go b/server/login.go index af784222e..55dfbfce3 100644 --- a/server/login.go +++ b/server/login.go @@ -110,11 +110,7 @@ func GetLogin(c *gin.Context) { } httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenstr) - redirect := httputil.GetCookie(c.Request, "user_last") - if len(redirect) == 0 { - redirect = "/" - } - c.Redirect(303, redirect) + c.Redirect(303, "/") } diff --git a/server/pages.go b/server/pages.go index 4d765face..74a73c206 100644 --- a/server/pages.go +++ b/server/pages.go @@ -1,192 +1,15 @@ package server import ( - "net/http" - "strconv" - "time" - "github.com/gin-gonic/gin" - "github.com/drone/drone/cache" - "github.com/drone/drone/model" "github.com/drone/drone/router/middleware/session" - "github.com/drone/drone/shared/httputil" "github.com/drone/drone/shared/token" - "github.com/drone/drone/store" ) +// ShowIndex serves the main Drone application page. func ShowIndex(c *gin.Context) { user := session.User(c) - if user == nil { - c.Redirect(http.StatusSeeOther, "/login") - return - } - - // get the repository list from the cache - repos, err := cache.GetRepos(c, user) - if err != nil { - c.String(400, err.Error()) - return - } - - // filter to only show the currently active ones - activeRepos, err := store.GetRepoListOf(c, repos) - if err != nil { - c.String(400, err.Error()) - return - } - - c.HTML(200, "index.html", gin.H{ - "User": user, - "Repos": activeRepos, - }) -} - -func ShowAllRepos(c *gin.Context) { - user := session.User(c) - if user == nil { - c.Redirect(http.StatusSeeOther, "/login") - return - } - - // get the repository list from the cache - repos, err := cache.GetRepos(c, user) - if err != nil { - c.String(400, err.Error()) - return - } - - c.HTML(200, "repos.html", gin.H{ - "User": user, - "Repos": repos, - }) -} - -func ShowLogin(c *gin.Context) { - c.HTML(200, "login.html", gin.H{"Error": c.Query("error")}) -} - -func ShowLoginForm(c *gin.Context) { - c.HTML(200, "login_form.html", gin.H{}) -} - -func ShowUser(c *gin.Context) { - user := session.User(c) - token, _ := token.New( - token.CsrfToken, - user.Login, - ).Sign(user.Hash) - - c.HTML(200, "user.html", gin.H{ - "User": user, - "Csrf": token, - }) -} - -func ShowRepo(c *gin.Context) { - user := session.User(c) - repo := session.Repo(c) - - builds, _ := store.GetBuildList(c, repo) - groups := []*model.BuildGroup{} - - var curr *model.BuildGroup - for _, build := range builds { - date := time.Unix(build.Created, 0).Format("Jan 2 2006") - if curr == nil || curr.Date != date { - curr = &model.BuildGroup{} - curr.Date = date - groups = append(groups, curr) - } - curr.Builds = append(curr.Builds, build) - } - - httputil.SetCookie(c.Writer, c.Request, "user_last", repo.FullName) - - c.HTML(200, "repo.html", gin.H{ - "User": user, - "Repo": repo, - "Builds": builds, - "Groups": groups, - }) - -} - -func ShowRepoConf(c *gin.Context) { - - user := session.User(c) - repo := session.Repo(c) - - token, _ := token.New( - token.CsrfToken, - user.Login, - ).Sign(user.Hash) - - c.HTML(200, "repo_config.html", gin.H{ - "User": user, - "Repo": repo, - "Csrf": token, - "Link": httputil.GetURL(c.Request), - }) -} - -func ShowRepoEncrypt(c *gin.Context) { - user := session.User(c) - repo := session.Repo(c) - - token, _ := token.New( - token.CsrfToken, - user.Login, - ).Sign(user.Hash) - - c.HTML(200, "repo_secret.html", gin.H{ - "User": user, - "Repo": repo, - "Csrf": token, - }) -} - -func ShowRepoBadges(c *gin.Context) { - user := session.User(c) - repo := session.Repo(c) - - c.HTML(200, "repo_badge.html", gin.H{ - "User": user, - "Repo": repo, - "Link": httputil.GetURL(c.Request), - }) -} - -func ShowBuild(c *gin.Context) { - user := session.User(c) - repo := session.Repo(c) - num, _ := strconv.Atoi(c.Param("number")) - seq, _ := strconv.Atoi(c.Param("job")) - if seq == 0 { - seq = 1 - } - - build, err := store.GetBuildNumber(c, repo, num) - if err != nil { - c.AbortWithError(404, err) - return - } - - jobs, err := store.GetJobList(c, build) - if err != nil { - c.AbortWithError(404, err) - return - } - - var job *model.Job - for _, j := range jobs { - if j.Number == seq { - job = j - break - } - } - - httputil.SetCookie(c.Writer, c.Request, "user_last", repo.FullName) var csrf string if user != nil { @@ -196,12 +19,20 @@ func ShowBuild(c *gin.Context) { ).Sign(user.Hash) } - c.HTML(200, "build.html", gin.H{ - "User": user, - "Repo": repo, - "Build": build, - "Jobs": jobs, - "Job": job, - "Csrf": csrf, + c.HTML(200, "index.html", gin.H{ + "user": user, + "csrf": csrf, }) } + +// ShowLogin is a legacy endpoint that now redirects to +// initiliaze the oauth flow +func ShowLogin(c *gin.Context) { + c.Redirect(303, "/authorize") +} + +// ShowLoginForm displays a login form for systems like Gogs that do not +// yet support oauth workflows. +func ShowLoginForm(c *gin.Context) { + c.HTML(200, "login.html", gin.H{}) +} diff --git a/server/stream.go b/server/stream.go index aae7bf2fd..b80bbc73a 100644 --- a/server/stream.go +++ b/server/stream.go @@ -5,17 +5,18 @@ import ( "encoding/json" "io" "strconv" - - "github.com/gin-gonic/gin" + "time" "github.com/drone/drone/bus" + "github.com/drone/drone/cache" "github.com/drone/drone/model" "github.com/drone/drone/router/middleware/session" "github.com/drone/drone/store" "github.com/drone/drone/stream" - log "github.com/Sirupsen/logrus" - + "github.com/Sirupsen/logrus" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" "github.com/manucorporat/sse" ) @@ -30,14 +31,14 @@ func GetRepoEvents(c *gin.Context) { defer func() { bus.Unsubscribe(c, eventc) close(eventc) - log.Infof("closed event stream") + logrus.Infof("closed event stream") }() c.Stream(func(w io.Writer) bool { select { case event := <-eventc: if event == nil { - log.Infof("nil event received") + logrus.Infof("nil event received") return false } @@ -75,13 +76,13 @@ func GetStream(c *gin.Context) { build, err := store.GetBuildNumber(c, repo, buildn) if err != nil { - log.Debugln("stream cannot get build number.", err) + logrus.Debugln("stream cannot get build number.", err) c.AbortWithError(404, err) return } job, err := store.GetJobNumber(c, build, jobn) if err != nil { - log.Debugln("stream cannot get job number.", err) + logrus.Debugln("stream cannot get job number.", err) c.AbortWithError(404, err) return } @@ -112,5 +113,174 @@ func GetStream(c *gin.Context) { c.Writer.Flush() } - log.Debugf("Closed stream %s#%d", repo.FullName, build.Number) + logrus.Debugf("Closed stream %s#%d", repo.FullName, build.Number) +} + +var ( + // Time allowed to write the file to the client. + writeWait = 5 * time.Second + + // Time allowed to read the next pong message from the client. + pongWait = 60 * time.Second + + // Send pings to client with this period. Must be less than pongWait. + pingPeriod = 30 * time.Second +) + +// LogStream streams the build log output to the client. +func LogStream(c *gin.Context) { + repo := session.Repo(c) + buildn, _ := strconv.Atoi(c.Param("build")) + jobn, _ := strconv.Atoi(c.Param("number")) + + c.Writer.Header().Set("Content-Type", "text/event-stream") + + build, err := store.GetBuildNumber(c, repo, buildn) + if err != nil { + logrus.Debugln("stream cannot get build number.", err) + c.AbortWithError(404, err) + return + } + job, err := store.GetJobNumber(c, build, jobn) + if err != nil { + logrus.Debugln("stream cannot get job number.", err) + c.AbortWithError(404, err) + return + } + if job.Status != model.StatusRunning { + logrus.Debugln("stream not found.") + c.AbortWithStatus(404) + return + } + + ws, err := upgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + logrus.Errorf("Cannot upgrade websocket. %s", err) + } + return + } + logrus.Debugf("Successfull upgraded websocket") + + ticker := time.NewTicker(pingPeriod) + defer ticker.Stop() + + rc, err := stream.Reader(c, stream.ToKey(job.ID)) + if err != nil { + c.AbortWithError(404, err) + return + } + + quitc := make(chan bool) + defer func() { + quitc <- true + close(quitc) + rc.Close() + ws.Close() + logrus.Debug("Successfully closed websocket") + }() + + go func() { + defer func() { + recover() + }() + for { + select { + case <-quitc: + return + case <-ticker.C: + err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)) + if err != nil { + return + } + } + } + }() + + var scanner = bufio.NewScanner(rc) + var b []byte + for scanner.Scan() { + b = scanner.Bytes() + if len(b) == 0 { + continue + } + ws.SetWriteDeadline(time.Now().Add(writeWait)) + ws.WriteMessage(websocket.TextMessage, b) + } +} + +// EventStream produces the User event stream, sending all repository, build +// and agent events to the client. +func EventStream(c *gin.Context) { + ws, err := upgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + logrus.Errorf("Cannot upgrade websocket. %s", err) + } + return + } + logrus.Debugf("Successfull upgraded websocket") + + user := session.User(c) + repo := map[string]bool{} + if user != nil { + repo, _ = cache.GetRepoMap(c, user) + } + + ticker := time.NewTicker(pingPeriod) + quitc := make(chan bool) + eventc := make(chan *bus.Event, 10) + bus.Subscribe(c, eventc) + defer func() { + ticker.Stop() + bus.Unsubscribe(c, eventc) + quitc <- true + close(quitc) + close(eventc) + ws.Close() + logrus.Debug("Successfully closed websocket") + }() + + go func() { + defer func() { + recover() + }() + for { + select { + case <-quitc: + return + case event := <-eventc: + if event == nil { + return + } + if repo[event.Repo.FullName] || !event.Repo.IsPrivate { + ws.SetWriteDeadline(time.Now().Add(writeWait)) + ws.WriteJSON(event) + } + case <-ticker.C: + err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)) + if err != nil { + return + } + } + } + }() + + reader(ws) +} + +func reader(ws *websocket.Conn) { + defer ws.Close() + ws.SetReadLimit(512) + ws.SetReadDeadline(time.Now().Add(pongWait)) + ws.SetPongHandler(func(string) error { + ws.SetReadDeadline(time.Now().Add(pongWait)) + return nil + }) + for { + _, _, err := ws.ReadMessage() + if err != nil { + break + } + } } diff --git a/server/template/files/index.html b/server/template/files/index.html new file mode 100644 index 000000000..248343c87 --- /dev/null +++ b/server/template/files/index.html @@ -0,0 +1,22 @@ + + + + + + + {{ if .csrf }}{{ end }} + + + + + + + +
+ + + + + diff --git a/server/template/files/login.html b/server/template/files/login.html new file mode 100644 index 000000000..134a67aaa --- /dev/null +++ b/server/template/files/login.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + +
+ + + +
+ + + diff --git a/server/template/files/logout.html b/server/template/files/logout.html new file mode 100644 index 000000000..209daa7b0 --- /dev/null +++ b/server/template/files/logout.html @@ -0,0 +1 @@ +LOGOUT diff --git a/server/template/template.go b/server/template/template.go new file mode 100644 index 000000000..014605d95 --- /dev/null +++ b/server/template/template.go @@ -0,0 +1,31 @@ +package template + +//go:generate go-bindata -pkg template -o template_gen.go files/ + +import ( + "encoding/json" + "html/template" + "path/filepath" +) + +// Load loads the templates from the embedded file map. This function will not +// compile if go generate is not executed before. +func Load() *template.Template { + dir, _ := AssetDir("files") + tmpl := template.New("_").Funcs(template.FuncMap{"json": marshal}) + for _, name := range dir { + path := filepath.Join("files", name) + src := MustAsset(path) + tmpl = template.Must( + tmpl.New(name).Parse(string(src)), + ) + } + + return tmpl +} + +// marshal is a helper function to render data as JSON inside the template. +func marshal(v interface{}) template.JS { + a, _ := json.Marshal(v) + return template.JS(a) +} diff --git a/static/images/docker.svg b/static/images/docker.svg deleted file mode 100644 index ae937ca1c..000000000 --- a/static/images/docker.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/static/images/docker_blue.svg b/static/images/docker_blue.svg deleted file mode 100644 index bb007f66e..000000000 --- a/static/images/docker_blue.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/static/images/docker_white.svg b/static/images/docker_white.svg deleted file mode 100644 index 519cd2081..000000000 --- a/static/images/docker_white.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/static/images/dummy.png b/static/images/dummy.png deleted file mode 100644 index 2b428fa16170cea250e8080c1838e46de7fe52b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5376 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 diff --git a/static/images/favicon.ico b/static/images/favicon.ico deleted file mode 100644 index a7607313a63dd76fb880228ce6ed6fa75b4678b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmb`HJxjw-6oyYf)Pjfwr3E|Kv<^ZSrGnzrK^z>^NeV^OP4EwBh0>y6adP(`IJk(T zC=T`y2vQeC2kBN(K@pA5ZFBJ&Vo|i^$(wV|d(KU6LPUK0!(rhVm*t>HL_`LG6q#lo z5utX`)ua(~uxeCc`n)i-JC=sF@@*V z=zHh<&4_J0J6`?CWO4xCljD6sSI9-U_Aos;;s>W@tNU@!pth^)_?PgE5+6f_c!GFF z*U>YxU)>X)5|pWJWHOl`dTRKq%Fm2~@}OJMXtY!1@MK}pAm@0`js81l=A7YEJ@as6 z`1GEueVm3{sIlGxIu5$7wL)&)BVQvo#(f3S>2w?CLvZ8aQ}4%!M_$iY>tD5~4?BCX z-NK`1xwWi%oqj+4hrgI{fcMLLNF0JZJc4^I9p6)1gOFa^t(qSg3Z@CZMDMW2X5dFtKj+adA+p{&De diff --git a/static/images/favicon.png b/static/images/favicon.png deleted file mode 100644 index 5ff57c62002cb8639888bdd82c8950d6da05de01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 366 zcmV-!0g?WRP)`t<3)%n$73Y8Asb{4?`YL=;8! zX2GFHj~=aO{$iE=t%NX-wP(+sjYI;6(fV+OS%VgR(=bhjIsVY0L))x>2PuXELjMWf zWnGF|_RrXVG;3I6^Fum!?%a7UrXiSzA7=+C+)aa@>?a`*&c0bS00_Pzun5sx!7{{v zOtP#0!V9!Qtc)Q@@p(CE09?FyaU(DD6T&EpVg7dP*s*<%|BXIa1;u!@ffl12j{pDw M07*qoM6N<$f=)%IKL7v# diff --git a/static/images/logo_dark.svg b/static/images/logo_dark.svg deleted file mode 100644 index be92f1150..000000000 --- a/static/images/logo_dark.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/static/images/logo_light.svg b/static/images/logo_light.svg deleted file mode 100644 index af16f2873..000000000 --- a/static/images/logo_light.svg +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/static/images/ubuntu.svg b/static/images/ubuntu.svg deleted file mode 100644 index 850665f7a..000000000 --- a/static/images/ubuntu.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/static/scripts/build.js b/static/scripts/build.js deleted file mode 100644 index a152d09bf..000000000 --- a/static/scripts/build.js +++ /dev/null @@ -1,200 +0,0 @@ - - -function JobViewModel(repo, build, job, status) { - var self = this; - self.status = status; - - self.stream = function() { - $("#output").html(""); - $("#restart").hide(); - $("#cancel").show(); - - var buf = new Drone.Buffer(); - buf.start(document.getElementById("output")); - - $( "#tail" ).show(); - $( "#tail" ).click(function() { - buf.autoFollow = !buf.autoFollow; - if (buf.autoFollow) { - $( "#tail i" ).text("pause"); - $( "#tail" ).show(); - - // scroll to the bottom of the page - window.scrollTo(0, document.body.scrollHeight); - } else { - $( "#tail i" ).text("expand_more"); - $( "#tail" ).show(); - } - }) - - Stream(repo, build, job, function(out){ - buf.write(out); - }); - }; - - if (status !== "running" && status !== "pending") { - Logs(repo, build, job); - $("#restart").show(); - } - - if (status === "running") { - self.stream(); - } - - $("#restart").click(function() { - $("#restart").hide(); - $("#output").html(""); - $(".status").attr("class", "status pending").text("pending"); - - $.ajax({ - url: "/api/repos/"+repo+"/builds/"+build, - type: "POST", - success: function( data ) { }, - error: function( data ) { - console.log(data); - } - }); - }) - - $("#cancel").click(function() { - $("#cancel").hide(); - - $.ajax({ - url: "/api/repos/"+repo+"/builds/"+build+"/"+job, - type: "DELETE", - success: function( data ) { }, - error: function( data ) { - console.log(data); - } - }); - }) - - - Subscribe(repo, function(data){ - if (!data.jobs) { - return; - } - if (data.number !== build) { - return; - } - - var before = self.status; - self.status = data.jobs[job-1].status; - - // update the status for each job in the view - for (var i=0;i").attr("data-title", line.proc); - $("#output").append(pre); - - // create the buffer for the group of output - var buf = new Drone.Buffer(); - buf.start(pre[0]); - - // add items to the group - group = { - pre: pre, - buf: buf, - }; - groups[line.proc]=group; - } - - group.buf.write(line.out+"\n"); - } - - for (var i=0; i b.full_name().toLowerCase() ? 1 : -1; -} - -/** - * Creates an observable object that stores a list of hook event - * types (push, pull request, etc) and true or false if enabled. - */ -function Hook(repo) { - var data = { - "pull_request" : repo.events.indexOf("pull_request") !== -1, - "push" : repo.events.indexOf("push") !== -1, - "tag" : repo.events.indexOf("tag") !== -1, - "deploy" : repo.events.indexOf("deploy") !== -1 - }; - - this.pull_request = ko.observable(data.pull_request); - this.push = ko.observable(data.push); - this.tag = ko.observable(data.tag); - this.deploy = ko.observable(data.deploy); -} - -/** - * Creates an observable user. - */ -function User(data) { - this.login = ko.observable(data.login); - this.email = ko.observable(data.email); - this.avatar_url = ko.observable(data.avatar_url); - this.active = ko.observable(data.active); - this.admin = ko.observable(data.admin); -} - -/** - * Compares two user objects by login. Used to sort - * a list of users. - */ -function UserCompare(a, b) { - return a.login().toLowerCase() > b.login().toLowerCase() ? 1 : -1; -} diff --git a/static/scripts/nodes.js b/static/scripts/nodes.js deleted file mode 100644 index 74b7ec2c4..000000000 --- a/static/scripts/nodes.js +++ /dev/null @@ -1,74 +0,0 @@ - -function NodeViewModel() { - var self = this; - - // handle requests to create a new node. - $(".modal-node button").click(function(e) { - - var node = { - address : $("#addr").val(), - key : $("#key").val(), - cert : $("#cert").val(), - ca : $("#ca").val() - }; - - $.ajax({ - url: "/api/nodes", - type: "POST", - contentType: "application/json", - data: JSON.stringify(node), - success: function( data ) { - // clears the form value - $(".modal-node input").val(""); - - var el = $("
").attr("class", "col-sm-4").append( - $("
").attr("class", "card").attr("data-id", data.id).append( - $("
").attr("class", "card-header").append( - $("").attr("class", "linux_amd64") - ) - ).append( - $("
").attr("class", "card-block").append( - $("

").text(data.address) - ).append( - $("

").attr("class", "card-text").text(data.architecture) - ).append( - $("

").attr("class", "btn-group").append( - $("