mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
Merge branch 'master' into pr/adjustConfigKeySetsInSteps
This commit is contained in:
commit
2dbfeed813
BIN
documentation/docs/images/githubRelease.png
Normal file
BIN
documentation/docs/images/githubRelease.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
77
documentation/docs/steps/githubPublishRelease.md
Normal file
77
documentation/docs/steps/githubPublishRelease.md
Normal file
@ -0,0 +1,77 @@
|
||||
# githubPublishRelease
|
||||
|
||||
## Description
|
||||
This step creates a tag in your GitHub repository together with a release.
|
||||
|
||||
The release can be filled with text plus additional information like:
|
||||
|
||||
* Closed pull request since last release
|
||||
* Closed issues since last release
|
||||
* link to delta information showing all commits since last release
|
||||
|
||||
The result looks like
|
||||
|
||||
![Example release](../images/githubRelease.png)
|
||||
|
||||
## Prerequisites
|
||||
You need to create a personal access token within GitHub and add this to the Jenkins credentials store.
|
||||
|
||||
Please see [GitHub documentation for details about creating the personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/).
|
||||
|
||||
## Example
|
||||
|
||||
Usage of pipeline step:
|
||||
|
||||
```groovy
|
||||
githubPublishRelease script: this, releaseBodyHeader: "**This is the latest success!**<br />"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|addClosedIssues|no|`false`||
|
||||
|addDeltaToLastRelease|no|`false`||
|
||||
|customFilterExtension|no|``||
|
||||
|excludeLabels|no|<ul><li>`duplicate`</li><li>`invalid`</li><li>`question`</li><li>`wontfix`</li></ul>||
|
||||
|githubApiUrl|no|`//https://api.github.com`||
|
||||
|githubOrg|yes|`script.commonPipelineEnvironment.getGitFolder()`||
|
||||
|githubRepo|yes|`script.commonPipelineEnvironment.getGitRepo()`||
|
||||
|githubServerUrl|no|`https://github.com`||
|
||||
|githubTokenCredentialsId|yes|||
|
||||
|releaseBodyHeader|no|||
|
||||
|version|yes|`script.commonPipelineEnvironment.getArtifactVersion()`||
|
||||
|
||||
### Details:
|
||||
|
||||
* `script` defines the global script environment of the Jenkinsfile run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for storing the measured duration.
|
||||
* All GitHub related properties allow you to overwrite the default behavior of identifying e.g. GitHub organization, GitHub repository.
|
||||
* `version` defines the version number which will be written as tag as well as release name
|
||||
* By defining the `releaseBodyHeader` you can specify the content which will appear for the release
|
||||
* If you set `addClosedIssues` to `true`, a list of all closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`
|
||||
* If you set `addDeltaToLastRelease` to `true`, a link will be added to the relese information that brings up all commits since the last release.
|
||||
* By passing the parameter `customFilterExtension` it is possible to pass additional filter criteria for retrieving closed issues since the last release. Additional criteria could be for example specific `label`, or `filter` according to [GitHub API documentation](https://developer.github.com/v3/issues/).
|
||||
* It is possible to exclude issues with dedicated labels using parameter `excludeLabels`. Usage is like `excludeLabels: ['label1', 'label2']`
|
||||
|
||||
|
||||
## Step configuration
|
||||
|
||||
We recommend to define values of step parameters via [config.yml file](../configuration.md).
|
||||
|
||||
In following sections the configuration is possible:
|
||||
|
||||
| parameter | general | step | stage |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script||||
|
||||
|addClosedIssues||X|X|
|
||||
|addDeltaToLastRelease||X|X|
|
||||
|customFilterExtension||X|X|
|
||||
|excludeLabels||X|X|
|
||||
|githubApiUrl|X|X|X|
|
||||
|githubOrg||X|X|
|
||||
|githubRepo||X|X|
|
||||
|githubServerUrl|X|X|X|
|
||||
|githubTokenCredentialsId|X|X|X|
|
||||
|releaseBodyHeader||X|X|
|
||||
|version||X|X|
|
@ -12,6 +12,7 @@ nav:
|
||||
- dockerExecute: steps/dockerExecute.md
|
||||
- dockerExecuteOnKubernetes: steps/dockerExecuteOnKubernetes.md
|
||||
- durationMeasure: steps/durationMeasure.md
|
||||
- githubPublishRelease: steps/githubPublishRelease.md
|
||||
- gaugeExecuteTests: steps/gaugeExecuteTests.md
|
||||
- handlePipelineStepErrors: steps/handlePipelineStepErrors.md
|
||||
- healthExecuteCheck: steps/healthExecuteCheck.md
|
||||
|
@ -12,6 +12,8 @@ general:
|
||||
from: 'origin/master'
|
||||
to: 'HEAD'
|
||||
format: '%b'
|
||||
githubApiUrl: 'https://api.github.com'
|
||||
githubServerUrl: 'https://github.com'
|
||||
gitSshKeyCredentialsId: '' #needed to allow sshagent to run with local ssh key
|
||||
jenkinsKubernetes:
|
||||
jnlpAgent: 's4sdk/jenkins-agent-k8s:latest'
|
||||
@ -140,6 +142,15 @@ steps:
|
||||
workspace: '**/*.*'
|
||||
stashExcludes:
|
||||
workspace: 'nohup.out'
|
||||
githubPublishRelease:
|
||||
addClosedIssues: false
|
||||
addDeltaToLastRelease: false
|
||||
customFilterExtension: ''
|
||||
excludeLabels:
|
||||
- 'duplicate'
|
||||
- 'invalid'
|
||||
- 'question'
|
||||
- 'wontfix'
|
||||
gaugeExecuteTests:
|
||||
buildTool: 'maven'
|
||||
dockerEnvVars:
|
||||
|
196
test/groovy/GithubPublishReleaseTest.groovy
Normal file
196
test/groovy/GithubPublishReleaseTest.groovy
Normal file
File diff suppressed because one or more lines are too long
134
vars/githubPublishRelease.groovy
Normal file
134
vars/githubPublishRelease.groovy
Normal file
@ -0,0 +1,134 @@
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'githubPublishRelease'
|
||||
@Field Set GENERAL_CONFIG_KEYS = ['githubApiUrl', 'githubTokenCredentialsId', 'githubServerUrl']
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'addClosedIssues',
|
||||
'addDeltaToLastRelease',
|
||||
'customFilterExtension',
|
||||
'excludeLabels',
|
||||
'githubApiUrl',
|
||||
'githubTokenCredentialsId',
|
||||
'githubOrg',
|
||||
'githubRepo',
|
||||
'githubServerUrl',
|
||||
'releaseBodyHeader',
|
||||
'version'
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.addIfEmpty('githubOrg', script.commonPipelineEnvironment.getGithubOrg())
|
||||
.addIfEmpty('githubRepo', script.commonPipelineEnvironment.getGithubRepo())
|
||||
.addIfEmpty('version', script.commonPipelineEnvironment.getArtifactVersion())
|
||||
.withMandatoryProperty('githubOrg')
|
||||
.withMandatoryProperty('githubRepo')
|
||||
.withMandatoryProperty('githubTokenCredentialsId')
|
||||
.withMandatoryProperty('version')
|
||||
.use()
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], config)
|
||||
|
||||
withCredentials([string(credentialsId: config.githubTokenCredentialsId, variable: 'TOKEN')]) {
|
||||
def releaseBody = config.releaseBodyHeader?"${config.releaseBodyHeader}<br />":''
|
||||
def content = getLastRelease(config, TOKEN)
|
||||
if (config.addClosedIssues)
|
||||
releaseBody += addClosedIssue(config, TOKEN, content.published_at)
|
||||
if (config.addDeltaToLastRelease)
|
||||
releaseBody += addDeltaToLastRelease(config, content.tag_name)
|
||||
postNewRelease(config, TOKEN, releaseBody)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map getLastRelease(config, TOKEN){
|
||||
def result = [:]
|
||||
|
||||
def response = httpRequest "${config.githubApiUrl}/repos/${config.githubOrg}/${config.githubRepo}/releases/latest?access_token=${TOKEN}"
|
||||
if (response.status == 200) {
|
||||
result = readJSON text: response.content
|
||||
} else {
|
||||
echo "[${STEP_NAME}] This is the first release - no previous releases available"
|
||||
config.addDeltaToLastRelease = false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
String addClosedIssue(config, TOKEN, publishedAt){
|
||||
if (config.customFilterExtension) {
|
||||
config.customFilterExtension = "&${config.customFilterExtension}"
|
||||
}
|
||||
|
||||
def publishedAtFilter = publishedAt ? "&since=${publishedAt}": ''
|
||||
|
||||
def response = httpRequest "${config.githubApiUrl}/repos/${config.githubOrg}/${config.githubRepo}/issues?access_token=${TOKEN}&per_page=100&state=closed&direction=asc${publishedAtFilter}${config.customFilterExtension}"
|
||||
def result = ''
|
||||
|
||||
content = readJSON text: response.content
|
||||
|
||||
//list closed pull-requests
|
||||
result += '<br />**List of closed pull-requests since last release**<br />'
|
||||
for (def item : content) {
|
||||
if (item.pull_request && !isExcluded(item, config.excludeLabels)) {
|
||||
result += "[#${item.number}](${item.html_url}): ${item.title}<br />"
|
||||
}
|
||||
}
|
||||
//list closed issues
|
||||
result += '<br />**List of closed issues since last release**<br />'
|
||||
for (def item : content) {
|
||||
if (!item.pull_request && !isExcluded(item, config.excludeLabels)) {
|
||||
result += "[#${item.number}](${item.html_url}): ${item.title}<br />"
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
String addDeltaToLastRelease(config, latestTag){
|
||||
def result = ''
|
||||
//add delta link to previous release
|
||||
result += '<br />**Changes**<br />'
|
||||
result += "[${latestTag}...${config.version}](${config.githubServerUrl}/${config.githubOrg}/${config.githubRepo}/compare/${latestTag}...${config.version}) <br />"
|
||||
return result
|
||||
}
|
||||
|
||||
void postNewRelease(config, TOKEN, releaseBody){
|
||||
releaseBody = releaseBody.replace('"', '\\"')
|
||||
//write release information
|
||||
def data = "{\"tag_name\": \"${config.version}\",\"target_commitish\": \"master\",\"name\": \"${config.version}\",\"body\": \"${releaseBody}\",\"draft\": false,\"prerelease\": false}"
|
||||
try {
|
||||
httpRequest httpMode: 'POST', requestBody: data, url: "${config.githubApiUrl}/repos/${config.githubOrg}/${config.githubRepo}/releases?access_token=${TOKEN}"
|
||||
} catch (e) {
|
||||
echo """[${STEP_NAME}] Error occured when writing release information
|
||||
---------------------------------------------------------------------
|
||||
Request body was:
|
||||
---------------------------------------------------------------------
|
||||
${data}
|
||||
---------------------------------------------------------------------"""
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
boolean isExcluded(item, excludeLabels){
|
||||
def result = false
|
||||
excludeLabels.each {labelName ->
|
||||
item.labels.each { label ->
|
||||
if (label.name == labelName) {
|
||||
result = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
Loading…
Reference in New Issue
Block a user