mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-10-21 20:25:57 +00:00
initial public commit
This commit is contained in:
288
cmd/drone/drone.go
Normal file
288
cmd/drone/drone.go
Normal file
@@ -0,0 +1,288 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/drone/drone/pkg/build"
|
||||
"github.com/drone/drone/pkg/build/log"
|
||||
"github.com/drone/drone/pkg/build/repo"
|
||||
"github.com/drone/drone/pkg/build/script"
|
||||
|
||||
"launchpad.net/goyaml"
|
||||
)
|
||||
|
||||
var (
|
||||
// identity file (id_rsa) that will be injected
|
||||
// into the container if specified
|
||||
identity = flag.String("identity", "", "")
|
||||
|
||||
// runs Drone in parallel mode if True
|
||||
parallel = flag.Bool("parallel", false, "")
|
||||
|
||||
// build will timeout after N milliseconds.
|
||||
// this will default to 500 minutes (6 hours)
|
||||
timeout = flag.Duration("timeout", 300*time.Minute, "")
|
||||
|
||||
// runs Drone with verbose output if True
|
||||
verbose = flag.Bool("v", false, "")
|
||||
|
||||
// displays the help / usage if True
|
||||
help = flag.Bool("h", false, "")
|
||||
)
|
||||
|
||||
func init() {
|
||||
// default logging
|
||||
log.SetPrefix("\033[2m[DRONE] ")
|
||||
log.SetSuffix("\033[0m\n")
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetPriority(log.LOG_NOTICE)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Parse the input parameters
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
if *help {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
log.SetPriority(log.LOG_DEBUG)
|
||||
}
|
||||
|
||||
// Must speicify a command
|
||||
args := flag.Args()
|
||||
if len(args) == 0 {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
switch {
|
||||
// run drone build assuming the current
|
||||
// working directory contains the drone.yml
|
||||
case args[0] == "build" && len(args) == 1:
|
||||
path, _ := os.Getwd()
|
||||
path = filepath.Join(path, ".drone.yml")
|
||||
run(path)
|
||||
|
||||
// run drone build where the path to the
|
||||
// source directory is provided
|
||||
case args[0] == "build" && len(args) == 2:
|
||||
path := args[1]
|
||||
path = filepath.Clean(path)
|
||||
path, _ = filepath.Abs(path)
|
||||
path = filepath.Join(path, ".drone.yml")
|
||||
run(path)
|
||||
|
||||
// run drone vet where the path to the
|
||||
// source directory is provided
|
||||
case args[0] == "vet" && len(args) == 2:
|
||||
path := args[1]
|
||||
path = filepath.Clean(path)
|
||||
path, _ = filepath.Abs(path)
|
||||
path = filepath.Join(path, ".drone.yml")
|
||||
vet(path)
|
||||
|
||||
// run drone vet assuming the current
|
||||
// working directory contains the drone.yml
|
||||
case args[0] == "vet" && len(args) == 1:
|
||||
path, _ := os.Getwd()
|
||||
path = filepath.Join(path, ".drone.yml")
|
||||
vet(path)
|
||||
|
||||
// print the help message
|
||||
case args[0] == "help" && len(args) == 1:
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func vet(path string) {
|
||||
// parse the Drone yml file
|
||||
script, err := script.ParseBuildFile(path)
|
||||
if err != nil {
|
||||
log.Err(err.Error())
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
// print the Drone yml as parsed
|
||||
out, _ := goyaml.Marshal(script)
|
||||
log.Noticef("parsed yaml:\n%s", string(out))
|
||||
}
|
||||
|
||||
func run(path string) {
|
||||
// parse the Drone yml file
|
||||
s, err := script.ParseBuildFile(path)
|
||||
if err != nil {
|
||||
log.Err(err.Error())
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
// get the repository root directory
|
||||
dir := filepath.Dir(path)
|
||||
code := repo.Repo{Path: dir}
|
||||
|
||||
// does the local repository match the
|
||||
// $GOPATH/src/{package} pattern? This is
|
||||
// important so we know the target location
|
||||
// where the code should be copied inside
|
||||
// the container.
|
||||
if gopath, ok := getRepoPath(dir); ok {
|
||||
code.Dir = gopath
|
||||
|
||||
} else if gopath, ok := getGoPath(dir); ok {
|
||||
// in this case we found a GOPATH and
|
||||
// reverse engineered the package path
|
||||
code.Dir = gopath
|
||||
|
||||
} else {
|
||||
// otherwise just use directory name
|
||||
code.Dir = filepath.Base(dir)
|
||||
}
|
||||
|
||||
// this is where the code gets uploaded to the container
|
||||
// TODO move this code to the build package
|
||||
code.Dir = filepath.Join("/var/cache/drone/src", filepath.Clean(code.Dir))
|
||||
|
||||
// track all build results
|
||||
var builders []*build.Builder
|
||||
|
||||
// ssh key to import into container
|
||||
var key []byte
|
||||
if len(*identity) != 0 {
|
||||
key, err = ioutil.ReadFile(*identity)
|
||||
if err != nil {
|
||||
fmt.Printf("[Error] Could not find or read identity file %s\n", identity)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
builds := []*script.Build{s}
|
||||
|
||||
// loop through and create builders
|
||||
for _, b := range builds { //script.Builds {
|
||||
builder := build.Builder{}
|
||||
builder.Build = b
|
||||
builder.Repo = &code
|
||||
builder.Key = key
|
||||
builder.Stdout = os.Stdout
|
||||
builder.Timeout = *timeout
|
||||
|
||||
if *parallel == true {
|
||||
var buf bytes.Buffer
|
||||
builder.Stdout = &buf
|
||||
}
|
||||
|
||||
builders = append(builders, &builder)
|
||||
}
|
||||
|
||||
switch *parallel {
|
||||
case false:
|
||||
runSequential(builders)
|
||||
case true:
|
||||
runParallel(builders)
|
||||
}
|
||||
|
||||
// if in parallel mode, print out the buffer
|
||||
// if we had a failure
|
||||
for _, builder := range builders {
|
||||
if builder.BuildState.ExitCode == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if buf, ok := builder.Stdout.(*bytes.Buffer); ok {
|
||||
log.Noticef("printing stdout for failed build %s", builder.Build.Name)
|
||||
println(buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
// this exit code is initially 0 and will
|
||||
// be set to an error code if any of the
|
||||
// builds fail.
|
||||
var exit int
|
||||
|
||||
fmt.Printf("\nDrone Build Results \033[90m(%v)\033[0m\n", len(builders))
|
||||
|
||||
// loop through and print results
|
||||
for _, builder := range builders {
|
||||
build := builder.Build
|
||||
res := builder.BuildState
|
||||
duration := time.Duration(res.Finished - res.Started)
|
||||
switch {
|
||||
case builder.BuildState.ExitCode == 0:
|
||||
fmt.Printf(" \033[32m\u2713\033[0m %v \033[90m(%v)\033[0m\n", build.Name, humanizeDuration(duration*time.Second))
|
||||
case builder.BuildState.ExitCode != 0:
|
||||
fmt.Printf(" \033[31m\u2717\033[0m %v \033[90m(%v)\033[0m\n", build.Name, humanizeDuration(duration*time.Second))
|
||||
exit = builder.BuildState.ExitCode
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit(exit)
|
||||
}
|
||||
|
||||
func runSequential(builders []*build.Builder) {
|
||||
// loop through and execute each build
|
||||
for _, builder := range builders {
|
||||
if err := builder.Run(); err != nil {
|
||||
log.Errf("Error executing build: %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runParallel(builders []*build.Builder) {
|
||||
// spawn four worker goroutines
|
||||
var wg sync.WaitGroup
|
||||
for _, builder := range builders {
|
||||
// Increment the WaitGroup counter
|
||||
wg.Add(1)
|
||||
// Launch a goroutine to run the build
|
||||
go func(builder *build.Builder) {
|
||||
defer wg.Done()
|
||||
builder.Run()
|
||||
}(builder)
|
||||
time.Sleep(500 * time.Millisecond) // get weird iptables failures unless we sleep.
|
||||
}
|
||||
|
||||
// wait for the workers to finish
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
var usage = func() {
|
||||
fmt.Println(`Drone is a tool for building and testing code in Docker containers.
|
||||
|
||||
Usage:
|
||||
|
||||
drone command [arguments]
|
||||
|
||||
The commands are:
|
||||
|
||||
build build and test the repository
|
||||
version print the version number
|
||||
vet validate the yaml configuration file
|
||||
|
||||
-v runs drone with verbose output
|
||||
-h display this help and exit
|
||||
--parallel runs drone build tasks in parallel
|
||||
--timeout=300ms timeout build after 300 milliseconds
|
||||
|
||||
Examples:
|
||||
drone build builds the source in the pwd
|
||||
drone build /path/to/repo builds the source repository
|
||||
|
||||
Use "drone help [command]" for more information about a command.
|
||||
`)
|
||||
}
|
90
cmd/drone/util.go
Normal file
90
cmd/drone/util.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// getGoPath checks the source codes absolute path
|
||||
// in reference to the host operating system's GOPATH
|
||||
// to correctly determine the code's package path. This
|
||||
// is Go-specific, since Go code must exist in
|
||||
// $GOPATH/src/github.com/{owner}/{name}
|
||||
func getGoPath(dir string) (string, bool) {
|
||||
path := os.Getenv("GOPATH")
|
||||
if len(path) == 0 {
|
||||
return "", false
|
||||
}
|
||||
// append src to the GOPATH, since
|
||||
// the code will be stored in the src dir
|
||||
path = filepath.Join(path, "src")
|
||||
if !filepath.HasPrefix(dir, path) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// remove the prefix from the directory
|
||||
// this should leave us with the go package name
|
||||
return dir[len(path):], true
|
||||
}
|
||||
|
||||
var gopathExp = regexp.MustCompile("./src/(github.com/[^/]+/[^/]+|bitbucket.org/[^/]+/[^/]+|code.google.com/[^/]+/[^/]+)")
|
||||
|
||||
// getRepoPath checks the source codes absolute path
|
||||
// on the host operating system in an attempt
|
||||
// to correctly determine the code's package path. This
|
||||
// is Go-specific, since Go code must exist in
|
||||
// $GOPATH/src/github.com/{owner}/{name}
|
||||
func getRepoPath(dir string) (path string, ok bool) {
|
||||
// let's get the package directory based
|
||||
// on the path in the host OS
|
||||
indexes := gopathExp.FindStringIndex(dir)
|
||||
if len(indexes) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
index := indexes[len(indexes)-1]
|
||||
|
||||
// if the dir is /home/ubuntu/go/src/github.com/foo/bar
|
||||
// the index will start at /src/github.com/foo/bar.
|
||||
// We'll need to strip "/src/" which is where the
|
||||
// magic number 5 comes from.
|
||||
index = strings.LastIndex(dir, "/src/")
|
||||
return dir[index+5:], true
|
||||
}
|
||||
|
||||
// getGitOrigin checks the .git origin in an attempt
|
||||
// to correctly determine the code's package path. This
|
||||
// is Go-specific, since Go code must exist in
|
||||
// $GOPATH/src/github.com/{owner}/{name}
|
||||
func getGitOrigin(dir string) (path string, ok bool) {
|
||||
// TODO
|
||||
return
|
||||
}
|
||||
|
||||
// prints the time as a human readable string
|
||||
func humanizeDuration(d time.Duration) string {
|
||||
if seconds := int(d.Seconds()); seconds < 1 {
|
||||
return "Less than a second"
|
||||
} else if seconds < 60 {
|
||||
return fmt.Sprintf("%d seconds", seconds)
|
||||
} else if minutes := int(d.Minutes()); minutes == 1 {
|
||||
return "About a minute"
|
||||
} else if minutes < 60 {
|
||||
return fmt.Sprintf("%d minutes", minutes)
|
||||
} else if hours := int(d.Hours()); hours == 1 {
|
||||
return "About an hour"
|
||||
} else if hours < 48 {
|
||||
return fmt.Sprintf("%d hours", hours)
|
||||
} else if hours < 24*7*2 {
|
||||
return fmt.Sprintf("%d days", hours/24)
|
||||
} else if hours < 24*30*3 {
|
||||
return fmt.Sprintf("%d weeks", hours/24/7)
|
||||
} else if hours < 24*365*2 {
|
||||
return fmt.Sprintf("%d months", hours/24/30)
|
||||
}
|
||||
return fmt.Sprintf("%f years", d.Hours()/24/365)
|
||||
}
|
1076
cmd/droned/assets/css/drone.css
Normal file
1076
cmd/droned/assets/css/drone.css
Normal file
File diff suppressed because it is too large
Load Diff
1263
cmd/droned/assets/css/drone.less
Normal file
1263
cmd/droned/assets/css/drone.less
Normal file
File diff suppressed because it is too large
Load Diff
BIN
cmd/droned/assets/img/build_failing.png
Normal file
BIN
cmd/droned/assets/img/build_failing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
cmd/droned/assets/img/build_none.png
Normal file
BIN
cmd/droned/assets/img/build_none.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
cmd/droned/assets/img/build_success.png
Normal file
BIN
cmd/droned/assets/img/build_success.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
cmd/droned/assets/img/build_unknown.png
Normal file
BIN
cmd/droned/assets/img/build_unknown.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
cmd/droned/assets/img/favicon.ico
Normal file
BIN
cmd/droned/assets/img/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
cmd/droned/assets/img/favicon.png
Normal file
BIN
cmd/droned/assets/img/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 442 B |
187
cmd/droned/drone.go
Normal file
187
cmd/droned/drone.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/go.net/websocket"
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/bmizerany/pat"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/russross/meddler"
|
||||
|
||||
"github.com/drone/drone/pkg/channel"
|
||||
"github.com/drone/drone/pkg/database"
|
||||
"github.com/drone/drone/pkg/handler"
|
||||
)
|
||||
|
||||
var (
|
||||
// local path where the SQLite database
|
||||
// should be stored. By default this is
|
||||
// in the current working directory.
|
||||
path string
|
||||
|
||||
// port the server will run on
|
||||
port string
|
||||
|
||||
// database driver used to connect to the database
|
||||
driver string
|
||||
|
||||
// driver specific connection information. In this
|
||||
// case, it should be the location of the SQLite file
|
||||
datasource string
|
||||
)
|
||||
|
||||
func main() {
|
||||
// parse command line flags
|
||||
flag.StringVar(&path, "path", "", "")
|
||||
flag.StringVar(&port, "port", ":8080", "")
|
||||
flag.StringVar(&driver, "driver", "sqlite3", "")
|
||||
flag.StringVar(&datasource, "datasource", "drone.sqlite", "")
|
||||
flag.Parse()
|
||||
|
||||
// setup database and handlers
|
||||
setupDatabase()
|
||||
setupStatic()
|
||||
setupHandlers()
|
||||
|
||||
// start the webserver on the default port.
|
||||
panic(http.ListenAndServe(port, nil))
|
||||
}
|
||||
|
||||
// setup the database connection and register with the
|
||||
// global database package.
|
||||
func setupDatabase() {
|
||||
// inform meddler we're using sqlite
|
||||
meddler.Default = meddler.SQLite
|
||||
|
||||
// connect to the SQLite database
|
||||
db, err := sql.Open(driver, datasource)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
database.Set(db)
|
||||
}
|
||||
|
||||
// setup routes for static assets. These assets may
|
||||
// be directly embedded inside the application using
|
||||
// the `rice embed` command, else they are served from disk.
|
||||
func setupStatic() {
|
||||
box := rice.MustFindBox("assets")
|
||||
http.Handle("/css/", http.FileServer(box.HTTPBox()))
|
||||
http.Handle("/img/", http.FileServer(box.HTTPBox()))
|
||||
}
|
||||
|
||||
// setup routes for serving dynamic content.
|
||||
func setupHandlers() {
|
||||
m := pat.New()
|
||||
m.Get("/login", handler.ErrorHandler(handler.Login))
|
||||
m.Post("/login", handler.ErrorHandler(handler.Authorize))
|
||||
m.Get("/logout", handler.ErrorHandler(handler.Logout))
|
||||
m.Get("/forgot", handler.ErrorHandler(handler.Forgot))
|
||||
m.Post("/forgot", handler.ErrorHandler(handler.ForgotPost))
|
||||
m.Get("/reset", handler.ErrorHandler(handler.Reset))
|
||||
m.Post("/reset", handler.ErrorHandler(handler.ResetPost))
|
||||
m.Get("/register", handler.ErrorHandler(handler.Register))
|
||||
m.Post("/register", handler.ErrorHandler(handler.RegisterPost))
|
||||
m.Get("/accept", handler.UserHandler(handler.TeamMemberAccept))
|
||||
|
||||
// handlers for setting up your GitHub repository
|
||||
m.Post("/new/github.com", handler.UserHandler(handler.RepoCreateGithub))
|
||||
m.Get("/new/github.com", handler.UserHandler(handler.RepoAdd))
|
||||
|
||||
// handlers for linking your GitHub account
|
||||
m.Get("/auth/login/github", handler.UserHandler(handler.LinkGithub))
|
||||
|
||||
// handlers for dashboard pages
|
||||
m.Get("/dashboard/team/:team", handler.UserHandler(handler.TeamShow))
|
||||
m.Get("/dashboard", handler.UserHandler(handler.UserShow))
|
||||
|
||||
// handlers for user account management
|
||||
m.Get("/account/user/profile", handler.UserHandler(handler.UserEdit))
|
||||
m.Post("/account/user/profile", handler.UserHandler(handler.UserUpdate))
|
||||
m.Get("/account/user/delete", handler.UserHandler(handler.UserDeleteConfirm))
|
||||
m.Post("/account/user/delete", handler.UserHandler(handler.UserDelete))
|
||||
m.Get("/account/user/password", handler.UserHandler(handler.UserPass))
|
||||
m.Post("/account/user/password", handler.UserHandler(handler.UserPassUpdate))
|
||||
m.Get("/account/user/teams/add", handler.UserHandler(handler.TeamAdd))
|
||||
m.Post("/account/user/teams/add", handler.UserHandler(handler.TeamCreate))
|
||||
m.Get("/account/user/teams", handler.UserHandler(handler.UserTeams))
|
||||
|
||||
// handlers for team managements
|
||||
m.Get("/account/team/:team/profile", handler.UserHandler(handler.TeamEdit))
|
||||
m.Post("/account/team/:team/profile", handler.UserHandler(handler.TeamUpdate))
|
||||
m.Get("/account/team/:team/delete", handler.UserHandler(handler.TeamDeleteConfirm))
|
||||
m.Post("/account/team/:team/delete", handler.UserHandler(handler.TeamDelete))
|
||||
m.Get("/account/team/:team/members/add", handler.UserHandler(handler.TeamMemberAdd))
|
||||
m.Post("/account/team/:team/members/add", handler.UserHandler(handler.TeamMemberInvite))
|
||||
m.Get("/account/team/:team/members/edit", handler.UserHandler(handler.TeamMemberEdit))
|
||||
m.Post("/account/team/:team/members/edit", handler.UserHandler(handler.TeamMemberUpdate))
|
||||
m.Post("/account/team/:team/members/delete", handler.UserHandler(handler.TeamMemberDelete))
|
||||
m.Get("/account/team/:team/members", handler.UserHandler(handler.TeamMembers))
|
||||
|
||||
// handlers for system administration
|
||||
m.Get("/account/admin/settings", handler.AdminHandler(handler.AdminSettings))
|
||||
m.Post("/account/admin/settings", handler.AdminHandler(handler.AdminSettingsUpdate))
|
||||
m.Get("/account/admin/users/edit", handler.AdminHandler(handler.AdminUserEdit))
|
||||
m.Post("/account/admin/users/edit", handler.AdminHandler(handler.AdminUserUpdate))
|
||||
m.Post("/account/admin/users/delete", handler.AdminHandler(handler.AdminUserDelete))
|
||||
m.Get("/account/admin/users/add", handler.AdminHandler(handler.AdminUserAdd))
|
||||
m.Post("/account/admin/users", handler.AdminHandler(handler.AdminUserInvite))
|
||||
m.Get("/account/admin/users", handler.AdminHandler(handler.AdminUserList))
|
||||
|
||||
// handlers for GitHub post-commit hooks
|
||||
m.Post("/hook/github.com", handler.ErrorHandler(handler.Hook))
|
||||
|
||||
// handlers for first-time installation
|
||||
m.Get("/install", handler.ErrorHandler(handler.Install))
|
||||
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/tree/:branch/status.png", handler.ErrorHandler(handler.Badge))
|
||||
m.Get("/:host/:owner/:name/tree/:branch", 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))
|
||||
m.Get("/:host/:owner/:name/params", handler.RepoAdminHandler(handler.RepoParamsForm))
|
||||
m.Get("/:host/:owner/:name/badges", handler.RepoAdminHandler(handler.RepoBadges))
|
||||
m.Get("/:host/:owner/:name/keys", handler.RepoAdminHandler(handler.RepoKeys))
|
||||
m.Get("/:host/:owner/:name/delete", handler.RepoAdminHandler(handler.RepoDeleteForm))
|
||||
m.Post("/:host/:owner/:name/delete", handler.RepoAdminHandler(handler.RepoDelete))
|
||||
m.Get("/:host/:owner/:name", handler.RepoHandler(handler.RepoDashboard))
|
||||
m.Post("/:host/:owner/:name", handler.RepoHandler(handler.RepoUpdate))
|
||||
http.Handle("/feed", websocket.Handler(channel.Read))
|
||||
|
||||
// no routes are served at the root URL. Instead we will
|
||||
// redirect the user to his/her dashboard page.
|
||||
m.Get("/", http.RedirectHandler("/dashboard", http.StatusSeeOther))
|
||||
|
||||
// the first time a page is requested we should record
|
||||
// the scheme and hostname.
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// get the hostname and scheme
|
||||
|
||||
// our multiplexer is a bit finnicky and therefore requires
|
||||
// us to strip any trailing slashes in order to correctly
|
||||
// find and match a route.
|
||||
if r.URL.Path != "/" && strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.Redirect(w, r, r.URL.Path[:len(r.URL.Path)-1], http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
// standard header variables that should be set, for good measure.
|
||||
w.Header().Add("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
|
||||
w.Header().Add("X-Frame-Options", "DENY")
|
||||
w.Header().Add("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Add("X-XSS-Protection", "1; mode=block")
|
||||
|
||||
// ok, now we're ready to serve the request.
|
||||
m.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user