diff --git a/.drone.yml b/.drone.yml index 53cd1f2..9a409e1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -3,8 +3,23 @@ type: docker name: build steps: +- name: Build Go app + image: registry.cuzo.dev/library/golang + volumes: + - name: deps + path: /go + commands: + - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/ cmd/drone-ntfy/main.go + - name: Build docker image image: registry.cuzo.dev/plugins/docker + depends_on: + - Build Go app + when: + ref: + include: + - refs/heads/main + - refs/tags/** privileged: true volumes: - name: manifest @@ -19,25 +34,16 @@ steps: password: from_secret: docker_hub_pass -image_pull_secrets: -- custom_mirror_registry - -trigger: - event: - - push - - tag - exclude: - - pull_request - ---- -kind: pipeline -type: docker -name: manifest - -steps: - name: Upload manifest image: registry.cuzo.dev/plugins/manifest privileged: true + depends_on: + - Build docker image + when: + ref: + include: + - refs/heads/main + - refs/tags/** volumes: - name: manifest path: docker @@ -52,25 +58,6 @@ steps: from_secret: docker_hub_pass platforms: - linux/amd64 -- name: send ntfy notification - image: registry.cuzo.dev/parrazam/drone-ntfy - when: - status: [success, failure] - ref: - exclude: - - refs/tags/* - settings: - url: https://ntfy.parravidales.es - topic: pipelines - priority: low - tags: manifest - username: - from_secret: ntfy_user - password: - from_secret: ntfy_password - -depends_on: -- build image_pull_secrets: - custom_mirror_registry @@ -82,6 +69,7 @@ trigger: exclude: - pull_request + --- kind: pipeline type: docker @@ -94,22 +82,9 @@ steps: api_key: from_secret: drone_api_key base_url: https://git.parravidales.es -- name: send ntfy notification - image: registry.cuzo.dev/parrazam/drone-ntfy - when: - status: [success, failure] - settings: - url: https://ntfy.parravidales.es - topic: pipelines - priority: low - tags: release - username: - from_secret: ntfy_user - password: - from_secret: ntfy_password depends_on: -- manifest +- build image_pull_secrets: - custom_mirror_registry @@ -117,3 +92,26 @@ image_pull_secrets: trigger: event: - tag + + +--- +kind: pipeline +type: docker +name: notify + +steps: +- name: send ntfy notification + image: registry.cuzo.dev/parrazam/drone-ntfy + settings: + url: https://ntfy.parravidales.es + topic: pipelines + priority: low + token: + from_secret: ntfy_token + +image_pull_secrets: +- custom_mirror_registry + +depends_on: +- build +- release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fe15e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/ +bin/ +.env diff --git a/Dockerfile b/Dockerfile index 2325933..3f9d75a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,4 @@ FROM alpine -ADD script.sh /bin/ -RUN chmod +x /bin/script.sh -RUN apk -Uuv add curl ca-certificates -ENTRYPOINT /bin/script.sh +ADD bin/main /bin/main +RUN apk -Uuv add ca-certificates +ENTRYPOINT /bin/main diff --git a/README.md b/README.md index 1684c2b..f7be3b6 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,11 @@ steps: url: https://ntfy.example.org topic: events priority: low - tags: + tags: - pipeline-status - dev - username: - from_secret: ntfy_user - password: - from_secret: ntfy_password + token: + from_secret: ntfy_token ``` ## Properties @@ -54,3 +52,33 @@ Username with publish permissions. Password for username. > *Default: none* + +`token` *string* [optional] \ +[***SECRET RECOMMENDED***] \ +Token to use, instead username and password. + +> *Default: none* + +## Development + +If you want to test the project locally, first you need to create an `.env` file with: + +```env +PLUGIN_TOPIC= +PLUGIN_URL= +PLUGIN_USERNAME= +PLUGIN_PASSWORD= +PLUGIN_TOKEN= +CI_COMMIT_SHA= +CI_COMMIT_MESSAGE= +CI_REPO_NAME= +CI_COMMIT_BRANCH= +CI_COMMIT_REF= +DRONE_BUILD_NUMBER= +DRONE_BUILD_STATUS= +DRONE_STAGE_NUMBER= +DRONE_STAGE_STATUS= +DRONE_TAG= +DRONE_BUILD_LINK= +DRONE_COMMIT_LINK= +``` diff --git a/cmd/drone-ntfy/config/config.go b/cmd/drone-ntfy/config/config.go new file mode 100644 index 0000000..691bb9c --- /dev/null +++ b/cmd/drone-ntfy/config/config.go @@ -0,0 +1,30 @@ +package config + +type App struct { + BaseUrl string `env:"PLUGIN_URL" envDefault:"https://ntfy.sh"` + Topic string `env:"PLUGIN_TOPIC,required"` + Username string `env:"PLUGIN_USERNAME"` + Password string `env:"PLUGIN_PASSWORD"` + Token string `env:"PLUGIN_TOKEN"` + Title string `env:"PLUGIN_TITLE"` + Priority string `env:"PLUGIN_PRIORITY" envDefault:"default"` + Tags []string `env:"PLUGIN_TAGS" envSeparator:","` + DefaultTags []string `env:"PLUGIN_DEFAULT_TAGS" envDefault:"drone"` + Message string `env:"PLUGIN_MESSAGE"` +} + +type Drone struct { + BuildNumber string `env:"DRONE_BUILD_NUMBER"` + BuildStatus string `env:"DRONE_BUILD_STATUS"` + Tag string `env:"DRONE_TAG"` + BuildLink string `env:"DRONE_BUILD_LINK"` + CommitLink string `env:"DRONE_COMMIT_LINK"` + RepoName string `env:"DRONE_REPO_NAME"` +} + +type Ci struct { + CommitMessage string `env:"CI_COMMIT_MESSAGE"` + CommitSha string `env:"CI_COMMIT_SHA"` + CommitBranch string `env:"CI_COMMIT_BRANCH"` + CommitRef string `env:"CI_COMMIT_REF"` +} diff --git a/cmd/drone-ntfy/main.go b/cmd/drone-ntfy/main.go new file mode 100644 index 0000000..245f2e4 --- /dev/null +++ b/cmd/drone-ntfy/main.go @@ -0,0 +1,111 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "strings" + + "git.parravidales.es/parra/drone-ntfy/cmd/drone-ntfy/config" + "github.com/caarlos0/env/v7" + "github.com/joho/godotenv" +) + +type Config struct { + App config.App + Drone config.Drone + Ci config.Ci +} + +func main() { + + cfg := loadCfg() + + updateAppConfig(&cfg) + addTagsBasedOnResult(&cfg) + sendNotification(&cfg) +} + +func loadCfg() Config { + + envErr := godotenv.Load() + if envErr != nil { + fmt.Printf("unable to load .env file: %e\n", envErr) + } + + conf := Config{ + App: config.App{}, + Drone: config.Drone{}, + Ci: config.Ci{}, + } + loadConfig(&conf.App) + loadConfig(&conf.Drone) + loadConfig(&conf.Ci) + + conf.App.Tags = append(conf.App.DefaultTags, conf.App.Tags...) + + return conf +} + +func loadConfig(cfg any) { + err := env.Parse(cfg) + if err != nil { + log.Fatalf("unable to parse environment variables: %e", err) + } +} + +func updateAppConfig(cfg *Config) { + + cfg.App.Title = "Build #" + cfg.Drone.BuildNumber + " " + cfg.Drone.BuildStatus + + if strings.Contains(cfg.Ci.CommitRef, "refs/tags/") { + cfg.App.Tags = append(cfg.App.Tags, cfg.Drone.Tag) + cfg.App.Message = "Tag " + cfg.Drone.Tag + " created" + } else { + cfg.App.Tags = append(cfg.App.Tags, cfg.Drone.RepoName+"/"+cfg.Ci.CommitBranch) + cfg.App.Message = "[" + cfg.Ci.CommitSha[0:8] + "] " + cfg.Ci.CommitMessage + } +} + +func addTagsBasedOnResult(cfg *Config) { + + if cfg.Drone.BuildStatus == "success" { + cfg.App.Tags = append(cfg.App.Tags, "white_check_mark") + } else if cfg.Drone.BuildStatus == "failure" { + cfg.App.Tags = append(cfg.App.Tags, "x") + } else { + cfg.App.Tags = append(cfg.App.Tags, "grey_question") + } +} + +func sendNotification(cfg *Config) { + + req, _ := http.NewRequest("POST", + cfg.App.BaseUrl+"/"+cfg.App.Topic, + strings.NewReader(cfg.App.Message)) + + if cfg.App.Token != "" { + req.Header.Add("Authorization", "Bearer "+cfg.App.Token) + } else { + req.SetBasicAuth(cfg.App.Username, cfg.App.Password) + } + req.Header.Set("Title", cfg.App.Title) + req.Header.Set("Priority", cfg.App.Priority) + req.Header.Set("Tags", strings.Join(cfg.App.Tags, ",")) + req.Header.Set("Actions", getActions(cfg)) + res, err := http.DefaultClient.Do(req) + if err != nil { + log.Fatalf("error trying to notify the result. Error: %+v", err) + } + if res.StatusCode != 200 { + log.Fatalf("error from server. HTTP status: %d. Error: %e", res.StatusCode, err) + } +} + +func getActions(cfg *Config) string { + var buildLink = "view, Build, " + cfg.Drone.BuildLink + if strings.Contains(cfg.Ci.CommitRef, "refs/tags/") { + return buildLink + } + return buildLink + "; view, Changes, " + cfg.Drone.CommitLink +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b2ec15a --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module git.parravidales.es/parra/drone-ntfy + +go 1.19 + +require ( + github.com/caarlos0/env/v7 v7.0.0 + github.com/joho/godotenv v1.5.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..daef734 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/caarlos0/env/v7 v7.0.0 h1:cyczlTd/zREwSr9ch/mwaDl7Hse7kJuUY8hvHfXu5WI= +github.com/caarlos0/env/v7 v7.0.0/go.mod h1:LPPWniDUq4JaO6Q41vtlyikhMknqymCLBw0eX4dcH1E= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/script.sh b/script.sh deleted file mode 100644 index abb3ec8..0000000 --- a/script.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/sh - -DEFAULT_TAGS="drone" -BASE_URL=${PLUGIN_URL:-"https://ntfy.sh"} -TOPIC=$PLUGIN_TOPIC # mandatory -TITLE="Build #$DRONE_BUILD_NUMBER $DRONE_BUILD_STATUS" -PRIORITY=${PLUGIN_PRIORITY:-"default"} -TAGS=${PLUGIN_TAGS:-""} - -MESSAGE="[${CI_COMMIT_SHA:0:8}] $CI_COMMIT_MESSAGE" - -if [[ $CI_COMMIT_REF == *"refs/tags/"* ]] -then - MESSAGE="Tag $DRONE_TAG created" - DEFAULT_TAGS="$DEFAULT_TAGS,$DRONE_TAG" -else - DEFAULT_TAGS="$DEFAULT_TAGS,$CI_REPO_NAME/$CI_COMMIT_BRANCH" -fi - -if [ -z "$TOPIC" ] -then - echo "Topic cannot be empty."; - exit 1 -fi - -URL="$BASE_URL/$TOPIC" - -if [ $DRONE_BUILD_STATUS = "success" ] -then - DEFAULT_TAGS="$DEFAULT_TAGS,white_check_mark" -elif [ $DRONE_BUILD_STATUS = "failure" ] -then - DEFAULT_TAGS="$DEFAULT_TAGS,x" -else - DEFAULT_TAGS="$DEFAULT_TAGS,grey_question" -fi - -TAGS="$DEFAULT_TAGS,$TAGS" -TAGS=${TAGS%,} - -AUTH_HEADER="" -if [ -z "$PLUGIN_USERNAME" ] || [ -z "$PLUGIN_PASSWORD" ] -then - echo "Trying to publish message in a public topic..." -else - AUTH_HEADER="-u $PLUGIN_USERNAME:$PLUGIN_PASSWORD" -fi - -HTTP_STATUS=$( -curl \ - -o /dev/null -s -w "%{http_code}\n" \ - --retry 3 --retry-delay 5 \ - $AUTH_HEADER \ - -H title:"$TITLE" \ - -H tags:$TAGS \ - -H prio:$PRIORITY \ - -H "Actions: view, Build, $DRONE_BUILD_LINK; view, Changes, $DRONE_COMMIT_LINK" \ - -d "$MESSAGE" \ - $URL -) - -if [ $? -eq 0 ] && [ $HTTP_STATUS -eq 200 ] -then - echo "Message sent!" -else - echo "Error publishing notification." - exit 2 -fi