Replace DeployErrors with a better system(?) (fix #42)
This commit is contained in:
parent
20b955231b
commit
a122598484
@ -1,30 +0,0 @@
|
|||||||
// package main is the main package for the LapisDeploy program
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DeployError contains important information about an error if something went wrong.
|
|
||||||
type DeployError struct {
|
|
||||||
code int
|
|
||||||
where string
|
|
||||||
details string
|
|
||||||
command_output string
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendOverMatrix provides an easy way to send the contents of a DeployError over Matrix
|
|
||||||
func (deploy_error *DeployError) SendOverMatrix() {
|
|
||||||
sendMessage(MatrixMessage{text: deploy_error.ToString()})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToString converts a DeployError into a human readable string.
|
|
||||||
func (deploy_error *DeployError) ToString() string {
|
|
||||||
return fmt.Sprintf("%sError in `%s`! (%s) Code: %d",
|
|
||||||
Circles["red"], deploy_error.where, deploy_error.details, deploy_error.code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newDeployError creates a DeployError
|
|
||||||
func newDeployError(code int, where string, details string, command_output string) DeployError {
|
|
||||||
return DeployError{code: code, where: where, details: details, command_output: command_output}
|
|
||||||
}
|
|
46
main.go
46
main.go
@ -3,6 +3,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -12,7 +13,7 @@ import (
|
|||||||
"github.com/akamensky/argparse"
|
"github.com/akamensky/argparse"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Circle emoji storage.
|
// Circle emoji
|
||||||
var Circles = map[string]string{
|
var Circles = map[string]string{
|
||||||
"white": "⚪️ ",
|
"white": "⚪️ ",
|
||||||
"green": "🟢 ",
|
"green": "🟢 ",
|
||||||
@ -21,9 +22,6 @@ var Circles = map[string]string{
|
|||||||
"orange": "🟠 ",
|
"orange": "🟠 ",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a configuration struct
|
|
||||||
var configuration = Configuration{}
|
|
||||||
|
|
||||||
// fileExists returns whether the given file or directory exists.
|
// fileExists returns whether the given file or directory exists.
|
||||||
func fileExists(path string) (bool, error) {
|
func fileExists(path string) (bool, error) {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
@ -36,51 +34,51 @@ func fileExists(path string) (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a configuration struct
|
||||||
|
var configuration = Configuration{}
|
||||||
|
|
||||||
// handler is in charge of handling requests after the JSON has been parsed
|
// handler is in charge of handling requests after the JSON has been parsed
|
||||||
func handler(data map[string]interface{}) {
|
func handler(data map[string]interface{}) {
|
||||||
repository := data["repository"].(map[string]interface{})
|
repository := data["repository"].(map[string]interface{})
|
||||||
log.Default().Printf("Repo: %s", repository["full_name"])
|
log.Default().Printf("Repo: %s", repository["full_name"])
|
||||||
sendMessage(MatrixMessage{text: fmt.Sprintf("%sHandling webhook for `%s`...",
|
sendInfo(fmt.Sprintf("Handling webhook for `%s`...", repository["full_name"]))
|
||||||
Circles["white"], repository["full_name"])})
|
|
||||||
|
|
||||||
repo_name := repository["name"].(string)
|
repo_name := repository["name"].(string)
|
||||||
|
|
||||||
site, exists, err := getSite(repo_name)
|
site, exists, err := getSite(repo_name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
deploy_error := newDeployError(1, "handler", fmt.Sprintf("Failed to check if site '%s' exists", repo_name), fmt.Sprint(err))
|
sendError(errors.New(fmt.Sprintf("Failed to check if site '%s' exists: %s", repo_name, err)))
|
||||||
deploy_error.SendOverMatrix()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
sendMessage(MatrixMessage{text: Circles["white"] + "Updating repository..."})
|
sendInfo("Updating repository...")
|
||||||
if deploy_error := site.Update(); deploy_error.code != 0 {
|
if err := site.Update(); err != nil {
|
||||||
deploy_error.SendOverMatrix()
|
sendError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
new_site, exists, err := getSite(site.name)
|
new_site, exists, err := getSite(site.name)
|
||||||
if err != nil || !exists {
|
if err != nil || !exists {
|
||||||
newDeployError(1, "main", "Failed to update site data on a site we just created!", fmt.Sprint(err))
|
sendError(errors.New("Failed to update site data on a site we just updated: " + repo_name))
|
||||||
}
|
}
|
||||||
site = new_site
|
site = new_site
|
||||||
sendMessage(MatrixMessage{text: Circles["white"] + "Restarting server..."})
|
sendInfo("Restarting server...")
|
||||||
if deploy_error := site.Restart(); deploy_error.code != 0 {
|
if error := site.Restart(); error != nil {
|
||||||
deploy_error.SendOverMatrix()
|
sendError(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendMessage(MatrixMessage{text: Circles["white"] + "Cloning repository..."})
|
sendInfo("Cloning repositiory...")
|
||||||
if deploy_error := CloneSite(repository["ssh_url"].(string), repo_name); deploy_error.code != 0 {
|
if error := CloneSite(repository["ssh_url"].(string), repo_name); error != nil {
|
||||||
deploy_error.SendOverMatrix()
|
sendError(error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sendMessage(MatrixMessage{text: Circles["white"] + "Starting server..."})
|
sendInfo("Starting server...")
|
||||||
if site, exists, err = getSite(repo_name); err != nil {
|
if site, exists, err = getSite(repo_name); err != nil {
|
||||||
deploy_error := newDeployError(1, "handler",
|
sendError(err)
|
||||||
fmt.Sprintf("Failed to get site '%s' after creation!", repo_name), fmt.Sprint(err))
|
return
|
||||||
deploy_error.SendOverMatrix()
|
|
||||||
}
|
}
|
||||||
if deploy_error := site.Start(); deploy_error.code != 0 {
|
if error := site.Start(); error != nil {
|
||||||
deploy_error.SendOverMatrix()
|
sendError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer sendMessage(MatrixMessage{text: "🚀 Launched for the first time!"})
|
defer sendMessage(MatrixMessage{text: "🚀 Launched for the first time!"})
|
||||||
|
19
matrix.go
19
matrix.go
@ -3,6 +3,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -29,15 +30,29 @@ type MatrixCommand struct {
|
|||||||
description string
|
description string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output queue
|
// Output queue.
|
||||||
var MatrixOut []MatrixMessage
|
var MatrixOut []MatrixMessage
|
||||||
|
|
||||||
// sendMessage sends a message through Matrix
|
// sendMessage sends a message through Matrix.
|
||||||
func sendMessage(msg MatrixMessage) {
|
func sendMessage(msg MatrixMessage) {
|
||||||
log.Print(msg.text)
|
log.Print(msg.text)
|
||||||
MatrixOut = append(MatrixOut, msg)
|
MatrixOut = append(MatrixOut, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendError sends an error through Matrix.
|
||||||
|
func sendError(err error) {
|
||||||
|
sendMessage(MatrixMessage{
|
||||||
|
text: fmt.Sprintf("%s %s", Circles["red"], err),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendInfo sends a bit of info text through Matrix.
|
||||||
|
func sendInfo(text string) {
|
||||||
|
sendMessage(MatrixMessage{
|
||||||
|
text: fmt.Sprintf("%s %s", Circles["white"], text),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// initMatrix starts a Matrix bot.
|
// initMatrix starts a Matrix bot.
|
||||||
func initMatrix() {
|
func initMatrix() {
|
||||||
client, err := mautrix.NewClient(configuration.matrix.homeserver, "", "")
|
client, err := mautrix.NewClient(configuration.matrix.homeserver, "", "")
|
||||||
|
@ -16,9 +16,9 @@ func getSitesByString(text string) ([]Site, []string) {
|
|||||||
sites := []Site{} // sites holds every site we need
|
sites := []Site{} // sites holds every site we need
|
||||||
// Determine which sites to get
|
// Determine which sites to get
|
||||||
if text == "all" { // If we need to get all sites, (!restart all)
|
if text == "all" { // If we need to get all sites, (!restart all)
|
||||||
var err DeployError
|
var err error
|
||||||
sites, err = getAllSites() // Get all sites
|
sites, err = getAllSites() // Get all sites
|
||||||
if err.code != 0 { // Check for errors
|
if err != nil { // Check for errors
|
||||||
errors = append(errors, "Failed to get all sites!")
|
errors = append(errors, "Failed to get all sites!")
|
||||||
}
|
}
|
||||||
} else { // If we need to get a specific site, (!restart LapisDeploy-TestApp)
|
} else { // If we need to get a specific site, (!restart LapisDeploy-TestApp)
|
||||||
@ -53,7 +53,7 @@ func registerChatCommands() {
|
|||||||
callback: func(ctx context.Context, evt *event.Event, args []string) string {
|
callback: func(ctx context.Context, evt *event.Event, args []string) string {
|
||||||
text := Circles["white"] + "Getting sites...\n"
|
text := Circles["white"] + "Getting sites...\n"
|
||||||
sites, err := getAllSites()
|
sites, err := getAllSites()
|
||||||
if err.code != 0 {
|
if err != nil {
|
||||||
return text + Circles["red"] + "Failed to get sites!"
|
return text + Circles["red"] + "Failed to get sites!"
|
||||||
}
|
}
|
||||||
for _, site := range sites {
|
for _, site := range sites {
|
||||||
@ -82,9 +82,8 @@ func registerChatCommands() {
|
|||||||
text += Circles["red"] + error + "\n"
|
text += Circles["red"] + error + "\n"
|
||||||
}
|
}
|
||||||
for _, site := range sites { // For every site queued to be restarted,
|
for _, site := range sites { // For every site queued to be restarted,
|
||||||
if err := site.Restart(); err.code != 0 { // Attempt to restart it
|
if err := site.Restart(); err != nil { // Attempt to restart it
|
||||||
text += fmt.Sprintf("%sRestarting '%s'... failed!\n", Circles["red"], site.getName())
|
text += fmt.Sprintf("%sRestarting '%s'... failed!\n", Circles["red"], site.getName())
|
||||||
text += err.ToString()
|
|
||||||
} else { // Otherwise, success.
|
} else { // Otherwise, success.
|
||||||
text += fmt.Sprintf("%sRestarting '%s'... success", Circles["green"], site.getName())
|
text += fmt.Sprintf("%sRestarting '%s'... success", Circles["green"], site.getName())
|
||||||
}
|
}
|
||||||
@ -105,9 +104,8 @@ func registerChatCommands() {
|
|||||||
text += Circles["red"] + error + "\n"
|
text += Circles["red"] + error + "\n"
|
||||||
}
|
}
|
||||||
for _, site := range sites {
|
for _, site := range sites {
|
||||||
if err := site.Start(); err.code != 0 {
|
if err := site.Start(); err != nil {
|
||||||
text += fmt.Sprintf("%sStarting '%s'... failed!\n", Circles["red"], site.getName())
|
text += fmt.Sprintf("%sStarting '%s'... failed!\n", Circles["red"], site.getName())
|
||||||
text += err.ToString()
|
|
||||||
} else {
|
} else {
|
||||||
text += fmt.Sprintf("%sStarting '%s'... success!\n", Circles["green"], site.getName())
|
text += fmt.Sprintf("%sStarting '%s'... success!\n", Circles["green"], site.getName())
|
||||||
}
|
}
|
||||||
@ -128,9 +126,8 @@ func registerChatCommands() {
|
|||||||
text += Circles["red"] + error + "\n"
|
text += Circles["red"] + error + "\n"
|
||||||
}
|
}
|
||||||
for _, site := range sites {
|
for _, site := range sites {
|
||||||
if err := site.Stop(); err.code != 0 {
|
if err := site.Stop(); err != nil {
|
||||||
text += fmt.Sprintf("%sStopping '%s'... failed!", Circles["red"], site.getName())
|
text += fmt.Sprintf("%sStopping '%s'... failed: %s", Circles["red"], site.getName(), err)
|
||||||
text += err.ToString()
|
|
||||||
} else {
|
} else {
|
||||||
text += fmt.Sprintf("%sStopping '%s'... success", Circles["green"], site.getName())
|
text += fmt.Sprintf("%sStopping '%s'... success", Circles["green"], site.getName())
|
||||||
}
|
}
|
||||||
|
58
site.go
58
site.go
@ -98,13 +98,12 @@ func (site *Site) getName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getAllSites gets every site installed.
|
// getAllSites gets every site installed.
|
||||||
func getAllSites() ([]Site, DeployError) {
|
func getAllSites() ([]Site, error) {
|
||||||
sites_dir := configuration.sites_dir
|
sites_dir := configuration.sites_dir
|
||||||
files, err := os.ReadDir(sites_dir)
|
files, err := os.ReadDir(sites_dir)
|
||||||
var sites []Site
|
var sites []Site
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sites, newDeployError(1, "startAllSites",
|
return sites, errors.New(fmt.Sprintf("Failed to read sites: %s", err))
|
||||||
"Failed to read sites", fmt.Sprint(err))
|
|
||||||
}
|
}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if !file.IsDir() {
|
if !file.IsDir() {
|
||||||
@ -112,30 +111,30 @@ func getAllSites() ([]Site, DeployError) {
|
|||||||
}
|
}
|
||||||
site, exists, err := getSite(file.Name())
|
site, exists, err := getSite(file.Name())
|
||||||
if err != nil || !exists {
|
if err != nil || !exists {
|
||||||
return sites, newDeployError(1, "getAllSites", "Failed to read sites", fmt.Sprint(err))
|
return sites, errors.New(fmt.Sprintf("Failed to read sites: %s", err))
|
||||||
}
|
}
|
||||||
sites = append(sites, site)
|
sites = append(sites, site)
|
||||||
}
|
}
|
||||||
return sites, DeployError{}
|
return sites, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// startAllSites attempts to start every site
|
// startAllSites attempts to start every site
|
||||||
func startAllSites() DeployError {
|
func startAllSites() error {
|
||||||
sites, err := getAllSites()
|
sites, err := getAllSites()
|
||||||
if err.code != 0 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, site := range sites {
|
for _, site := range sites {
|
||||||
err = site.Start()
|
err = site.Start()
|
||||||
if err.code != 0 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DeployError{}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start attempts to start a Lapis server in the given repository.
|
// Start attempts to start a Lapis server in the given repository.
|
||||||
func (site *Site) Start() DeployError {
|
func (site *Site) Start() error {
|
||||||
log.Printf("Starting Lapis server in %s...", site.getName())
|
log.Printf("Starting Lapis server in %s...", site.getName())
|
||||||
|
|
||||||
old_cwd, _ := os.Getwd()
|
old_cwd, _ := os.Getwd()
|
||||||
@ -144,18 +143,17 @@ func (site *Site) Start() DeployError {
|
|||||||
|
|
||||||
cmd := exec.Command("lapis", "serve")
|
cmd := exec.Command("lapis", "serve")
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return newDeployError(1, "startSite",
|
return errors.New(fmt.Sprintf("Failed to start Lapis server in '%s': %s", site.getName(), err))
|
||||||
fmt.Sprintf("Failed to start Lapis server in '%s'", site.getName()), "")
|
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return DeployError{}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop attempts to stop a Lapis server in the given repository.
|
// Stop attempts to stop a Lapis server in the given repository.
|
||||||
func (site *Site) Stop() DeployError {
|
func (site *Site) Stop() error {
|
||||||
log.Printf("Stopping Lapis server %s...", site.getName())
|
log.Printf("Stopping Lapis server %s...", site.getName())
|
||||||
|
|
||||||
old_cwd, _ := os.Getwd()
|
old_cwd, _ := os.Getwd()
|
||||||
@ -164,17 +162,16 @@ func (site *Site) Stop() DeployError {
|
|||||||
|
|
||||||
cmd := exec.Command("lapis", "term")
|
cmd := exec.Command("lapis", "term")
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return newDeployError(1, "stopSite",
|
return errors.New(fmt.Sprintf("Failed to stop Lapis server in '%s': %s", site.getName(), err))
|
||||||
fmt.Sprintf("Failed to stop Lapis server in '%s'", site.getName()), "")
|
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
}()
|
}()
|
||||||
return DeployError{}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restart attempts to restart the Lapis server in the given repository.
|
// Restart attempts to restart the Lapis server in the given repository.
|
||||||
func (site *Site) Restart() DeployError {
|
func (site *Site) Restart() error {
|
||||||
log.Printf("Restarting Lapis server in %s...", site.getName())
|
log.Printf("Restarting Lapis server in %s...", site.getName())
|
||||||
|
|
||||||
old_cwd, _ := os.Getwd()
|
old_cwd, _ := os.Getwd()
|
||||||
@ -183,38 +180,33 @@ func (site *Site) Restart() DeployError {
|
|||||||
|
|
||||||
out, err := exec.Command("lapis", "build").CombinedOutput()
|
out, err := exec.Command("lapis", "build").CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newDeployError(1, "restartSite",
|
return errors.New(fmt.Sprintf("Failed to run 'lapis build' in '%s': %s", site.getName(), err))
|
||||||
fmt.Sprintf("Failed to run 'lapis build' in '%s'", site.getName()), string(out))
|
|
||||||
}
|
}
|
||||||
log.Printf("[lapis build] %s", out)
|
log.Printf("[lapis build] %s", out)
|
||||||
if !strings.Contains(string(out), "HUP") {
|
if !strings.Contains(string(out), "HUP") {
|
||||||
return newDeployError(1, "restartSite",
|
return errors.New(fmt.Sprintf("Failed to restart Lapis server! (Lapis not running?): %s", string(out)))
|
||||||
"Failed to restart Lapis server! (Lapis not running?)", string(out))
|
|
||||||
}
|
}
|
||||||
return DeployError{}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update attempts to pull or clone a repository using the given name and url
|
// Update attempts to pull or clone a repository using the given name and url
|
||||||
func (site *Site) Update() DeployError {
|
func (site *Site) Update() error {
|
||||||
log.Printf("Pulling down repository %s...", site.getName())
|
log.Printf("Pulling down repository %s...", site.getName())
|
||||||
repo, err := git.Open(configuration.sites_dir + "/" + site.name)
|
repo, err := git.Open(configuration.sites_dir + "/" + site.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newDeployError(1, "updateSite",
|
return errors.New(fmt.Sprintf("Failed to open git repository '%s': %s", site.name, err))
|
||||||
fmt.Sprintf("Failed to open git repository '%s'", site.name), fmt.Sprint(err))
|
|
||||||
}
|
}
|
||||||
if err = repo.Pull(); err != nil {
|
if err = repo.Pull(); err != nil {
|
||||||
return newDeployError(1, "updateSite",
|
return errors.New(fmt.Sprintf("Failed to pull down git repository '%s': %s", site.getName(), err))
|
||||||
fmt.Sprintf("Failed to pull down git repository '%s'", site.getName()), fmt.Sprint(err))
|
|
||||||
}
|
}
|
||||||
return DeployError{}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneSite will clone a site and put it in the configured 'sites_dir'
|
// CloneSite will clone a site and put it in the configured 'sites_dir'
|
||||||
func CloneSite(url string, name string) DeployError {
|
func CloneSite(url string, name string) error {
|
||||||
log.Printf("Cloning repository %s...", name)
|
log.Printf("Cloning repository %s...", name)
|
||||||
if err := git.Clone(url, configuration.sites_dir+"/"+name); err != nil {
|
if err := git.Clone(url, configuration.sites_dir+"/"+name); err != nil {
|
||||||
return newDeployError(1, "cloneSite",
|
return errors.New(fmt.Sprintf("Failed to pull down repository '%s': %s", name, err))
|
||||||
fmt.Sprintf("Failed to pull down repository '%s'", name), fmt.Sprint(err))
|
|
||||||
}
|
}
|
||||||
return DeployError{}
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user