Skip to content

Commit

Permalink
Merge pull request #1 from DeathVenom54/dev
Browse files Browse the repository at this point in the history
Release v1.0.0
  • Loading branch information
0xDevansh authored Feb 18, 2022
2 parents 6b04e93 + cacf7e3 commit c2c1355
Show file tree
Hide file tree
Showing 18 changed files with 899 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*.dll
*.so
*.dylib
build/

# Test binary, built with `go test -c`
*.test
Expand All @@ -13,3 +14,9 @@

# Dependency directories (remove the comment below to include it)
# vendor/

# Logs
*.log

# IDE files
.idea/
116 changes: 114 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,114 @@
# pm2-deploy-inator
A Go app to automatically deploy your pm2 apps

<h1 align="center">
<img alt="Project logo" width="100" src="docs/logo.png" align="center"> GitHub Deploy-inator</h1>

<div align="center">
<a href="https://discord.gg/qJnrRvt7wW">
<img alt="Discord" src="https://img.shields.io/discord/873232757508157470?color=%235865F2&label=support&style=for-the-badge">
</a>
</div>

> Automatic deployment app based on GitHub webhooks
## 💡 Motivation

I code and maintain a lot of Discord bots and other projects, all
running on my web server. Every time I pushed an update to a bot, I'd
have to SSH in, pull the code from Github, build it and restart the
process. Although I managed to boil this down into a sweet `yarn deploy`,
that still needed me to SSH into the server. I tried implementing git hooks
but to no avail.

And then, this project was born.

## 🛠️ Installation and Setup

