Skip to content

Commit

Permalink
feat: add a parallelDockerUpdateCli shared pipeline combining the bui…
Browse files Browse the repository at this point in the history
…ldDockerAndPublishImage and updatecli ones
  • Loading branch information
lemeurherveCB committed Dec 6, 2021
1 parent 7ba9194 commit 0afc6fc
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 1 deletion.
171 changes: 171 additions & 0 deletions test/groovy/ParallelDockerUpdatecliStepTests.groovy
@@ -0,0 +1,171 @@
import org.junit.Before
import org.junit.Test

import mock.CurrentBuild

import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertTrue

class ParallelDockerUpdatecliStepTests extends BaseTest {
static final String scriptName = 'vars/parallelDockerUpdatecli.groovy'
static final String testImageName = 'myImage'
static final String anotherMainBranchName = 'another'
static final String anotherCronTriggerExpression = '@daily'
static final String anotherContainerMemory = '512Mi'
static final String anotherCredentialsId = 'another-github-token'

@Override
@Before
void setUp() throws Exception {
super.setUp()
// Mocks of the shared pipelines we want to test
helper.registerAllowedMethod('buildDockerAndPublishImage', [String.class, Map.class], { s, m -> s + m })
helper.registerAllowedMethod('updatecli', [Map.class], { m -> m })

// Default behavior is a build trigger by a timertrigger on the main branch (most frequent case)
binding.setProperty('currentBuild', new CurrentBuild('SUCCESS', ['hudson.triggers.TimerTrigger']))
}

@Test
void itFailsWithDefault() throws Exception {
def script = loadScript(scriptName)

// when calling with the "parallelDockerUpdatecli" function with default configuration
script.call()
printCallStack()

// Then we expect a failing build
assertJobStatusFailure()

// And the error message is shown
assertTrue(assertMethodCallContainsPattern('echo', 'Error: no imageName provided.'))
}

@Test
void itRunsSuccessfullyWithImageNameOnPrimaryBranch() throws Exception {
def script = loadScript(scriptName)

// when calling with the "parallelDockerUpdatecli" function with default configuration on the primary branch
addEnvVar('BRANCH_IS_PRIMARY', 'true')
script.call(imageName: testImageName)
printCallStack()

// Then we expect a successfull build
assertJobStatusSuccess()

// And the error message is not shown
assertFalse(assertMethodCallContainsPattern('echo', 'Error: no imageName provided.'))

// And the correct image name is passed to buildDockerAndPublishImage
assertTrue(assertMethodCallContainsPattern('buildDockerAndPublishImage', testImageName))

// And updatecli(action: 'diff') is called
assertTrue(assertMethodCallContainsPattern('updatecli', 'action=diff'))

// And updatecli(action: 'apply') is called only if we are on the primary branch
assertTrue(assertMethodCallContainsPattern('updatecli', 'action=apply'))
}

@Test
void itRunsSuccessfullyWithImageNameNotOnPrimaryBranch() throws Exception {
def script = loadScript(scriptName)

// when calling with the "parallelDockerUpdatecli" function with default configuration not on the primary branch (env.BRANCH_IS_PRIMARY not set)
script.call(imageName: testImageName)
printCallStack()

// Then we expect a successfull build
assertJobStatusSuccess()

// And the error message is not shown
assertFalse(assertMethodCallContainsPattern('echo', 'Error: no imageName provided.'))

// And the correct image name is passed to buildDockerAndPublishImage
assertTrue(assertMethodCallContainsPattern('buildDockerAndPublishImage', testImageName))

// And updatecli(action: 'diff') is called
assertTrue(assertMethodCallContainsPattern('updatecli', 'action=diff'))

// And updatecli(action: 'apply') is called only if we are on the primary branch
assertFalse(assertMethodCallContainsPattern('updatecli', 'action=apply'))
}

@Test
void itRunsSuccessfullyWithImageNameWithoutRebuildImage() throws Exception {
def script = loadScript(scriptName)

// when calling with the "parallelDockerUpdatecli" function with rebuildImageOnPeriodicJob set to false
script.call(imageName: testImageName, rebuildImageOnPeriodicJob: false)
printCallStack()

// Then we expect a successfull build
assertJobStatusSuccess()

// And the error message is not shown
assertFalse(assertMethodCallContainsPattern('echo', 'Error: no imageName provided.'))

// And buildDockerAndPublishImage is not called (default behavior set as a build trigger by a TimerTrigger)
assertFalse(assertMethodCallContainsPattern('buildDockerAndPublishImage', testImageName))

// And updatecli(action: 'diff') is called
assertTrue(assertMethodCallContainsPattern('updatecli', 'action=diff'))
}

@Test
void itRunsSuccessfullyWithImageNameWithoutRebuildImageNorTimerTrigger() throws Exception {
def script = loadScript(scriptName)

// when calling with the "parallelDockerUpdatecli" function with rebuildImageOnPeriodicJob set to false, and the trigger is not a TimerTrigger
binding.setProperty('currentBuild', new CurrentBuild('SUCCESS', ['hudson.triggers.NotATimerTrigger']))
script.call(imageName: testImageName, rebuildImageOnPeriodicJob: false)
printCallStack()

// Then we expect a successfull build
assertJobStatusSuccess()

// And the error message is not shown
assertFalse(assertMethodCallContainsPattern('echo', 'Error: no imageName provided.'))

// And buildDockerAndPublishImage is called (default behavior set as a build trigger which is not a timertrigger)
assertTrue(assertMethodCallContainsPattern('buildDockerAndPublishImage', testImageName))

// And updatecli(action: 'diff') is called
assertTrue(assertMethodCallContainsPattern('updatecli', 'action=diff'))
}


@Test
void itRunsSuccessfullyWithCustomParameters() throws Exception {
def script = loadScript(scriptName)

// when calling with the "parallelDockerUpdatecli" function with custom parameters
// Note: imageName & rebuildImageOnPeriodicJob have already been tested in other tests
addEnvVar('BRANCH_IS_PRIMARY', 'true')
script.call(
imageName: testImageName,
mainBranch: anotherMainBranchName,
cronTriggerExpression: anotherCronTriggerExpression,
containerMemory: anotherContainerMemory,
credentialsId: anotherCredentialsId
)
printCallStack()

// Then we expect a successfull build
assertJobStatusSuccess()

// And the error message is not shown
assertFalse(assertMethodCallContainsPattern('echo', 'Error: no imageName provided.'))

// And the correct image name is passed to buildDockerAndPublishImage
assertTrue(assertMethodCallContainsPattern('buildDockerAndPublishImage', testImageName))

// And updatecli(action: 'diff') is called
assertTrue(assertMethodCallContainsPattern('updatecli', 'action=diff'))

// And the custom parameters are taken in account
assertTrue(assertMethodCallContainsPattern('buildDockerAndPublishImage', 'mainBranch=' + anotherMainBranchName))
assertTrue(assertMethodCallContainsPattern('string', anotherCredentialsId))
assertTrue(assertMethodCallContainsPattern('updatecli', 'cronTriggerExpression=' + anotherCronTriggerExpression))
assertTrue(assertMethodCallContainsPattern('updatecli', 'containerMemory=' + anotherContainerMemory))
}
}
12 changes: 11 additions & 1 deletion test/groovy/mock/CurrentBuild.groovy
Expand Up @@ -5,5 +5,15 @@ package mock
*/
class CurrentBuild implements Serializable {
String result
public CurrentBuild(String result) { this.result = result }
ArrayList buildCauses

public CurrentBuild(String result) {
this.result = result
this.buildCauses = []
}

public CurrentBuild(String result, ArrayList buildCauses) {
this.result = result
this.buildCauses = buildCauses
}
}
40 changes: 40 additions & 0 deletions vars/parallelDockerUpdatecli.groovy
@@ -0,0 +1,40 @@
def call(userConfig = [:]) {
def defaultConfig = [
imageName: '',
mainBranch: 'main',
rebuildImageOnPeriodicJob: true,
cronTriggerExpression: '@weekly',
containerMemory: '128Mi',
credentialsId: 'updatecli-github-token'
]

// Merging the 2 maps - https://blog.mrhaki.com/2010/04/groovy-goodness-adding-maps-to-map_21.html
final Map finalConfig = defaultConfig << userConfig

if (finalConfig.imageName == '') {
echo 'Error: no imageName provided.'
currentBuild.result = 'FAILURE'
return
}
parallel(
failFast: true,
'docker-image': {
// Do not rebuild the image when triggered by a periodic job if the config desactivate them
if (finalConfig.rebuildImageOnPeriodicJob || (!finalConfig.rebuildImageOnPeriodicJob && !currentBuild.getBuildCauses().contains('hudson.triggers.TimerTrigger'))) {
buildDockerAndPublishImage(finalConfig.imageName, [
mainBranch: finalConfig.mainBranch,
automaticSemanticVersioning: true,
gitCredentials: 'github-app-infra'
])
}
},
'updatecli': {
withCredentials([string(credentialsId: finalConfig.credentialsId,variable: 'UPDATECLI_GITHUB_TOKEN')]) {
updatecli(action: 'diff')
if (env.BRANCH_IS_PRIMARY) {
updatecli(action: 'apply', cronTriggerExpression: finalConfig.cronTriggerExpression, containerMemory: finalConfig.containerMemory)
}
}
},
)
}
18 changes: 18 additions & 0 deletions vars/parallelDockerUpdatecli.txt
@@ -0,0 +1,18 @@
This pipeline combines "buildDockerAndPublishImage" and "updatecli" shared pipelines. It lints, Builds, Tests and eventually Publishes a Docker image, and run in parallel updatecli.

