diff --git a/Dockerfile b/Dockerfile index 615407c..75376c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,16 @@ FROM okteto/okteto:latest as okteto -FROM golang:1.16 as message-builder -RUN go env -w GO111MODULE=off -RUN go get github.com/machinebox/graphql -COPY message.go . -RUN go build -o /message . -RUN curl -L https://github.com/jqlang/jq/releases/download/jq-1.6/jq-linux64 > /usr/bin/jq && chmod +x /usr/bin/jq +FROM golang:1.22 as builder +WORKDIR /app +ARG GO111MODULE=on +COPY . . +RUN CGO_ENABLED=0 go build -o /deploy-preview . -FROM ruby:3-slim-buster +FROM gcr.io/distroless/static-debian11 -RUN gem install octokit faraday-retry +COPY --from=builder /deploy-preview /deploy-preview +COPY --from=okteto /usr/local/bin/okteto /okteto -COPY notify-pr.sh /notify-pr.sh -RUN chmod +x notify-pr.sh -COPY --from=message-builder /usr/bin/jq /usr/bin/jq -COPY entrypoint.sh /entrypoint.sh -COPY --from=message-builder /message /message -COPY --from=okteto /usr/local/bin/okteto /usr/local/bin/okteto +ENV PATH=/ -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file +ENTRYPOINT ["/deploy-preview"] diff --git a/action.yml b/action.yml index 2cf500d..35685e0 100644 --- a/action.yml +++ b/action.yml @@ -23,17 +23,21 @@ inputs: log-level: description: "Log level string. Valid options are debug, info, warn, error" required: false + comment: + description: "Specify custom comment. Prefix with @ to read from a file." + required: false runs: using: "docker" image: "Dockerfile" args: - ${{ inputs.name }} - - ${{ inputs.timeout }} - - ${{ inputs.scope }} - - ${{ inputs.variables }} - - ${{ inputs.file }} - - ${{ inputs.branch }} - - ${{ inputs.log-level }} + - --timeout=${{ inputs.timeout }} + - --scope=${{ inputs.scope }} + - --var=${{ inputs.variables }} + - --file=${{ inputs.file }} + - --branch=${{ inputs.branch }} + - --log-level=${{ inputs.log-level }} + - --comment=${{ inputs.comment }} branding: color: 'green' icon: 'grid' diff --git a/default-message.md.gotmpl b/default-message.md.gotmpl new file mode 100644 index 0000000..9cd54af --- /dev/null +++ b/default-message.md.gotmpl @@ -0,0 +1,7 @@ +Your preview environment [{{ .PreviewName }}]({{ .PreviewURL }}) has been deployed +{{- if ne .PreviewSuccess true }} :warning::rotating_light: **but encountered errors** :rotating_light::warning:{{ end }}. + +Preview environment endpoint is available at: +{{ range $index, $url := .EndpointsMap -}} + * [{{ $index }}]({{ $url }}) +{{ end }} diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index 90cfba1..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/sh -set -e - -name=$1 -timeout=$2 -scope=$3 -variables=$4 -file=$5 -branch=$6 -log_level=$7 - -if [ -z $name ]; then - echo "Preview environment name is required" - exit 1 -fi - -if [ -z $scope ]; then - scope=global -fi - -if [ ! -z "$OKTETO_CA_CERT" ]; then - echo "Custom certificate is provided" - echo "$OKTETO_CA_CERT" > /usr/local/share/ca-certificates/okteto_ca_cert.crt - update-ca-certificates -fi - -if [ -z "$branch" ]; then - if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then - branch=${GITHUB_HEAD_REF} - else - branch=${GITHUB_REF#refs/heads/} - fi -fi - -if [ -z "$branch" ]; then - echo "fail to detect branch name" - exit 1 -fi - -repository=$GITHUB_REPOSITORY - -if [ ! -z $timeout ]; then -params="${params} --timeout=$timeout" -fi - -variable_params="" -if [ ! -z "${variables}" ]; then - for ARG in $(echo "${variables}" | tr ',' '\n'); do - variable_params="${variable_params} --var ${ARG}" - done - - params="${params} $variable_params" -fi - -if [ ! -z "$file" ]; then -params="${params} --file $file" -fi - -export OKTETO_DISABLE_SPINNER=1 -if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then - number=$(jq '[ .number ][0]' $GITHUB_EVENT_PATH) -elif [ "${GITHUB_EVENT_NAME}" = "repository_dispatch" ]; then - number=$(jq '[ .client_payload.pull_request.number ][0]' $GITHUB_EVENT_PATH) -fi - -if [ ! -z "$log_level" ]; then - log_level="--log-level ${log_level}" -fi - -# https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging -# https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables -if [ "${RUNNER_DEBUG}" = "1" ]; then - log_level="--log-level debug" -fi - -echo running: okteto preview deploy $name $log_level --scope $scope --branch="${branch}" --repository="${GITHUB_SERVER_URL}/${repository}" --sourceUrl="${GITHUB_SERVER_URL}/${repository}/pull/${number}" ${params} --wait -ret=0 -okteto preview deploy $name $log_level --scope $scope --branch="${branch}" --repository="${GITHUB_SERVER_URL}/${repository}" --sourceUrl="${GITHUB_SERVER_URL}/${repository}/pull/${number}" ${params} --wait || ret=1 - -if [ -z "$number" ] || [ "$number" = "null" ]; then - echo "No pull-request defined, skipping notification." - exit 0 -fi - -if [ -n "$GITHUB_TOKEN" ]; then - if [ $ret = 1 ]; then - message=$(/message $name 1) - else - message=$(/message $name 0) - fi - /notify-pr.sh "$message" $GITHUB_TOKEN $name -fi - -if [ $ret = 1 ]; then - exit 1 -fi diff --git a/github.go b/github.go new file mode 100644 index 0000000..048fe47 --- /dev/null +++ b/github.go @@ -0,0 +1,193 @@ +package main + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "strings" +) + +type GitHubEvent struct { + PullRequest struct { + Number int `json:"number"` + Head struct { + Ref string `json:"ref"` + } `json:"head"` + } `json:"pull_request"` + Repository struct { + HtmlURL string `json:"html_url"` + FullName string `json:"full_name"` + } `json:"repository"` + ClientPayload struct { + PullRequest struct { + Number int `json:"number"` + } `json:"pull_request"` + } `json:"client_payload"` +} + +type GitHubComment struct { + ID int `json:"id"` + Body string `json:"body"` +} + +type github struct { + repositoryURL string + prNumber int + defaultBranch string + repositoryName string +} + +type ciInfo interface { + RepositoryURL() string + SourceURL() string + DefaultBranch() string + Notify(message string) error +} + +var _ ciInfo = (*github)(nil) + +func newGitHub() (ciInfo, error) { + event, err := os.Open(os.Getenv("GITHUB_EVENT_PATH")) + if err != nil { + log.Printf("failed to read GITHUB_EVENT_PATH: %s", os.Getenv("GITHUB_EVENT_PATH")) + return nil, err + } + defer event.Close() + + var payload GitHubEvent + err = json.NewDecoder(event).Decode(&payload) + if err != nil { + log.Printf("failed to parse GITHUB_EVENT_PATH: %s", os.Getenv("GITHUB_EVENT_PATH")) + return nil, err + } + + gh := &github{} + + switch os.Getenv("GITHUB_EVENT_NAME") { + case "pull_request", "pull_request_target": + gh.prNumber = payload.PullRequest.Number + gh.defaultBranch = payload.PullRequest.Head.Ref + gh.repositoryURL = payload.Repository.HtmlURL + gh.repositoryName = payload.Repository.FullName + case "repository_dispatch": + gh.prNumber = payload.ClientPayload.PullRequest.Number + gh.defaultBranch = strings.TrimPrefix(os.Getenv("GITHUB_REF"), "refs/heads/") + gh.repositoryURL = payload.Repository.HtmlURL + gh.repositoryName = payload.Repository.FullName + } + + return gh, nil +} + +func (gh *github) RepositoryURL() string { + return gh.repositoryURL +} + +func (gh *github) SourceURL() string { + return fmt.Sprintf("%s/pull/%d", gh.repositoryURL, gh.prNumber) +} + +func (gh *github) DefaultBranch() string { + return gh.defaultBranch +} + +func (gh *github) PRNumber() int { + return gh.prNumber +} + +func (gh *github) Notify(message string) error { + githubToken := os.Getenv("GITHUB_TOKEN") + + if githubToken == "" { + log.Println("failed to set message as no GITHUB_TOKEN found") + return errors.New("missing GITHUB_TOKEN") + } + + resp, err := gh.callGitHub(githubToken, "GET", gh.repositoryName, nil, "issues", fmt.Sprintf("%d", gh.prNumber), "comments") + if err != nil { + return fmt.Errorf("failed to retrieve PR comments: %s", err) + } + + defer resp.Body.Close() + + var comments []GitHubComment + json.NewDecoder(resp.Body).Decode(&comments) + + identifier := gh.previewIdentifier() + var comment *GitHubComment + for _, c := range comments { + if strings.Contains(c.Body, identifier) { + comment = &c + break + } + } + + msgBodyBuf, err := gh.getGitHubCommentMessage(message) + if err != nil { + return err + } + if comment == nil { + _, err = gh.callGitHub(githubToken, "POST", gh.repositoryName, msgBodyBuf, "issues", fmt.Sprintf("%d", gh.prNumber), "comments") + if err != nil { + return fmt.Errorf("failed to create new comment: %s", err) + } + return nil + } + + fmt.Println("Message already exists in the PR. Updating") + _, err = gh.callGitHub(githubToken, "PATCH", gh.repositoryName, msgBodyBuf, "issues", "comments", fmt.Sprintf("%d", comment.ID)) + if err != nil { + return fmt.Errorf("failed to update comment: %s", err) + } + return nil +} + +func (gh *github) getGitHubCommentMessage(message string) (*bytes.Buffer, error) { + msgBody := struct { + Body string `json:"body"` + }{ + Body: message + gh.previewIdentifier(), + } + + msgBodyStr, err := json.Marshal(msgBody) + if err != nil { + return nil, fmt.Errorf("failed to encode message body: %v", msgBody) + } + + return bytes.NewBuffer(msgBodyStr), nil +} + +func (gh *github) callGitHub(token string, method string, repo string, body io.Reader, path ...string) (*http.Response, error) { + path = append([]string{repo}, path...) + uri, _ := url.JoinPath("https://api.github.com/repos/", path...) + req, _ := http.NewRequest(method, uri, body) + req.Header.Set("Authorization", "token "+token) + r, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + if r.StatusCode < http.StatusOK || r.StatusCode >= http.StatusBadRequest { + var errResp = struct { + Message string `json:"message"` + }{} + err = json.NewDecoder(r.Body).Decode(&errResp) + if err != nil { + return nil, fmt.Errorf("failed to decode body: %s", err) + } + + return nil, errors.New(errResp.Message) + } + + return r, nil +} + +func (gh *github) previewIdentifier() string { + return fmt.Sprintf("", gh.prNumber) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cfe1412 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module github.com/okteto/deploy-preview + +go 1.22 + +require ( + github.com/spf13/pflag v1.0.5 + golang.org/x/text v0.16.0 +) + +require github.com/hoshsadiq/godotenv v1.0.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..750dace --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/hoshsadiq/godotenv v1.0.0 h1:Hjx9hW+vqSOm5LN/UwMktxAekKvuXIg+BzIUmGQ7wXQ= +github.com/hoshsadiq/godotenv v1.0.0/go.mod h1:BZLGi0xKHU92H+AKkNoy/BsSFrZUUN3C8SdvyF3gt+c= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..45d763f --- /dev/null +++ b/main.go @@ -0,0 +1,193 @@ +package main + +import ( + "errors" + "fmt" + "github.com/hoshsadiq/godotenv" + flag "github.com/spf13/pflag" + "log" + "os" + "os/exec" + "strings" + "time" +) + +type sliceString []string + +func (i *sliceString) String() string { + if i == nil { + return "" + } + return strings.Join(*i, ";\n") + ";\n" +} + +func (i *sliceString) Set(value string) error { + vars, err := godotenv.Unmarshal(value) + if err != nil { + return err + } + + for k, v := range vars { + *i = append(*i, fmt.Sprintf("%s=%s", k, v)) + } + return nil +} + +func (i *sliceString) Type() string { + return "var" +} + +type DeployOptions struct { + branch string + file string + logLevel string + name string + scope string + timeout time.Duration + variables sliceString + wait bool + comment string + + ci ciInfo +} + +func exitIfErr(err error) { + if err != nil { + fmt.Println(err) + os.Exit(2) + } +} + +/* +todo: the follow code is left: + + if [ ! -z "$OKTETO_CA_CERT" ]; then + echo "Custom certificate is provided" + echo "$OKTETO_CA_CERT" > /usr/local/share/ca-certificates/okteto_ca_cert.crt + update-ca-certificates + fi +*/ +func main() { + ci, err := getCIInfo() + exitIfErr(err) + + opts := DeployOptions{ + ci: ci, + } + flagSet := flag.NewFlagSet("deploy-preview", flag.ContinueOnError) + flagSet.StringVar(&opts.branch, "branch", ci.DefaultBranch(), "the branch to deploy (defaults to the current branch)") + flagSet.StringVar(&opts.scope, "scope", "global", "the scope of preview environment to create. Accepted values are ['personal', 'global']") + flagSet.StringVar(&opts.logLevel, "log-level", getLogLevel("warn"), "amount of information output (debug, info, warn, error)") + flagSet.DurationVar(&opts.timeout, "timeout", 5*time.Minute, "the length of time to wait for completion, zero means never. Any other values should contain a corresponding time unit e.g. 1s, 2m, 3h ") + flagSet.Var(&opts.variables, "var", "set a preview environment variable, this will be parsed as an env file, but can be set more than once") + flagSet.BoolVar(&opts.wait, "wait", false, "wait until the preview environment deployment finishes (defaults to false)") + flagSet.StringVar(&opts.file, "file", "", "relative path within the repository to the okteto manifest (default to okteto.yaml or .okteto/okteto.yaml)") + flagSet.StringVar(&opts.comment, "comment", "", "Specify custom comment. Prefix with @ to read from a file") + err = flagSet.Parse(os.Args) + + if err != nil { + if errors.Is(err, flag.ErrHelp) { + // pflag already takes care of printing the usage. + os.Exit(0) + } + + exitIfErr(err) + } + + err = validateInput(flagSet, &opts) + exitIfErr(err) + + err = deployPreview(opts) + if err != nil { + log.Printf("deploy failed due to: %s", err) + } + var success = err == nil + + err = notify(ci, success, opts.name, opts.comment) + exitIfErr(err) + + if !success { + os.Exit(1) + } +} + +func notify(ci ciInfo, success bool, name string, comment string) error { + if ci == nil { + log.Printf("Not notifying anything, CI not supported") + } + + message, err := generateMessage(success, name, comment) + exitIfErr(err) + + return ci.Notify(message) +} + +func getCIInfo() (ciInfo, error) { + switch { + case os.Getenv("GITHUB_ACTIONS") == "true": + return newGitHub() + } + + return nil, errors.New("unsupported CI environment") +} + +func getLogLevel(def string) string { + // https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging + // https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables + if os.Getenv("RUNNER_DEBUG") == "1" { + return "debug" + } + + return def +} + +func validateInput(flagSet *flag.FlagSet, opts *DeployOptions) error { + if flagSet.NArg() != 2 { + return errors.New("preview environment name is required") + } + + opts.branch = opts.ci.DefaultBranch() + if opts.branch == "" { + // this essentially means that retrieveDefaultBranch was unable to find a value + return errors.New("failed to detect branch") + } + + opts.name = flagSet.Arg(1) + return nil +} + +func deployPreview(opts DeployOptions) error { + args := []string{"preview", "deploy", opts.name} + args = append(args, fmt.Sprintf("--scope=%s", opts.scope)) + args = append(args, fmt.Sprintf("--branch=%s", opts.branch)) + args = append(args, fmt.Sprintf("--repository=%s", opts.ci.RepositoryURL())) + args = append(args, fmt.Sprintf("--sourceUrl=%s", opts.ci.SourceURL())) + + if opts.timeout > 0 { + args = append(args, fmt.Sprintf("--timeout=%s", opts.timeout.String())) + } + + if opts.file != "" { + args = append(args, fmt.Sprintf("--file=%s", opts.file)) + } + + if logLevel := getLogLevel(opts.logLevel); logLevel != "" { + args = append(args, fmt.Sprintf("--log-level=%s", logLevel)) + } + + for _, variable := range opts.variables { + args = append(args, fmt.Sprintf("--var=%s", variable)) + } + + args = append(args, "--wait") + + cmd := exec.Command("okteto", args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = append(os.Environ(), "OKTETO_DISABLE_SPINNER=1") + + log.Printf("running: okteto %s", strings.Join(args, " ")) + + return cmd.Run() +} diff --git a/message.go b/message.go index 20847cc..f333a50 100755 --- a/message.go +++ b/message.go @@ -1,85 +1,168 @@ package main import ( + "bytes" + _ "embed" "encoding/json" "fmt" - "io/ioutil" + "golang.org/x/text/cases" + "golang.org/x/text/language" + "io" + "net/url" "os" "os/exec" "path/filepath" + "strings" + "text/template" ) +//go:embed default-message.md.gotmpl +var defaultCommentTemplate string + type contexts struct { Current string `json:"current-context"` Contexts map[string]context `json:"contexts"` } type context struct { - Name string `json:"name"` + Name *url.URL `json:"name"` +} + +func (p *context) UnmarshalJSON(data []byte) error { + type Context context + + tmp := struct { + Name string `json:"name"` + *Context + }{ + Context: (*Context)(p), + } + + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + + p.Name, err = url.Parse(tmp.Name) + if err != nil { + return err + } + + return nil } -//Endpoint represents an Okteto statefulset +// Endpoint represents an Okteto statefulset type Endpoint struct { - URL string `json:"url"` - Divert bool `json:"divert"` - Private bool `json:"private"` + URL *url.URL `json:"url"` + Divert bool `json:"divert"` + Private bool `json:"private"` } -func main() { - previewName := os.Args[1] - previewCommandExitCode := os.Args[2] +func (p *Endpoint) UnmarshalJSON(data []byte) error { + type endpoint Endpoint - oktetoURL, err := getOktetoURL() + tmp := struct { + URL string `json:"url"` + *endpoint + }{ + endpoint: (*endpoint)(p), + } + + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + + p.URL, err = url.Parse(tmp.URL) if err != nil { - return + return err } - previewURL := fmt.Sprintf("%s/previews/%s", oktetoURL, previewName) + return nil +} + +func generateMessage(previewSucceeded bool, previewName string, commentTemplate string) (string, error) { + oktetoURL, err := getOktetoURL() + if err != nil { + return "", err + } - var firstLine string - if previewCommandExitCode == "0" { - firstLine = fmt.Sprintf("Your preview environment [%s](%s) has been deployed.", previewName, previewURL) - } else { - firstLine = fmt.Sprintf("Your preview environment [%s](%s) has been deployed with errors.", previewName, previewURL) + commentTemplate, err = getCommentTemplate(commentTemplate) + if err != nil { + return "", err } - fmt.Println(firstLine) endpoints, err := getEndpoints(previewName) if err != nil { - return - } - if len(endpoints) == 1 { - fmt.Printf("\n Preview environment endpoint is available [here](%s)", endpoints[0]) - } else if len(endpoints) > 1 { - endpoints = translateEndpoints(endpoints) - fmt.Printf("\n Preview environment endpoints are available at:") - for _, endpoint := range endpoints { - fmt.Printf("\n * %s", endpoint) + return "", err + } + + previewURLSuffix := fmt.Sprintf("%s.%s", previewName, oktetoURL.Host) + templateVars := map[string]interface{}{ + "OktetoURL": oktetoURL.String(), + "PreviewURL": fmt.Sprintf("%s/#/previews/%s", oktetoURL, previewName), + "PreviewName": previewName, + "PreviewURLSuffix": previewURLSuffix, + "PreviewSuccess": previewSucceeded, + "Endpoints": endpoints, + "EndpointsMap": getEndpointsMap(previewURLSuffix, endpoints), + } + + return parseTemplate(commentTemplate, templateVars) +} + +func getCommentTemplate(commentTemplate string) (string, error) { + if commentTemplate == "" { + commentTemplate = defaultCommentTemplate + } + + if commentTemplate[0:1] == "@" { + file, err := os.Open(commentTemplate[1:]) + if err != nil { + return "", err } + + fileContents, err := io.ReadAll(file) + if err != nil { + return "", err + } + + return string(fileContents), nil } + return commentTemplate, nil } -func getOktetoURL() (string, error) { +func getEndpointsMap(previewURLSuffix string, endpoints []*url.URL) map[string]string { + endpointsMap := make(map[string]string, len(endpoints)) + for _, endpoint := range endpoints { + name := strings.TrimSuffix(endpoint.Host, "-"+previewURLSuffix) + endpointsMap[name] = endpoint.String() + } + + return endpointsMap +} + +func getOktetoURL() (*url.URL, error) { contextsPath := filepath.Join(os.Getenv("HOME"), ".okteto", "context", "config.json") - b, err := ioutil.ReadFile(contextsPath) + b, err := os.ReadFile(contextsPath) if err != nil { - return "", err + return nil, err } contexts := &contexts{} if err := json.Unmarshal(b, contexts); err != nil { - return "", err + return nil, err } if val, ok := contexts.Contexts[contexts.Current]; ok { return val.Name, nil } - return "", fmt.Errorf("context %s is missing", contexts.Current) + return nil, fmt.Errorf("context %s is missing", contexts.Current) } -func getEndpoints(name string) ([]string, error) { +func getEndpoints(name string) ([]*url.URL, error) { cmd := exec.Command("okteto", "preview", "endpoints", name, "-o", "json") cmd.Env = os.Environ() o, err := cmd.CombinedOutput() @@ -92,17 +175,30 @@ func getEndpoints(name string) ([]string, error) { if err != nil { return nil, err } - endpointURLs := make([]string, 0) + endpointURLs := make([]*url.URL, 0, len(endpoints)) for _, e := range endpoints { endpointURLs = append(endpointURLs, e.URL) } return endpointURLs, nil } -func translateEndpoints(endpoints []string) []string { - result := make([]string, 0) - for _, endpoint := range endpoints { - result = append(result, fmt.Sprintf("[%s](%s)", endpoint, endpoint)) +func parseTemplate(templateText string, vars map[string]interface{}) (string, error) { + var output bytes.Buffer + + tmpl, err := template.New("template").Funcs(map[string]interface{}{ + "Contains": strings.Contains, + "HasPrefix": strings.HasPrefix, + "HasSuffix": strings.HasSuffix, + "Title": cases.Title(language.English).String, + "Trim": strings.TrimSpace, + }).Parse(templateText) + if err != nil { + return "", err + } + err = tmpl.Execute(&output, vars) + if err != nil { + return "", err } - return result + + return output.String(), nil } diff --git a/notify-pr.sh b/notify-pr.sh deleted file mode 100644 index 668bf7d..0000000 --- a/notify-pr.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env ruby -require "octokit" -require "json" - -if ENV["GITHUB_EVENT_NAME"] != "pull_request" && ENV["GITHUB_EVENT_NAME"] != "repository_dispatch" - puts "This action only supports either pull_request or repository_dispatch events." - exit(1) -end - -if !message = ARGV[1] - puts "Missing GITHUB_TOKEN" - exit(1) -end - -message = ARGV[0] -preview_name = ARGV[2] -repo = ENV["GITHUB_REPOSITORY"] - -json = File.read(ENV.fetch("GITHUB_EVENT_PATH")) -event = JSON.parse(json) -if ENV["GITHUB_EVENT_NAME"] == "pull_request" - pr = event["number"] -else - pr = event["client_payload"]["pull_request"]["number"] -end - -github = Octokit::Client.new(:access_token => ENV["GITHUB_TOKEN"]) -comments = github.issue_comments(repo, pr) -comment = comments.find do |c| - c["body"].start_with?("Your preview environment") && - c["body"].include?("[#{preview_name}]") -end - -if comment - puts "Message already exists in the PR. Updating" - github.update_comment(repo, comment["id"], message) - exit(0) -end - -github.add_comment(repo, pr, message)