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

Add standard release pipeline library with generic trigger #22

Merged
merged 6 commits into from
Oct 31, 2022
Merged
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ lib = library(identifier: 'jenkins@<tag>', retriever: modernSCM([
| Name | Description |
|--------------------------------------------------------|:-----------------------------------------------------------------------------------------|
| [standardReleasePipeline.groovy](./vars/standardReleasePipeline.groovy) | The library sets up the necessary jenkins properties for you such as agent label, docker image to use as well as workflow time out. Check how to use the [default](./tests/jenkins/jobs/StandardReleasePipeline_JenkinsFile) in your workflow and how to [overide](./tests/jenkins/jobs/StandardReleasePipelineWithArgs_JenkinsFile) agent & docker image if you need.|
| [standardReleasePipelineWithGenericTrigger.groovy](./vars/standardReleasePipelineWithGenericTrigger.groovy) | A standard release pipeline for OpenSearch projects including generic triggers. A tag or a draft release can be used as a trigger using this library. The defaults are all set to trigger via a draft release. If the release is successful, the release can be published by using right params.. Check how to use the [default](./tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggers_Jenkinsfile) in your workflow and how to [overide](./tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggersTag_Jenkinsfile) values|
| [publishToNpm.groovy](./vars/publishToNpm.groovy) | A library to publish artifacts to NPM registry under @opensearch-project namespace. You can use [PublishToNpmLibTester](./tests/jenkins/lib-testers/PublishToNpmLibTester.groovy) to add tests in your repository. See how to use the lib in your [jenkinsFile](./tests/jenkins/jobs/PublishToNpm_Jenkinsfile)|

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion tests/jenkins/TestStandardReleasePipeline.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class TestStandardReleasePipeline extends BuildPipelineTest {
assertThat(echoCommand, hasItem('Executing on agent [docker:[image:test:image, reuseNode:false, stages:[:], args:, alwaysPull:true, containerPerStageRoot:false, label:AL2-X64]]'))
}

@Test
@Test
void 'check default values'(){
runScript("tests/jenkins/jobs/StandardReleasePipeline_JenkinsFile")
def echoCommand = getEchoCommands().findAll{
Expand Down
101 changes: 101 additions & 0 deletions tests/jenkins/TestStandardReleasePipelineWithGenericTriggers.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/


import jenkins.tests.BuildPipelineTest
import org.junit.Before
import org.junit.Test
import static org.hamcrest.MatcherAssert.assertThat
import static org.hamcrest.CoreMatchers.equalTo
import static com.lesfurets.jenkins.unit.MethodCall.callArgsToString
import static org.hamcrest.CoreMatchers.hasItem



class TestStandardReleasePipelineWithGenericTriggers extends BuildPipelineTest {

@Before
void setUp() {
helper.registerAllowedMethod("GenericTrigger", [Map.class], null)
binding.setVariable('tag', '1.0.0')
binding.setVariable('release_url', 'https://api.github.com/repos/Codertocat/Hello-World/releases/17372790')
super.setUp()
}


@Test
void testStandardReleasePipelineWithGenericTriggers() {
super.testPipeline('tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggers_Jenkinsfile')
}

@Test
void testStandardReleasePipelineWithTagTriggers() {
super.testPipeline('tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggersTag_Jenkinsfile')
}

@Test
void 'validate override values'() {
runScript("tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggers_Jenkinsfile")
def echoCommand = getCommands('echo').findAll{
command -> command.contains('agent')
}

assertThat(echoCommand.size(), equalTo(1))
assertThat(echoCommand, hasItem('Executing on agent [docker:[image:centos:7, reuseNode:false, stages:[:], args:, alwaysPull:true, containerPerStageRoot:false, label:AL2-X64]]'))
}

@Test
void 'validate default triggers'(){
runScript("tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggers_Jenkinsfile")
def cmd = getCommands('GenericTrigger').findAll{
c -> c.contains('generic')
}
assertThat(cmd.size(), equalTo(1))
assertThat(cmd, hasItem('{genericVariables=[{key=ref, value=$.release.tag_name}, {key=isDraft, value=$.release.draft}, {key=release_url, value=$.release.url}], tokenCredentialId=opensearch-ci-webhook-trigger-token, causeString=A tag was cut on opensearch-ci repo, printContributedVariables=false, printPostContent=false, regexpFilterText=$isDraft, regexpFilterExpression=true}'))
}

@Test
void 'validate release is published'(){
runScript("tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggers_Jenkinsfile")
def cmd = getCommands('sh').findAll{
c -> c.contains('curl')
}
assertThat(cmd.size(), equalTo(1))
assertThat(cmd, hasItem("curl -X PATCH -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer GIT_TOKEN' https://api.github.com/repos/Codertocat/Hello-World/releases/17372790 -d '{\"tag_name\":\"1.0.0\",\"draft\":false,\"prerelease\":false}'"))

}

@Test
void 'use tag as trigger'(){
runScript("tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggersTag_Jenkinsfile")
def cmd = getCommands('GenericTrigger').findAll{
c -> c.contains('generic')
}
assertThat(cmd.size(), equalTo(1))
assertThat(cmd, hasItem('{genericVariables=[{key=ref, value=.ref}, {key=isDraft, value=$.release.draft}, {key=release_url, value=$.release.url}], tokenCredentialId=opensearch-ci-webhook-trigger-token, causeString=A tag was cut on opensearch-ci repo, printContributedVariables=false, printPostContent=false, regexpFilterText=$ref, regexpFilterExpression=^refs/tags/.*}'))
}

@Test
void 'validate release is not published'(){
runScript("tests/jenkins/jobs/StandardReleasePipelineWithGenericTriggersTag_Jenkinsfile")
def cmd = getCommands('sh').findAll{
c -> c.contains('curl')
}
assertThat(cmd.size(), equalTo(0))
}

def getCommands(String method) {
def echoCommands = helper.callStack.findAll { call ->
call.methodName == method
}.collect { call ->
callArgsToString(call)
}
return echoCommands
}
}
2 changes: 1 addition & 1 deletion tests/jenkins/jobs/PublishToNpm_Jenkinsfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
PublishToNpm_Jenkinsfile.script(groovy.lang.Closure)
PublishToNpm_Jenkinsfile.publishToNpm({repository=https://github.com/opensearch-project/opensearch-ci, tag=1.0.0})
publishToNpm.checkout({$class=GitSCM, branches=[{name=1.0.0}], userRemoteConfigs=[{url=https://github.com/opensearch-project/opensearch-ci}]})
publishToNpm.string({credentialsId=publish-to-npm-token, variable=NPM_TOKEN})
publishToNpm.string({credentialsId=jenkins-opensearch-publish-to-npm-token, variable=NPM_TOKEN})
publishToNpm.withCredentials([NPM_TOKEN], groovy.lang.Closure)
publishToNpm.sh(npm set registry "https://registry.npmjs.org"; npm set //registry.npmjs.org/:_authToken NPM_TOKEN; npm publish --dry-run && npm publish --access public)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
standardReleasePipelineWithGenericTrigger(jsonValue: '.ref',
tokenIdCredential: 'opensearch-ci-webhook-trigger-token',
causeString: 'A tag was cut on opensearch-ci repo',
regexpFilterText: '$ref',
regexpFilterExpression: '^refs/tags/.*')
{
fakePublishToNpm(
tag: "${tag}"
)
}

def fakePublishToNpm(Map args) {
echo "fakePublishToNpm ${args}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
StandardReleasePipelineWithGenericTriggersTag_Jenkinsfile.run()
StandardReleasePipelineWithGenericTriggersTag_Jenkinsfile.standardReleasePipelineWithGenericTrigger({jsonValue=.ref, tokenIdCredential=opensearch-ci-webhook-trigger-token, causeString=A tag was cut on opensearch-ci repo, regexpFilterText=$ref, regexpFilterExpression=^refs/tags/.*}, groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.pipeline(groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.timeout({time=1, unit=HOURS})
standardReleasePipelineWithGenericTrigger.echo(Executing on agent [docker:[image:opensearchstaging/ci-runner:release-centos7-clients-v1, reuseNode:false, stages:[:], args:, alwaysPull:true, containerPerStageRoot:false, label:Jenkins-Agent-AL2-X64-C54xlarge-Docker-Host]])
standardReleasePipelineWithGenericTrigger.GenericTrigger({genericVariables=[{key=ref, value=.ref}, {key=isDraft, value=$.release.draft}, {key=release_url, value=$.release.url}], tokenCredentialId=opensearch-ci-webhook-trigger-token, causeString=A tag was cut on opensearch-ci repo, printContributedVariables=false, printPostContent=false, regexpFilterText=$ref, regexpFilterExpression=^refs/tags/.*})
standardReleasePipelineWithGenericTrigger.stage(Release, groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.script(groovy.lang.Closure)
StandardReleasePipelineWithGenericTriggersTag_Jenkinsfile.echo(fakePublishToNpm [tag:1.0.0])
standardReleasePipelineWithGenericTrigger.script(groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.postCleanup()
postCleanup.cleanWs({disableDeferredWipeout=true, deleteDirs=true})
standardReleasePipelineWithGenericTrigger.script(groovy.lang.Closure)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
standardReleasePipelineWithGenericTrigger(overrideAgent: 'AL2-X64',
overrideDockerImage: 'centos:7',
tokenIdCredential: 'opensearch-ci-webhook-trigger-token',
causeString: 'A tag was cut on opensearch-ci repo',
publishRelease: true)
{
fakePublishToMaven(
mavenArtifactsPath: "/maven",
autoPublish: true
)
}

def fakePublishToMaven(Map args) {
echo "fakePublishToMaven ${args}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
StandardReleasePipelineWithGenericTriggers_Jenkinsfile.run()
StandardReleasePipelineWithGenericTriggers_Jenkinsfile.standardReleasePipelineWithGenericTrigger({overrideAgent=AL2-X64, overrideDockerImage=centos:7, tokenIdCredential=opensearch-ci-webhook-trigger-token, causeString=A tag was cut on opensearch-ci repo, publishRelease=true}, groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.pipeline(groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.timeout({time=1, unit=HOURS})
standardReleasePipelineWithGenericTrigger.echo(Executing on agent [docker:[image:centos:7, reuseNode:false, stages:[:], args:, alwaysPull:true, containerPerStageRoot:false, label:AL2-X64]])
standardReleasePipelineWithGenericTrigger.GenericTrigger({genericVariables=[{key=ref, value=$.release.tag_name}, {key=isDraft, value=$.release.draft}, {key=release_url, value=$.release.url}], tokenCredentialId=opensearch-ci-webhook-trigger-token, causeString=A tag was cut on opensearch-ci repo, printContributedVariables=false, printPostContent=false, regexpFilterText=$isDraft, regexpFilterExpression=true})
standardReleasePipelineWithGenericTrigger.stage(Release, groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.script(groovy.lang.Closure)
StandardReleasePipelineWithGenericTriggers_Jenkinsfile.echo(fakePublishToMaven [mavenArtifactsPath:/maven, autoPublish:true])
standardReleasePipelineWithGenericTrigger.script(groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.postCleanup()
postCleanup.cleanWs({disableDeferredWipeout=true, deleteDirs=true})
standardReleasePipelineWithGenericTrigger.script(groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.string({credentialsId=jenkins-github-bot-token, variable=GIT_TOKEN})
standardReleasePipelineWithGenericTrigger.withCredentials([GIT_TOKEN], groovy.lang.Closure)
standardReleasePipelineWithGenericTrigger.sh(curl -X PATCH -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer GIT_TOKEN' https://api.github.com/repos/Codertocat/Hello-World/releases/17372790 -d '{"tag_name":"1.0.0","draft":false,"prerelease":false}')
2 changes: 1 addition & 1 deletion vars/publishToNpm.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void call(Map args = [:]) {

checkout([$class: 'GitSCM', branches: [[name: "${args.tag}" ]], userRemoteConfigs: [[url: "${args.repository}" ]]])

withCredentials([string(credentialsId: 'publish-to-npm-token', variable: 'NPM_TOKEN')]){
withCredentials([string(credentialsId: 'jenkins-opensearch-publish-to-npm-token', variable: 'NPM_TOKEN')]){
sh """npm set registry "https://registry.npmjs.org"; npm set //registry.npmjs.org/:_authToken ${NPM_TOKEN}; npm publish --dry-run && npm publish --access public"""
}
}
80 changes: 80 additions & 0 deletions vars/standardReleasePipelineWithGenericTrigger.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

/** A standard release pipeline for OpenSearch projects including generic triggers. A tag or a draft release can be used as a trigger using this library. The defaults are all set to trigger via a draft release. If the release is successful, the release can be published by using right params.
@param Map args = [:] args A map of the following parameters
@param body <Required> - A closure containing release steps to be executed in release stage.
@param args.tokenIdCredential <Required> - Credential id containing token for trigger authentication
@param args.overrideAgent <Optional> - Jenkins agent label to override the default ('Jenkins-Agent-AL2-X64-C54xlarge-Docker-Host')
@param args.overrideDockerImage <Optional> - Docker image to override the default ('opensearchstaging/ci-runner:release-centos7-clients-v1')
@param args.jsonValue <Optional> - Json value retrieved from payload of the webhook. Defaults to '$.release.tag_name'
@param args.causeString <Optional> - String mentioning why the workflow was triggered. Defaults to 'A tag was cut on GitHub repository causing this workflow to run'
@param args.regexpFilterText <Optional> - Variable to apply regular expression on. Defaults to '$isDraft'
@param.regexpFilterExpression <Optional> - Regular expression to test on the evaluated text specified. Defaults to ''
@param.publishRelease <Optional> - If set to true the release that triggered the job will be published on GitHub.
*/

void call(Map args = [:], Closure body) {
pipeline {
agent
{
docker {
label args.overrideAgent ?: 'Jenkins-Agent-AL2-X64-C54xlarge-Docker-Host'
image args.overrideDockerImage ?: 'opensearchstaging/ci-runner:release-centos7-clients-v1'
alwaysPull true
}
}
options {
timeout(time: 1, unit: 'HOURS')
}
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: (args.jsonValue ?: '$.release.tag_name')],
[key: 'isDraft', value: '$.release.draft'],
[key: 'release_url', value: '$.release.url']
],
tokenCredentialId: args.tokenIdCredential,
causeString: args.causeString ?: 'A tag was cut on GitHub repository causing this workflow to run',
printContributedVariables: false,
printPostContent: false,
regexpFilterText: (args.regexpFilterText ?: '$isDraft'),
regexpFilterExpression: (args.regexpFilterExpression ?: 'true')
)
}
environment {
tag = "$ref"
}
stages{
stage("Release") {
steps {
script {
body()
}
}
}
}
post {
success {
script {
if (args.publishRelease && release_url!= null){
withCredentials([string(credentialsId: 'jenkins-github-bot-token', variable: 'GIT_TOKEN')]){
sh "curl -X PATCH -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer ${GIT_TOKEN}' ${release_url} -d '{\"tag_name\":\"${tag}\",\"draft\":false,\"prerelease\":false}'"
}
}
}
}
always {
script {
postCleanup()
}
}
}
}
}