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

feat: [CI-14390]: Added new enhancements to plugins/jira #26

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
154 changes: 127 additions & 27 deletions plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ type Args struct {

// Deployment environment (optional)
EnvironmentName string `envconfig:"PLUGIN_ENVIRONMENT_NAME"`
// Environmnet Id (optional)
EnvironmentId string `envconfig:"PLUGIN_ENVIRONMENT_ID"`
// Environmnet Type (optional)
EnvironmentType string `envconfig:"PLUGIN_ENVIRONMENT_TYPE"`

vanisrikanithi marked this conversation as resolved.
Show resolved Hide resolved
// Link to deployment (optional)
Link string `envconfig:"PLUGIN_LINK"`
Expand All @@ -67,51 +71,66 @@ type Args struct {

// connect hostname (required)
ConnectHostname string `envconfig:"PLUGIN_CONNECT_HOSTNAME"`
// Issue Keys(optional)
IssueKeys []string `envconfig:"PLUGIN_ISSUEKEYS"`
}

// Exec executes the plugin.
func Exec(ctx context.Context, args Args) error {
var (
environ = toEnvironment(args)
issue = extractIssue(args)
state = toState(args)
version = toVersion(args)
deeplink = toLink(args)
environ = toEnvironment(args)
environmentID = toEnvironmentId(args)
environmentType = toEnvironmentType(args)
issues []string
state = toState(args)
version = toVersion(args)
deeplink = toLink(args)
)

// ExtractInstanceName extracts the instance name from the provided URL if any
instanceName := ExtractInstanceName(args.Instance)

logger := logrus.
WithField("client_id", args.ClientID).
WithField("cloud_id", args.CloudID).
WithField("project_id", args.Project).
WithField("instance", args.Instance).
WithField("instance", instanceName).
WithField("pipeline", args.Name).
WithField("environment", environ).
WithField("state", state).
WithField("version", version)
WithField("environment Type", environmentType).
WithField("environment ID", environmentID)

if issue == "" {
logger.Debugln("cannot find issue number")
return errors.New("failed to extract issue number")
//check if PLUGIN_ISSUEKEYS is provided
if len(args.IssueKeys) > 0 {
issues = args.IssueKeys
} else {
// fallback to extracting from commit if no issue keys are passed
var issue string = extractIssue(args)
if issue == "" {
logger.Debugln("cannot find issue number")
return errors.New("failed to extract issue number")
}
issues = []string{issue} // add the single issue here for consistency
}

commitMessage := args.Commit.Message
if len(commitMessage) > 255 {
logger.Warnln("Commit message exceeds 255 characters; truncating to fit.")
commitMessage = commitMessage[:252] + "..."
}
if len(commitMessage) > 255 {
logger.Warnln("Commit message exceeds 255 characters; truncating to fit.")
commitMessage = commitMessage[:252] + "..."
}

logger = logger.WithField("issue", issue)
logger.Debugln("successfully extraced issue number")

deploymentPayload := DeploymentPayload{
Deployments: []*Deployment{
{
Deploymentsequencenumber: args.Build.Number,
Updatesequencenumber: args.Build.Number,
IssueKeys: issues,
Associations: []Association{
{
Associationtype: "issueIdOrKeys",
Values: []string{issue},
Values: issues,
},
},
Displayname: strconv.Itoa(args.Build.Number),
Expand All @@ -125,13 +144,49 @@ func Exec(ctx context.Context, args Args) error {
URL: deeplink,
},
Environment: Environment{
ID: environ,
ID: environmentID,
Displayname: environ,
Type: environ,
Type: environmentType,
},
},
},
}
if len(args.IssueKeys) > 0 {
deploymentPayload.Deployments[0].Associations = nil
}
/*fmt.Println("formatted deploymentPayload JSON data")

Choose a reason for hiding this comment

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

remove this comment please. Please make sure those debug/temp/commented out code doesn't appear in final PR

Copy link
Author

Choose a reason for hiding this comment

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

done

jsonData, err := json.MarshalIndent(deploymentPayload, "", " ")
if err != nil {
fmt.Println("Error marshaling to JSON:", err)
}
fmt.Println(string(jsonData))*/

// Initialize an empty reference
references := []Reference{}
// Check if any input is available to update the reference
if args.Commit.Branch != "" || args.Commit.Link != "" || args.Commit.Rev != "" {
var reference Reference
// Update CommitInfo if Rev or Link is provided
if args.Commit.Rev != "" || args.Commit.Link != "" {
reference.Commit = &CommitInfo{
ID: args.Commit.Rev,
RepositoryURI: args.Commit.Link,
}
}
// Update RefInfo if both Branch and Link are provided
if args.Commit.Branch != "" && args.Commit.Link != "" {
reference.Ref = &RefInfo{
Name: args.Commit.Branch,
URI: fmt.Sprintf("%s/refs/%s", args.Commit.Link, args.Commit.Branch),
}
}

// Append the reference if at least one field is populated
if reference.Commit != nil || reference.Ref != nil {
references = append(references, reference)
}
}
// Build the Build struct and include references only if non-empty
buildPayload := BuildPayload{
Builds: []*Build{
{
Expand All @@ -141,13 +196,21 @@ func Exec(ctx context.Context, args Args) error {
URL: deeplink,
LastUpdated: time.Now(),
PipelineID: args.Name,
IssueKeys: []string{issue},
IssueKeys: issues,
State: state,
UpdateSequenceNumber: args.Build.Number,
References: references,
},
},
}

// Print the full data of buildPayload
// Marshaling the Build struct into JSON format with indentation
/*jsonData1, err1 := json.MarshalIndent(buildPayload, "", " ")
if err != nil {
fmt.Println("Error marshaling to JSON:", err1)
}
//Printing the formatted JSON data
fmt.Println(string(jsonData1))*/
// validation of arguments
if (args.ClientID == "" && args.ClientSecret == "") && (args.ConnnectKey == "") {
logger.Debugln("client id and secret are empty. specify the client id and secret or specify connect key")
Expand All @@ -156,7 +219,7 @@ func Exec(ctx context.Context, args Args) error {
// create tokens and deployments
if args.ClientID != "" && args.ClientSecret != "" {
// get cloud id
cloudID, err := getCloudID(args.Instance, args.CloudID)
cloudID, err := getCloudID(instanceName, args.CloudID)
if err != nil {
logger.Debugln("cannot get cloud id")
return err
Expand Down Expand Up @@ -187,15 +250,15 @@ func Exec(ctx context.Context, args Args) error {
}
if args.EnvironmentName != "" {
logger.Infoln("creating deployment")
deploymentErr := createConnectDeployment(deploymentPayload, args.Instance, args.Level, jwtToken)
deploymentErr := createConnectDeployment(deploymentPayload, instanceName, args.Level, jwtToken)
if deploymentErr != nil {
logger.WithError(deploymentErr).
Errorln("cannot create deployment")
return deploymentErr
}
} else {
logger.Infoln("creating build")
buildErr := createConnectBuild(buildPayload, args.Instance, args.Level, jwtToken)
buildErr := createConnectBuild(buildPayload, instanceName, args.Level, jwtToken)
if buildErr != nil {
logger.WithError(buildErr).
Errorln("cannot create build")
Expand All @@ -204,15 +267,23 @@ func Exec(ctx context.Context, args Args) error {
}
}
// only create card if the state is successful
ticketLink := fmt.Sprintf("https://%s.atlassian.net/browse/%s", args.Instance, issue)

var ticketLinks []string

if len(issues) > 0 {
for _, issue_key := range issues {
ticketLink := fmt.Sprintf("https://%s.atlassian.net/browse/%s", args.Instance, issue_key)
ticketLinks = append(ticketLinks, ticketLink)
}
}
cardData := Card{
Pipeline: args.Name,
Instance: args.Instance,
Instance: instanceName,
Project: args.Project,
State: state,
Version: version,
Environment: environ,
URL: ticketLink,
URL: ticketLinks,
}
if err := args.writeCard(cardData); err != nil {
fmt.Printf("Could not create adaptive card. %s\n", err)
Expand All @@ -239,6 +310,16 @@ func getOauthToken(args Args) (string, error) {
return "", err
}
req.Header.Set("Content-Type", "application/json")
/*
// Dump the entire HTTP request
requestDump, err := httputil.DumpRequest(req, true)
if err != nil {
fmt.Println("Error dumping request:", err)
} else {
fmt.Println(string(requestDump))
}
*/

res, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
Expand All @@ -257,6 +338,7 @@ func getOauthToken(args Args) (string, error) {
if err != nil {
return "", err
}
// fmt.Println(output["access_token"].(string))
return output["access_token"].(string), nil
}

Expand Down Expand Up @@ -323,6 +405,16 @@ func createConnectDeployment(payload DeploymentPayload, cloudID, debug, jwtToken
req.Header.Set("Authorization", "Bearer "+jwtToken)
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)

/* jsonData2, err2 := json.MarshalIndent(res, "", " ")
if err != nil {
fmt.Println("Error marshaling to JSON:", err2)
}

//Printing the formatted JSON data
fmt.Println("formatted Build Payload JSON data")
fmt.Println(string(jsonData2))*/

if err != nil {
return err
}
Expand Down Expand Up @@ -357,6 +449,14 @@ func createConnectBuild(payload BuildPayload, cloudID, debug, jwtToken string) e
if err != nil {
return err
}
/* jsonData3, err3 := json.MarshalIndent(res, "", " ")
if err != nil {
fmt.Println("Error marshaling to JSON:", err3)
}

//Printing the formatted JSON data
fmt.Println("formatted Build Payload JSON data")
fmt.Println(string(jsonData3))*/
defer res.Body.Close()
switch debug {
case "debug", "trace", "DEBUG", "TRACE":
Expand Down
81 changes: 43 additions & 38 deletions plugin/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,16 @@ type (

// build provides the build details.
Build struct {
BuildNumber int `json:"buildNumber"`
Description string `json:"description"`
DisplayName string `json:"displayName"`
IssueKeys []string `json:"issueKeys"`
Label string `json:"label"`
LastUpdated time.Time `json:"lastUpdated"`
PipelineID string `json:"pipelineId"`
References []struct {
Commit struct {
ID string `json:"id"`
RepositoryURI string `json:"repositoryUri"`
} `json:"commit"`
Ref struct {
Name string `json:"name"`
URI string `json:"uri"`
} `json:"ref"`
} `json:"references"`
SchemaVersion string `json:"schemaVersion"`
State string `json:"state"`
BuildNumber int `json:"buildNumber"`
Description string `json:"description"`
DisplayName string `json:"displayName"`
IssueKeys []string `json:"issueKeys"`
Label string `json:"label"`
LastUpdated time.Time `json:"lastUpdated"`
PipelineID string `json:"pipelineId"`
References []Reference `json:"references,omitempty"`
SchemaVersion string `json:"schemaVersion"`
State string `json:"state"`
TestInfo struct {
NumberFailed int64 `json:"numberFailed"`
NumberPassed int64 `json:"numberPassed"`
Expand All @@ -44,25 +35,39 @@ type (
UpdateSequenceNumber int `json:"updateSequenceNumber"`
URL string `json:"url"`
}
Reference struct {
Commit *CommitInfo `json:"commit,omitempty"` // Use a pointer to omit if nil
Ref *RefInfo `json:"ref,omitempty"` // Use a pointer to omit if nil
}
CommitInfo struct {
ID string `json:"id,omitempty"`
RepositoryURI string `json:"repositoryUri,omitempty"`
}

RefInfo struct {
Name string `json:"name,omitempty"`
URI string `json:"uri,omitempty"`
}
// Deployment provides the Deployment details.
Deployment struct {
Deploymentsequencenumber int `json:"deploymentSequenceNumber"`
Updatesequencenumber int `json:"updateSequenceNumber"`
Associations []Association `json:"associations"`
Displayname string `json:"displayName"`
URL string `json:"url"`
Description string `json:"description"`
Lastupdated time.Time `json:"lastUpdated"`
State string `json:"state"`
Pipeline JiraPipeline `json:"pipeline"`
Environment Environment `json:"environment"`
Deploymentsequencenumber int `json:"deploymentSequenceNumber"`
//IssueKeys []string `json:"issueKeys"`
IssueKeys []string `json:"issueKeys,omitempty"`
Updatesequencenumber int `json:"updateSequenceNumber"`
Associations []Association `json:"associations"`
Displayname string `json:"displayName"`
URL string `json:"url"`
Description string `json:"description"`
Lastupdated time.Time `json:"lastUpdated"`
State string `json:"state"`
Pipeline JiraPipeline `json:"pipeline"`
Environment Environment `json:"environment"`
}

// Association provides the association details.
Association struct {
Associationtype string `json:"associationType"`
Values []string `json:"values"`
Associationtype string `json:"associationType,omitempty"`
Values []string `json:"values,omitempty"`
}

// Environment provides the environment details.
Expand All @@ -86,12 +91,12 @@ type (

// struct for adaptive card
Card struct {
Pipeline string `json:"pipeline"`
Instance string `json:"instance"`
Project string `json:"project"`
State string `json:"state"`
Version string `json:"version"`
Environment string `json:"environment"`
URL string `json:"url"`
Pipeline string `json:"pipeline"`
Instance string `json:"instance"`
Project string `json:"project"`
State string `json:"state"`
Version string `json:"version"`
Environment string `json:"environment"`
URL []string `json:"url"`
}
)
Loading