jenkinsci / atlassian-jira-software-cloud-plugin

Atlassian Jira Software Cloud Plugin
https://plugins.jenkins.io/atlassian-jira-software-cloud/
Apache License 2.0
43 stars 46 forks source link

NO-JIRA Override issue extractor with provided list of keys #41

Closed PatrikSchalin-zz closed 3 years ago

PatrikSchalin-zz commented 3 years ago
Bypass the issue extractor run by proviging your own list of issue
keys for those cases when the Jenkins changelog does not reflect
what you want to do.
PatrikSchalin-zz commented 3 years ago

Sometimes it can be useful to make use of the jiraSendDeploymentInfo features even if Jenkins runs a job where the changeset is empty e.g. subsequent manually triggered run on same branch e.g. master. We have these use cases supported by patching the plugin but I wanted to see if there is any interest for this in the plugin.

ghost commented 3 years ago

@PatrikSchalin

This is similar to https://github.com/jenkinsci/atlassian-jira-software-cloud-plugin/pull/26

I'll try to review both PRs this week and pick up one to move forward with this enhancement. Looks like many teams want this feature.

ghost commented 3 years ago

@PatrikSchalin Changes look good. I have left a few minor comments.

PatrikSchalin-zz commented 3 years ago

@lenin-atlassian Great! I'll get on the minor stuff.

PatrikSchalin-zz commented 3 years ago

@lenin-atlassian Made changes based on comments, a bit unsure regarding test though. Went ahead and moved this from draft PR to a proper one, hope it is in order.

ghost commented 3 years ago

@PatrikSchalin Thanks, I have just pushed one minor update to the test. Otherwise it is all looking good. I have also tested this change locally.

I will merge now.

mcascone commented 3 years ago

Hi, can you please clarify since it's not in the documentation yet, we can add an issueKeys parameter to the jiraSendDeploymentInfo step, in cases like the first build on a branch, and for master/develop branches? It's up to us to get the value, but now we can specify it? Thank you in advance!

UPDATE: in my testing, on a PR 'branch', the plugin displays a warning, but still seems to send the info correctly:

//code:
jiraSendDeploymentInfo issueKeys: jiraId,
    environmentId: name, 
    environmentName: name, 
    environmentType: type, 
    site: 'mywork.atlassian.net'

jenkins console output:

 WARNING: Unknown parameter(s) found for class type 'com.atlassian.jira.cloud.jenkins.deploymentinfo.pipeline.JiraSendDeploymentInfoStep': issueKeys
 jiraSendDeploymentInfo: SUCCESS_DEPLOYMENT_ACCEPTED: Successfully sent deployment information to Jira: consilio.atlassian.net. Accepted deployments: [DeploymentKeyResponse{pipelineId='Consilio/workflows/consilio-template-repo/PR-4'environmentId='relativityqa.consiliotest.com', deploymentSequenceNumber=15}].
ghost commented 3 years ago

Hi @mcascone

Thanks for the feedback. I'll follow-up to get the documentation updated.

Reg:

jiraSendDeploymentInfo issueKeys: jiraId,
    environmentId: name, 
    environmentName: name, 
    environmentType: type, 
    site: 'mywork.atlassian.net'

issueKeys has to be a list of string. Eg:

issueKeys: ['SYD-44', 'SYD-45']
PatrikSchalin-zz commented 3 years ago

@mcascone @lenin-atlassian Sorry, guys...docs should have been part of the PR.

mcascone commented 3 years ago

Thanks for the update. I tweaked my code to return a list of string.

For what it's worth, and anyone else coming here, this is what i'm doing - I think it's pretty decent, but I'm always happy to learn a better way!

// in vars/initParms.groovy, called in the init pipeline stage
...
env.commitMessage = getCommitMessage()
...

// vars/getCommitMessage.groovy:

// This should return the whole commit message from the repo's most recent commit.
def call() {
  return pwsh(script: "git log -1 --format=format:%B", returnStdout: true).trim()
}

