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

Create publishToNpm library #21

Merged
merged 5 commits into from
Oct 27, 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
53 changes: 53 additions & 0 deletions tests/jenkins/TestPublishToNpm.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.
*/

package jenkins.tests

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

class TestPublishToNpm extends BuildPipelineTest {
@Override
@Before
void setUp() {

this.registerLibTester(new PublishToNpmLibTester('https://github.com/opensearch-project/opensearch-ci', '1.0.0'))
super.setUp()
}

@Test
public void test() {
super.testPipeline("tests/jenkins/jobs/PublishToNpm_Jenkinsfile")
}

@Test
void 'verify shell commands'(){
runScript('tests/jenkins/jobs/PublishToNpm_Jenkinsfile')

def npmCommands = getShellCommands()
assertThat(npmCommands, hasItem(
'npm set registry "https://registry.npmjs.org"; npm set //registry.npmjs.org/:_authToken NPM_TOKEN; npm publish --dry-run && npm publish --access public'.toString()
))

}
def getShellCommands() {
def shCommands = helper.callStack.findAll { call ->
call.methodName == 'sh'
}.collect { call ->
callArgsToString(call)
}.findAll { npmCommand ->
npmCommand.contains('npm')
}
return shCommands
}
}
24 changes: 24 additions & 0 deletions tests/jenkins/jobs/PublishToNpm_Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.
*/

pipeline {
agent none
stages {
stage('publishToNpm') {
steps {
script {
publishToNpm(
repository: 'https://github.com/opensearch-project/opensearch-ci',
tag: '1.0.0'
)
}
}
}
}
}
10 changes: 10 additions & 0 deletions tests/jenkins/jobs/PublishToNpm_Jenkinsfile.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
PublishToNpm_Jenkinsfile.run()
PublishToNpm_Jenkinsfile.pipeline(groovy.lang.Closure)
PublishToNpm_Jenkinsfile.echo(Executing on agent [label:none])
PublishToNpm_Jenkinsfile.stage(publishToNpm, groovy.lang.Closure)
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.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
Expand Up @@ -9,4 +9,3 @@
standardReleasePipeline.script(groovy.lang.Closure)
standardReleasePipeline.postCleanup()
postCleanup.cleanWs({disableDeferredWipeout=true, deleteDirs=true})
standardReleasePipeline.sh(docker image prune -f --all)
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,3 @@
standardReleasePipeline.script(groovy.lang.Closure)
standardReleasePipeline.postCleanup()
postCleanup.cleanWs({disableDeferredWipeout=true, deleteDirs=true})
standardReleasePipeline.sh(docker image prune -f --all)
42 changes: 42 additions & 0 deletions tests/jenkins/lib-testers/PublishToNpmLibTester.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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 static org.hamcrest.CoreMatchers.notNullValue
import static org.hamcrest.MatcherAssert.assertThat

class PublishToNpmLibTester extends LibFunctionTester {

private String repository
private String tag

public PublishToNpmLibTester(repository, tag){
this.repository = repository
this.tag = tag
}

void configure(helper, binding){
helper.registerAllowedMethod("checkout", [Map], {})
helper.registerAllowedMethod("withCredentials", [Map, Closure], { args, closure ->
closure.delegate = delegate
return helper.callClosure(closure)
})
}
void parameterInvariantsAssertions(call){
assertThat(call.args.repository.first(), notNullValue())
assertThat(call.args.tag.first(), notNullValue())
}

boolean expectedParametersMatcher(call) {
return call.args.repository.first().toString().equals(this.repository)
&& call.args.tag.first().toString().equals(this.tag)
}

String libFunctionName(){
return 'publishToNpm'
}
}
22 changes: 22 additions & 0 deletions vars/publishToNpm.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.
*/

/** Library to publish artifacts to NPM registry under @opensearch-project namespace
@param Map args = [:] args A map of the following parameters
@param args.repository <required> - Repository to be used to publish the artifact to npm
@param args.tag <required> - Tag reference to be used to publish the artifact
*/
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')]){
sh """npm set registry "https://registry.npmjs.org"; npm set //registry.npmjs.org/:_authToken ${NPM_TOKEN}; npm publish --dry-run && npm publish --access public"""
Copy link
Member

Choose a reason for hiding this comment

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

Prefer writing this in multiple lines for easier visibility.

sh """
    <code>
"""

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes its difficult to test things due to whitespace. Hence used the above approach. Similar to https://github.com/opensearch-project/opensearch-build-libraries/blob/main/vars/copyContainer.groovy#L35

Copy link
Member

Choose a reason for hiding this comment

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

Huh, I do find it not ideal for reading, what would happen if the code block is too long to put into one line?

Copy link
Member Author

Choose a reason for hiding this comment

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

This was not long enough that's why used this way. If its very long we can use the approach you suggested or try to break it down.

Copy link
Member

Choose a reason for hiding this comment

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

I think from my experience, we used to publish the client to staging NPM before final publish. Would that be performed on the Jenkinsfile level which calls this library?

Copy link
Member Author

Choose a reason for hiding this comment

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

@zelinh We won't be dealing with staging. If component team wants to follow that they can do on their own. We will only be directly releasing on prod platform

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we could add one another command npm logout at the beginning to make sure we don't accidentally publish to somewhere else or this could be replaced with new login?

Copy link
Member Author

Choose a reason for hiding this comment

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

We are using a token and not logging into the account so no need to log out. The scope of scope is within the withCredentials.

}
}
1 change: 0 additions & 1 deletion vars/standardReleasePipeline.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ void call(Map args = [:], Closure body) {
always {
script {
postCleanup()
sh 'docker image prune -f --all'
Copy link
Member

Choose a reason for hiding this comment

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

Why remove this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Caused an error looking for docker command on agent node.

Copy link
Member

Choose a reason for hiding this comment

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

Will this affect any other jenkinsfile that calls this?
Ex: We want to do the cleanup for docker build.

Copy link
Member Author

Choose a reason for hiding this comment

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

No, this file is not used anywhere today.

Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't agent node supposed to have docker installed? @gaiksaya

Copy link
Member

Choose a reason for hiding this comment

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

@rishabh6788 this file is using docker container running on a jenkins linux agent.
The agent can have docker but the container doesnt have to.
Except docker builder.

Copy link
Collaborator

Choose a reason for hiding this comment

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

understood, thank you!

}
}
}
Expand Down