Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
12 changes: 11 additions & 1 deletion actions/github/enrichPullRequest/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ inputs:
description: 'Name of the sync label'
required: false
default: 'jira-sync-complete'
httpEndpoint:
type: string
description: 'Endpoint for the action to use'
required: false
authToken:
type: string
description: 'Authentication token for the endpoint'
required: false
runs:
using: 'docker'
image: 'docker://ghcr.io/encoredigitalgroup/gh-action-enrich-pull-request:latest'
Expand All @@ -71,4 +79,6 @@ runs:
OPT_JIRA_TOKEN: ${{ inputs.jiraToken }}
OPT_ENABLE_JIRA_SYNC_LABEL: ${{ inputs.jiraEnableSyncLabel }}
OPT_JIRA_SYNC_LABEL_NAME: ${{ inputs.jiraSyncLabelName }}
OPT_ENABLE_JIRA_SYNC_DESCRIPTION: ${{ inputs.jiraEnableSyncDescription }}
OPT_ENABLE_JIRA_SYNC_DESCRIPTION: ${{ inputs.jiraEnableSyncDescription }}
OPT_HTTP_ENDPOINT: ${{ inputs.httpEndpoint }}
OPT_AUTH_TOKEN: ${{ inputs.authToken }}
2 changes: 2 additions & 0 deletions actions/github/enrichPullRequest/drivers/drivers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package drivers

const BranchName = "branch-name"
const Jira = "jira"
const General = "general"

func Validate(driver string) bool {
validDrivers := []string{
BranchName,
Jira,
General,
}

for _, validDriver := range validDrivers {
Expand Down
223 changes: 223 additions & 0 deletions actions/github/enrichPullRequest/drivers/general/general.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package general

import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"time"

"github.com/EncoreDigitalGroup/golib/logger"

branchname "github.com/EncoreDigitalGroup/ci-workflows/actions/github/enrichPullRequest/drivers/branch_name"
"github.com/EncoreDigitalGroup/ci-workflows/actions/github/enrichPullRequest/support/github"
)

type Configuration struct {
Enable bool
Endpoint string
AuthToken string
TicketID string
}

type Label struct {
Title string `json:"title"`
Description *string `json:"description"`
Color *string `json:"color"`
}

type APIResponse struct {
Title string `json:"title"`
Description *string `json:"description"`
Assignee *string `json:"assignee"`
Labels *[]Label `json:"labels"`
}

type HTTPError struct {
StatusCode int
Message string
}

func (e *HTTPError) Error() string {
return fmt.Sprintf("HTTP %d: %s", e.StatusCode, e.Message)
}

func Format(gh github.GitHub) {
branchName, err := gh.GetBranchName()
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}

endpoint := os.Getenv("OPT_HTTP_ENDPOINT")
if endpoint == "" {
logger.Error("OPT_HTTP_ENDPOINT is not set")
os.Exit(1)
}

authToken := os.Getenv("OPT_AUTH_TOKEN")
if authToken == "" {
logger.Error("OPT_AUTH_TOKEN is not set")
os.Exit(1)
}

ticketID, err := branchname.GetIssueKeyFromBranchName(branchName)
if err != nil {
logger.Error(err.Error())
os.Exit(1)
}

if ticketID == "" {
logger.Error("Ticket ID is empty")
return
}

config := Configuration{
Enable: true,
Endpoint: endpoint,
AuthToken: authToken,
TicketID: ticketID,
}

apiResponse, err := getTicketInfo(config)
if err != nil {
var httpErr *HTTPError
if errors.As(err, &httpErr) {
if httpErr.StatusCode == 404 {
logger.Errorf("Ticket not found: %s", ticketID)
comment := fmt.Sprintf("**Ticket Not Found**\n\n"+
"Unable to find ticket information for: `%s`\n\n"+
"Please verify that the ticket ID in your branch name is correct.", ticketID)
gh.AddPRComment(comment)
return
}

logger.Errorf("HTTP API error: %v", httpErr)
comment := "**API Error**\n\n" +
"Failed to fetch ticket information due to an API error. " +
"Please check the GitHub Action logs for specific error information."
gh.AddPRComment(comment)
return
}

logger.Errorf("Failed to get ticket info: %v", err)
comment := "Failed to get information from the API.\n\n" +
"Please check the GitHub Action logs for specific error information."
gh.AddPRComment(comment)
return
}

newPRTitle := apiResponse.Title
if newPRTitle == "" {
logger.Error("API response missing required 'title' field")
comment := "**Invalid API Response**\n\n" +
"The API response is missing the required 'title' field."
gh.AddPRComment(comment)
return
}

var newPRDescription string
if apiResponse.Description != nil {
newPRDescription = *apiResponse.Description
gh.UpdatePR(newPRTitle, newPRDescription)
} else {
gh.UpdatePRTitle(newPRTitle)
}

if apiResponse.Assignee != nil && *apiResponse.Assignee != "" {
logger.Infof("Assignee information received: %s (Note: GitHub assignee setting not implemented)", *apiResponse.Assignee)
}

if apiResponse.Labels != nil {
for _, label := range *apiResponse.Labels {
if label.Title == "" {
continue
}

description := ""
if label.Description != nil {
description = *label.Description
}

color := ""
if label.Color != nil {
color = *label.Color
}

gh.EnsureLabelExists(label.Title, description, color)
gh.AddLabelToPR(label.Title)
}
}
}

func getTicketInfo(config Configuration) (*APIResponse, error) {
if !config.Enable {
return nil, errors.New("general driver is not enabled")
}

if config.Endpoint == "" || config.AuthToken == "" || config.TicketID == "" {
return nil, errors.New("missing required configuration: endpoint, auth token, or ticket ID")
}

reqURL, err := url.Parse(config.Endpoint)
if err != nil {
return nil, fmt.Errorf("invalid endpoint URL: %v", err)
}

query := reqURL.Query()
query.Set("id", config.TicketID)
reqURL.RawQuery = query.Encode()

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %v", err)
}

req.Header.Set("Authorization", "Bearer "+config.AuthToken)
req.Header.Set("Accept", "application/json")

client := &http.Client{}

resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to make HTTP request: %v", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
logger.Errorf("Failed to close response body: %v", err)
}
}()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %v", err)
}

if resp.StatusCode == 404 {
return nil, &HTTPError{
StatusCode: resp.StatusCode,
Message: "ticket not found",
}
}

if resp.StatusCode != 200 {
return nil, &HTTPError{
StatusCode: resp.StatusCode,
Message: string(body),
}
}

var apiResponse APIResponse
if err := json.Unmarshal(body, &apiResponse); err != nil {
return nil, fmt.Errorf("failed to parse JSON response: %v", err)
}

return &apiResponse, nil
}
5 changes: 5 additions & 0 deletions actions/github/enrichPullRequest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/EncoreDigitalGroup/ci-workflows/actions/github/enrichPullRequest/drivers"
branchname "github.com/EncoreDigitalGroup/ci-workflows/actions/github/enrichPullRequest/drivers/branch_name"
"github.com/EncoreDigitalGroup/ci-workflows/actions/github/enrichPullRequest/drivers/jira"
httpdriver "github.com/EncoreDigitalGroup/ci-workflows/actions/github/enrichPullRequest/drivers/general"
"github.com/EncoreDigitalGroup/ci-workflows/actions/github/enrichPullRequest/support/github"
)

Expand Down Expand Up @@ -54,6 +55,10 @@ func main() {
if strategy == drivers.Jira {
jira.Format(gh)
}

if strategy == drivers.General {
httpdriver.Format(gh)
}
}

func checkEnvVars() {
Expand Down
Loading