// in final post pipeline stage:
post {
  always {
    sendJiraBuildInfo()
   }
}
// vars/sendJiraBuildInfo.groovy:

// Sends build info to the JIRA ID in the branch or commit message
// Requires Jira Cloud Jenkins plugin
// getJiraId returns a [list, of, string]
def call() {
  jiraSendBuildInfo branch: getJiraId()[0].toString(), site: 'mycompany.atlassian.net'    
}
// vars/getJiraId.groovy:

// Get the JIRA ID if it's in the branch_name.
// If we're on dev/master/release/PR, we have to get the JIRA ID out of the git log.
// This assumes the Jira ID is in the commit message somewhere.
// getJiraIdFromString returns a [list, of, string] and may be [null]
// (Apparently, PR builds count as 'branches' in Jenkins.)
def call() {
  if (env.BRANCH_NAME ==~ /develop|master|release.*|PR.*/) {
    jiraId = getJiraIdFromString(env.commitMessage)
    echo "Not on a feature branch, got JIRA ID '${jiraId}' from commit message"
  }
  else {
    jiraId = [env.BRANCH_NAME.toUpperCase()]
  }

  return jiraId
}
// vars/getJiraIdFromString.groovy:

// Returns the JIRA ID from a passed-in string.
// Will be Null if it's not there.
def call(String s) {
  // find the regex matches and collect them into a [list]
  // if no matches, returns []
  j = (s =~ /[a-zA-Z0-9]{1,10}-[0-9]+/).collect()

  def r = capitalizeList(j)

  return r
}

// This NonCPS trick is needed due to Jenkins' fail-safe environment.
// Use the spread/splat operator to capitalize each entry
@NonCPS
private static capitalizeList(List l) {
  return l*.toUpperCase()
}

Then for the deploy info, I just do:

// vars/sendJiraDeploymentInfo.groovy:

// Requires Jira Cloud Jenkins plugin
// Valid environment types are 'unmapped', 'development', 'testing', 'staging' and 'production'.
// ID and Name are the same
// Use issueKeys to override branch name - needs to be a [list, of, string]
// getJiraId returns a list of string
def call(String name='unknown', String type='unmapped') {
  jiraSendDeploymentInfo issueKeys: getJiraId(),
    environmentId: name, 
    environmentName: name, 
    environmentType: type, 
    site: 'mycompany.atlassian.net'
}
PatrikSchalin-zz commented 3 years ago

@mcascone Nice, we have a slightly diff use case. Our stable release flow is captured in a pipeline which is triggered by manually invoking the pipeline and thus the pipeline have empty/no changeset. When we do run we want to report all tickets since last stable so we search for multiple keys. Pipeline have all the important tags configured as env vars by previous step.

// vars/extractIssueKeys.groovy

def call(Map config) {
    assert config.fromRef : 'fromRef must be set!'
    assert config.toRef : 'toRef must be set!'

    def commitInfo = sh(script: "git log --pretty=format:\"%s%n%b\" refs/tags/${config.fromRef}..refs/tags/${config.toRef}", returnStdout: true).trim()

    def issueKeys = (commitInfo =~ /[A-Z][A-Z0-9_]{1,}-\d{1,}/).findAll()

    echo message: "Ref range ${config.fromRef}..${config.toRef} contains the following Jira key Ids: ${issueKeys}"

    return issueKeys
}

and pipeline usage in separate stage;

stage('Jira Stable') {
    when {
        expression {
            return params.DO_STABLE_RELEASE == true
        }
    }
    environment {
        //Pipeline step to extract Jira issue keys from commit messages
        ISSUE_KEYS = extractIssueKeys fromRef: "${env.TAG_STABLE_LATEST}", toRef: "${env.NEW_VERSION_TAG}"
    }
    steps {
        //Pipeline step to handle Jira interaction for new releases
        notifyJira version: env.NEW_VERSION_TAG, jiraProjectId: env.JIRA_PROJECT_ID, issueKeys: env.ISSUE_KEYS.tokenize('[,] ')
    }
}