Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor and use go only #60

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 10 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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
ENV GO111MODULE=ON
COPY . .
RUN 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"]
ENTRYPOINT ["/deploy-preview"]
15 changes: 9 additions & 6 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,20 @@ 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 }}
- --variables=${{ inputs.variables }}
- --file=${{ inputs.file }}
- --branch=${{ inputs.branch }}
- --log-level=${{ inputs.log-level }}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does need some testing. I haven't checked what the implications are if the inputs are not set. I imagine an empty value will be sent through, which means the final result will not be the default set in the go code.

branding:
color: 'green'
icon: 'grid'
7 changes: 7 additions & 0 deletions default-message.md.gotmpl
Original file line number Diff line number Diff line change
@@ -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 }}
96 changes: 0 additions & 96 deletions entrypoint.sh

This file was deleted.

185 changes: 185 additions & 0 deletions github.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package main

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"strings"
)

type GitHubEvent struct {
Number int `json:"number"`
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 {
repository string
sourceURL string
prNumber int
defaultBranch string
}

type ciInfo interface {
Repository() 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":

gh.prNumber = payload.Number
gh.defaultBranch = os.Getenv("GITHUB_HEAD_REF")
case "repository_dispatch":
gh.prNumber = payload.ClientPayload.PullRequest.Number
gh.defaultBranch = strings.TrimPrefix(os.Getenv("GITHUB_REF"), "refs/heads/")
}

gh.repository = fmt.Sprintf("%s/%s", os.Getenv("GITHUB_SERVER_URL"), os.Getenv("GITHUB_REPOSITORY"))
gh.sourceURL = fmt.Sprintf("%s/%s", gh.repository, gh.prNumber)

return gh, nil
}

func (gh *github) Repository() string {
return gh.repository
}

func (gh *github) SourceURL() string {
return gh.sourceURL
}

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")
githubRepository := os.Getenv("GITHUB_REPOSITORY")

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", githubRepository, 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", githubRepository, 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", githubRepository, 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("<!-- okteto-preview %d -->", gh.prNumber)
}
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/okteto/deploy-preview

go 1.22

require golang.org/x/text v0.16.0

require github.com/hoshsadiq/godotenv v1.0.0 // indirect
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used my custom fork of https://github.com/joho/godotenv/ which parses things a lot better. But happy to switch it back to https://github.com/joho/godotenv/, or another one if you have a preference.

4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
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=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
Loading