The following arguments are available for this function:
- String **imageName**: (Mandatory) name of the image to built, usually referenced as the "Repository" part of a Docker image's name without any tag (Example: "builder" or "terraform").
- String **mainBranch**: (Optional - Default: "main") name of the main branch of the repository
- String **rebuildImageOnPeriodicJob**: (Optional - Default: true) specify if the docker image has to be rebuilt and republished when triggered by a periodic job.
- String **cronTriggerExpression**: (Optional - Default: "@weekly") Enable periodic updatecli execution by providing a cron-like expression.
- String **containerMemory**: (Optional - Default: "128Mi") specify the amount of memory dedicated to the updatecli container.
- String **credentialsId**: (Optional - Default: "updatecli-github-token") specify the credentials used by updatecli to interact with github.

Examples:
<code>
// build and publish the docker image, and in parallel run "updatecli diff" command and also "updatecli apply" if the pipeline is on the main branch.
parallelDockerUpdatecli([imageName: 'myDockerImage'])

// build and publish the docker image only if there is a code change, and in parallel run "updatecli diff" command and also "updatecli apply" if the pipeline is on the main branch.
parallelDockerUpdatecli([imageName: 'myDockerImage', rebuildImageOnPeriodicJob: false])
</code>

0 comments on commit 0afc6fc

Please sign in to comment.