I have no idea. [Use systemd perhaps](https://medium.com/@benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6).

Download the built version from [releases](https://github.com/DeathVenom54/github-deploy-inator/releases) and unzip it to a directory.
Edit the config.json to your requirements and run the executable.

## 📝 config.json

All the required data must be provided in a config.json file, placed in the current
working directory.

### Format

- `port`: The port on which the application will listen for webhooks
- type: `string`
- format: `":DDDD"`, where D is a digit
- example: `":8000"`, `":440"`
<br><br>

- `endpoint`: The endpoint where the webhooks will be sent
- type: `string`
- format: `"/*"`
- example: `"/webhooks/github"`, `"/github/listener"`
<br><br>

- `listeners`: Settings for individual listeners
- type: `Listener[]`

#### Listener

- `name`: [required] A unique name for the listener. This is mentioned when a webhook is received, executed or failed.
- type: `string`
- example: `my-chat-app` (try not to include spaces)
<br><br>

- `repository`: [required] The full name of the repository for which this webhook will be executed.
- type: `string`
- format: `"author-name/repository-name"`
- example: `"DeathVenom54/github-deploy-inator"`
<br><br>

- `directory`: [required] The absolute path to the directory (folder) where the command will be executed.
- type: `string`
- example: `"E:/projects/github-deploy-inator"`, `"/home/dv/projects/github-deploy-inator"`
<br><br>

- `command`: [required] The command to run when the webhook is received.
- type: `string`
- example: `"yarn deploy"`, `"git pull origin main"`
<br><br>
- `secret`: The secret token set for your webhook. This makes sure that the webhook is from GitHub and is highly recommended to set.
- type: `string`
- example: `j4g34O3TK2JF4jrnjrkj34nt3i4`
<br><br>

- `branch`: Execute the command only if the push was to this branch.
- type: `string`
- example: `"main"`, `"dev"`
<br><br>

- `allowedPushers`: Execute the command only if this array contains the pusher's GitHub username
- type: `string[]`
- example: `["DeathVenom54", "webnoob"]`
<br><br>

- `notifyDiscord`: If you want to receive a notification on Discord (via webhook)
- type: `boolean`
<br><br>

- `discord`: This contains information needed for sending Discord notifications
- type: `Discord`

#### Discord

- `webhook`: [required] The url of the webhook where notifications should be sent
- type: `string`
- example: `"https://discord.com/api/webhooks/938275411766720533/s4nhfM-8XH1hMu9WYqSBUFaSD_erXSn6qqfdazzieCwtlINZho4teSvdlnEYgBM1E1IO"`
<br><br>

- `notifyBeforeRun`: Whether a notification should be sent before running the command
- type: `boolean`
<br><br>

- `sendOutput`: Whether the notification should contain the output sent by the command
- type: `boolean`

## 💻 Contributing to this project

If you find any bug in this project, have a suggestion or wish to contribute to it, feel free to [open an issue](https://github.com/DeathVenom54/github-deploy-inator/issues/new).

26 changes: 26 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# build for linux
GOOS=linux GOARCH=amd64 go build -o build/github_deploy-inator_linux_x64 main.go && echo "Built linux x64" || exit
GOOS=linux GOARCH=386 go build -o build/github_deploy-inator_linux_x86 main.go && echo "Built linux x86" || exit

# build for windows
GOOS=windows GOARCH=amd64 go build -o build/github_deploy-inator_windows_x64.exe main.go && echo "Built windows x64" || exit
GOOS=windows GOARCH=386 go build -o build/github_deploy-inator_windows_x86.exe main.go && echo "Built windows x86" || exit

# build for macos
GOOS=darwin GOARCH=amd64 go build -o build/github_deploy-inator_macos_x64 main.go && echo "Built macos x64" || exit

echo "Built all platforms, zipping files..."

cd build || exit

zip -r linux_x64.zip github_deploy-inator_linux_x64 config.json || exit
zip -r linux_x86.zip github_deploy-inator_linux_x86 config.json || exit

zip -r windows_x64.zip github_deploy-inator_windows_x64.exe config.json || exit
zip -r windows_x86.zip github_deploy-inator_windows_x86.exe config.json || exit

zip -r macos_x64.zip github_deploy-inator_macos_x64 config.json || exit

echo "Successfully zipped all files"

cd ..
18 changes: 18 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"port": ":4567",
"endpoint": "/github/webhook",
"listeners": [
{
"name": "example-listener",
"repository": "DeathVenom54/github-deploy-inator",
"directory": "/home/dv/projects",
"command": "ls",
"notifyDiscord": true,
"discord": {
"webhook": "webhook-goes-here",
"notifyBeforeRun": true,
"sendOutput": true
}
}
]
}
25 changes: 25 additions & 0 deletions config/executeConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package config

import (
"github.com/DeathVenom54/github-deploy-inator/logger"
"github.com/DeathVenom54/github-deploy-inator/router"
"net/http"
)

func ExecuteConfig() error {
config, err := ReadConfig()
if err != nil {
return err
}

// start server
r := router.CreateRouter(config)

logger.All.Printf("Listening for Github webhooks on port %s\n", config.Port)
err = http.ListenAndServe(config.Port, r)
if err != nil {
return err
}

return nil
}
27 changes: 27 additions & 0 deletions config/readConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package config

import (
"encoding/json"
"github.com/DeathVenom54/github-deploy-inator/structs"
"io/ioutil"
)

func ReadConfig() (*structs.Config, error) {
configText, err := ioutil.ReadFile("config.json")
if err != nil {
return &structs.Config{}, err
}

var config structs.Config
err = json.Unmarshal(configText, &config)
if err != nil {
return &structs.Config{}, err
}

err = ValidateConfig(&config)
if err != nil {
return &structs.Config{}, err
}

return &config, nil
}
75 changes: 75 additions & 0 deletions config/validateConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package config

import (
"errors"
"fmt"
"github.com/DeathVenom54/github-deploy-inator/structs"
"regexp"
)

func ValidateConfig(config *structs.Config) error {
// validate port and endpoint
err := shouldMatchRegex("port", config.Port, `^:\d+$`)
if err != nil {
return err
}
err = shouldMatchRegex("endpoint", config.Endpoint, `^\/[\w-\/]*$`)
if err != nil {
return err
}

// validate listeners
if len(config.Listeners) == 0 {
return errors.New("no listeners assigned, please add at least one")
}

for i, listener := range config.Listeners {
// required fields
err := shouldExist("name", listener.Name, i)
if err != nil {
return err
}
err = shouldMatchRegex(fmt.Sprintf("listeners[%d].repository", i), listener.Repository, `[\w-]+\/[\w-]+`)
if err != nil {
return err
}
err = shouldExist("directory", listener.Directory, i)
if err != nil {
return err
}
err = shouldExist("command", listener.Command, i)
if err != nil {
return err
}

// discord
if listener.NotifyDiscord {
if listener.Discord.Webhook != "" {
err := shouldMatchRegex(fmt.Sprintf("listeners[%d].discord.webhook", i), listener.Discord.Webhook, structs.DiscordWebhookRegex)
if err != nil {
return err
}
}
}
}
return nil
}

func shouldMatchRegex(field, value, regex string) error {
match, err := regexp.MatchString(regex, value)
if err != nil {
return err
}
if !match {
return errors.New(fmt.Sprintf("invalid %s in config.json, should be in format %s", field, regex))
}
return nil
}

func shouldExist(paramName string, paramValue string, listenerIndex int) error {
if paramValue == "" {
return errors.New(fmt.Sprintf("Invalid %s for listeners[%d]: \"%s\"", paramName, listenerIndex, paramValue))
}

return nil
}
Binary file added docs/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module github.com/DeathVenom54/github-deploy-inator

go 1.17

require (
github.com/bwmarrin/discordgo v0.23.3-0.20211228023845-29269347e820
github.com/clinet/discordgo-embed v0.0.0-20220113222025-bafe0c917646
github.com/go-chi/chi/v5 v5.0.7
)

require (
github.com/gorilla/websocket v1.4.2 // indirect
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed // indirect
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
)
22 changes: 22 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
github.com/bwmarrin/discordgo v0.23.3-0.20211228023845-29269347e820 h1:MIW5DnBVJAgAy4LYBqWwIMBB0ezklvh8b7DsYvHZHb0=
github.com/bwmarrin/discordgo v0.23.3-0.20211228023845-29269347e820/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/clinet/discordgo-embed v0.0.0-20220113222025-bafe0c917646 h1:WOA+0wBHL/ZkiIQ8ctBAO9d5nnf5I7cgE531zhxGTOY=
github.com/clinet/discordgo-embed v0.0.0-20220113222025-bafe0c917646/go.mod h1:p2/vBoWL0mBfu/3eXnLHKRD5HHlaqGBJqe+et80Z0cQ=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed h1:YoWVYYAfvQ4ddHv3OKmIvX7NCAhFGTj62VP2l2kfBbA=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Loading

0 comments on commit c2c1355

Please sign in to comment.