From d52cc56f3e591cc3ee24bd4acac08fd71a5ff1ae Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Thu, 11 Mar 2021 14:55:13 -0500 Subject: [PATCH 01/10] starting to update Justfile and Contributors guide --- CONTRIBUTING.adoc | 41 +++++++++++++++++++++++++++++++++++++++++ Justfile | 3 +++ 2 files changed, 44 insertions(+) create mode 100644 CONTRIBUTING.adoc create mode 100644 Justfile diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc new file mode 100644 index 000000000..7d1c7ce22 --- /dev/null +++ b/CONTRIBUTING.adoc @@ -0,0 +1,41 @@ +:toc: + +# Contributors Guide + +## Local Environment + +.Tools +|=== +| Tool | Purpose + +| https://gradle.org[Gradle] +| Used to run unit tests, package the JPI, and publish the plugin + +| https://github.com/casey/just[Just] +| A task runner. Used here to automate common commands used during development. + +| https://www.docker.com/get-started[Docker] +| Used to run a local Jenkins instance for testing. + +|=== + + +## Running Tests + +### Execute all the tests + +To run all the tests, run: + +[source,bash] +---- +just test +---- + +### Execute tests for a specific class + +To run tests for a specific Class, `StepWrapperSpec` for example, run: + +[source,bash] +---- +just test '*.StepWrapperSpec' +---- \ No newline at end of file diff --git a/Justfile b/Justfile new file mode 100644 index 000000000..b4a16142d --- /dev/null +++ b/Justfile @@ -0,0 +1,3 @@ +test class="*": + ./gradlew test --tests '{{class}}' + From dada4306c9f5571f7633e1a67e52dbfc1cd6468a Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Thu, 11 Mar 2021 17:48:11 -0500 Subject: [PATCH 02/10] update --- CONTRIBUTING.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 7d1c7ce22..f74678128 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -38,4 +38,13 @@ To run tests for a specific Class, `StepWrapperSpec` for example, run: [source,bash] ---- just test '*.StepWrapperSpec' +---- + +## Building the JPI + +To build the JPI, run: + +[source, bash] +---- +just jpi ---- \ No newline at end of file From 1329f4b317164375c45463fdb3b03d43313262d2 Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Sat, 13 Mar 2021 14:12:52 -0500 Subject: [PATCH 03/10] update justfile and docs --- CONTRIBUTING.adoc | 89 ++++++++++++- Justfile | 86 +++++++++++- build.gradlee | 126 ++++++++++++++++++ docs/modules/developer/nav.adoc | 1 + .../modules/developer/pages/CONTRIBUTING.adoc | 1 + 5 files changed, 298 insertions(+), 5 deletions(-) create mode 100644 build.gradlee create mode 120000 docs/modules/developer/pages/CONTRIBUTING.adoc diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index f74678128..b5511dc49 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -15,15 +15,13 @@ | A task runner. Used here to automate common commands used during development. | https://www.docker.com/get-started[Docker] -| Used to run a local Jenkins instance for testing. +| Used to build the documentation for local preview |=== ## Running Tests -### Execute all the tests - To run all the tests, run: [source,bash] @@ -31,6 +29,8 @@ To run all the tests, run: just test ---- +The gradle test report is published to `build/target/tests/test/index.html` + ### Execute tests for a specific class To run tests for a specific Class, `StepWrapperSpec` for example, run: @@ -40,6 +40,32 @@ To run tests for a specific Class, `StepWrapperSpec` for example, run: just test '*.StepWrapperSpec' ---- +### Code Coverage + +By default, JaCoCo code coverage is enabled when running test. + +Once executed, the JaCoCo coverage report can be found at: `build/reports/jacoco/test/html/index.html` + +To disable this, run: + +[source, bash] +---- +just --set coverage false test +---- + +## Linting + +This project uses https://github.com/diffplug/spotless[Spotless] and https://github.com/CodeNarc/CodeNarc[CodeNarc] to perform linting. The CodeNarc rule sets for `src/main` and `src/test` can be found in `config/codenarc/rules.groovy` and `config/codenarc/rulesTest.groovy`, respectively. + +Once executed, the reports can be found at `build/reports/codenarc/main.html` and `build/reports/codenarc/test.html`. + +To execute linting, run: + +[source,groovy] +---- +just lint +---- + ## Building the JPI To build the JPI, run: @@ -47,4 +73,59 @@ To build the JPI, run: [source, bash] ---- just jpi ----- \ No newline at end of file +---- + +Once built, the JPI will be located at `build/libs/templating-engine.jpi` + +## Building the Documentation + +This project uses https://antora.org/[Antora] to build the documentation. + +To build the documentation, run: + +[source, bash] +---- +just docs +---- + +Once built, the documentation can be viewed at `docs/html/index.html` + +### Customizing the documentation output directory + +The `docsDir` justfile variable configures the output directory. + +To modify the output directory, run: + +[source, bash] +---- +just --set docsDir some/other/directory docs +---- + +## Publishing JTE + +**If you have the permission**, you can cut a new release of JTE by running `just release `. + +For example: + +[source, bash] +---- +just release 2.0.4 +---- + +This will: + +1. create a `release/2.0.4` branch +2. update the version in the `build.gradle` +3. update the version in the `docs/antora.yml` +4. push those changes +5. create a `2.0.4` tag +6. publish the JPI + +[NOTE] +==== +Don't forget to go to the https://github.com/jenkinsci/templating-engine-plugin/releases[Releases Page] to officially release JTE with the current change log based off the most recent tag. +==== + +## Run a containerized Jenkins + +### Mounting local libraries for testing \ No newline at end of file diff --git a/Justfile b/Justfile index b4a16142d..4e5c406b9 100644 --- a/Justfile +++ b/Justfile @@ -1,3 +1,87 @@ +# when false, disables code coverage +coverage := "true" +# the output directory for the documentation +docsDir := "docs/html" +# the Antora playbook file to use when building docs +playbook := "docs/antora-playbook-local.yml" +# variables for running containerized jenkins +container := "jenkins" # the name of the container +port := "8080" # the port to forward Jenkins to + +# describes available recipes +help: + just --list --unsorted + +# wipe local caches +clean: + ./gradlew clean + rm -rf {{docsDir}} + +# Run unit tests test class="*": - ./gradlew test --tests '{{class}}' + #!/usr/bin/env bash + set -euxo pipefail + coverage=$([[ {{coverage}} == "true" ]] && echo "jacocoTestReport" || echo "") + ./gradlew test --tests '{{class}}' $coverage + +# Run spotless & codenarc +lint: + ./gradlew spotlessApply codenarc + +# Build the JPI +jpi: + ./gradlew clean jpi + +# executes the CI checks (test lint jpi) +ci: test lint jpi + +# Build the local Antora documentation +docs: + docker run \ + -it --rm \ + -v ~/.git-credentials:/home/antora/.git-credentials \ + -v $(pwd):/app -w /app \ + docker.pkg.github.com/boozallen/sdp-docs/builder \ + generate --generator booz-allen-site-generator \ + --to-dir {{docsDir}} \ + {{playbook}} + +# publishes the jpi +release version branch=`git branch --show-current`: + #!/usr/bin/env bash + if [[ ! "{{branch}}" == "justfile" ]]; then + echo "You can only cut a release from the 'main' branch." + echo "Currently on branch '{{branch}}'" + exit 1 + fi + # cut a release branch + git checkout -B release/{{version}} + # bump the version in relevant places + sed -ie "s/^version.*/version = '{{version}}'/g" build.gradle + sed -ie "s/^version:.*/version: '{{version}}'/g" docs/antora.yml + git add build.gradle docs/antora.yml + git commit -m "bump version to {{version}}" + git push --set-upstream origin release/{{version}} + # push a tag for this release + git tag {{version}} + git push origin refs/tags/{{version}} + # publish the JPI + ./gradlew publish + +# run a containerized jenkins instace +run flags='': + docker pull jenkins/jenkins:lts + docker run -d \ + --publish {{port}}:8080 \ + --name {{container}} \ + {{flags}} \ + jenkins/jenkins:lts +# swap the JPI in a running container and restart +reload: + if [ ! "$(docker ps -qaf name={{container}})" ]; then echo "container '{{container}}' not found'" && exit 1; fi + if [ ! "$(docker ps -qaf name={{container}} -f status=running)" ]; then docker start {{container}}; fi + just jpi + docker exec -it {{container}} /bin/bash -c "rm -rf /var/jenkins_home/plugins/templating-engine{,.*}" + docker cp build/libs/templating-engine.hpi {{container}}:/var/jenkins_home/plugins/templating-engine.hpi + docker restart {{container}} \ No newline at end of file diff --git a/build.gradlee b/build.gradlee new file mode 100644 index 000000000..ae7c245e2 --- /dev/null +++ b/build.gradlee @@ -0,0 +1,126 @@ +plugins { + id 'groovy' + id 'org.jenkins-ci.jpi' version '0.42.0' + id 'jacoco' + id "com.diffplug.gradle.spotless" version "3.29.0" + id 'codenarc' +} + +repositories { + jcenter() + maven { + url('https://repo.jenkins-ci.org/public/') + } +} + +group = 'org.jenkins-ci.plugins' +version = '2.0.4' +description = 'Allows users to create tool-agnostic, templated pipelines to be shared by multiple teams' + +jenkinsPlugin { + coreVersion = '2.138.1' + shortName = 'templating-engine' + displayName = 'Templating Engine' + url = 'https://github.com/jenkinsci/templating-engine-plugin' + disabledTestInjection = false + localizerOutputDir = "${project.buildDir}/generated-src/localizer" + configureRepositories = false + configurePublishing = true + developers { + developer { + id 'steven-terrana' + name 'Steven Terrana' + email 'terrana_steven@bah.com' + } + developer { + id 'carlosokieffebah' + name 'Carlos Okieffe' + email 'okieffe_carlos@bah.com' + } + } +} + +dependencies { + // plugin dependencies + implementation 'org.jenkins-ci.plugins.workflow:workflow-multibranch:2.20' + implementation 'org.jenkins-ci.plugins.workflow:workflow-api:2.28' + implementation 'org.jenkins-ci.plugins:branch-api:2.0.20' + implementation 'org.jenkins-ci.plugins:scm-api:2.2.7' + implementation 'org.jenkins-ci.plugins:junit:1.24' + implementation 'org.jenkins-ci.plugins:github-branch-source:2.5.1' + implementation 'org.jgrapht:jgrapht-core:1.4.0' + + // unit test dependencies + testImplementation 'junit:junit:4.12' + testImplementation 'org.spockframework:spock-core:1.3-groovy-2.4' + testImplementation 'net.bytebuddy:byte-buddy:1.10.7' // used by Spock + testImplementation 'org.objenesis:objenesis:3.1' // used by Spock + testImplementation(group: 'org.jenkins-ci.plugins', name: 'git', version:'3.9.3', classifier:'tests') { + exclude(module: 'httpclient') + exclude(module: 'annotation-indexer') + } + + testImplementation(group: "org.jenkins-ci.main", name: "jenkins-test-harness", version: "2.71") + + // test plugins + testImplementation(group: "org.jenkins-ci.plugins.workflow", name: "workflow-support", classifier: "tests") + testImplementation(group: "org.jenkins-ci.plugins", name: "scm-api", version: "2.3.0", classifier: "tests") + testImplementation(group: 'org.jenkins-ci.plugins', name: 'git', version:'3.9.3') { + exclude(module: 'httpclient') + exclude(module: 'annotation-indexer') + } + testImplementation 'org.jenkins-ci.plugins:token-macro:1.12.1' + testImplementation 'org.jenkins-ci.plugins.workflow:workflow-aggregator:2.6' + testImplementation 'org.jenkins-ci.plugins.workflow:workflow-step-api:2.19' +} + +jacocoTestReport { + reports { + html.enabled true + } +} + +spotless{ + groovy{ + target = fileTree("src/main/groovy") + fileTree(dir: "src/main/resources", include: "**/*.groovy") + fileTree("src/test/groovy") + trimTrailingWhitespace() + indentWithSpaces() + endWithNewline() + licenseHeaderFile 'groovy.header' + } +} + +codenarc { + toolVersion = '1.6.1' + configFile = file('./config/codenarc/rules.groovy') + +} + +codenarcMain{ + source = fileTree("src/main/groovy") + fileTree(dir: "src/main/resources", include: "**/*.groovy") +} + +codenarcTest{ + configFile = file('./config/codenarc/rulesTest.groovy') +} + +task codenarc { + description = "Evaluate code against CodeNarc" + dependsOn = [ 'codenarcMain', 'codenarcTest' ] +} + +sourceSets { + main{ + java{ + srcDirs = [] + } + groovy { + srcDirs = ["src/main/groovy", "src/main/java"] + exclude "**/package-info.groovy" + } + } +} + +groovydoc{ + source fileTree("src/main/groovy") +} diff --git a/docs/modules/developer/nav.adoc b/docs/modules/developer/nav.adoc index b2c4e5c30..8f4ec729f 100644 --- a/docs/modules/developer/nav.adoc +++ b/docs/modules/developer/nav.adoc @@ -1,2 +1,3 @@ * xref:index.adoc[Developer Documentation] +** xref:CONTRIBUTING.adoc[Contributing] ** xref:initialization.adoc[Initialization Process] \ No newline at end of file diff --git a/docs/modules/developer/pages/CONTRIBUTING.adoc b/docs/modules/developer/pages/CONTRIBUTING.adoc new file mode 120000 index 000000000..b58c1b761 --- /dev/null +++ b/docs/modules/developer/pages/CONTRIBUTING.adoc @@ -0,0 +1 @@ +../../../../CONTRIBUTING.adoc \ No newline at end of file From 360575764530f333e51358f434d044c4cbf11d1d Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Sun, 14 Mar 2021 11:32:46 -0400 Subject: [PATCH 04/10] update --- CONTRIBUTING.adoc | 57 ++++++++++++++++++++++++++++++++++++++++++++++- Justfile | 6 ++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index b5511dc49..82c854b79 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -128,4 +128,59 @@ Don't forget to go to the https://github.com/jenkinsci/templating-engine-plugin/ ## Run a containerized Jenkins -### Mounting local libraries for testing \ No newline at end of file +It is often helpful to run Jenkins in a container locally to test various scenarios with JTE during development. + +[source, bash] +---- +just run +---- + +With the default settings, this will expose jenkins on http://localhost:8080 + +### Change the container name + +[source, bash] +---- +just --set container someName run +---- + +### Change the port forwarding target + +[source, bash] +---- +just --set port 9000 run +---- + +### Pass arbitrary flags to the container + +Parameters passed to `just run` are sent as flags to the `docker run` command. + +[source, bash] +---- +just run -e SOMEVAR="some var" +---- + +### Mounting local libraries for testing + +Local directories can be configured as Git SCM library sources even if they do not have a remote repository. + +For example, if `~/local-libraries` is a directory containing a local git repository then to mount it to the container you would run: + +[source, bash] +---- +just run -v ~/local-libraries:/local-libraries +---- + +You could then configure a library source using the file protocol to specify the repository location at `file:///local-libraries` + +[TIP] +==== +When using this technique, changes to the libraries must be committed to be found. In a separate terminal, run: + +[source, bash] +---- +just watch ~/local-libraries +---- + +to automatically commit changes to the libraries. +==== \ No newline at end of file diff --git a/Justfile b/Justfile index 4e5c406b9..9ff5fc324 100644 --- a/Justfile +++ b/Justfile @@ -84,4 +84,8 @@ reload: just jpi docker exec -it {{container}} /bin/bash -c "rm -rf /var/jenkins_home/plugins/templating-engine{,.*}" docker cp build/libs/templating-engine.hpi {{container}}:/var/jenkins_home/plugins/templating-engine.hpi - docker restart {{container}} \ No newline at end of file + docker restart {{container}} + +# watches the given path to commit all changes as they occur +watch path: + watchexec 'cd {{path}} && git add -A && git commit -m "update"' -w {{path}} \ No newline at end of file From 7ad7fdce775e9a1580598127c7ca318c698797d4 Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Sun, 14 Mar 2021 11:33:40 -0400 Subject: [PATCH 05/10] update --- Makefile | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index a672de89d..000000000 --- a/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Minimal makefile to build Antora documentation -BUILDDIR = docs/html -PLAYBOOK = docs/antora-playbook-local.yml - -# Put it first so that "make" without argument is like "make help". -help: ## Show target options - @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//' - -clean: ## removes remote documentation and compiled documentation - rm -rf $(BUILDDIR) - -.PHONY: docs -docs: clean ## builds the antora documentation - docker run \ - -t --rm \ - -v ~/.git-credentials:/home/antora/.git-credentials \ - -v $(shell pwd):/app -w /app \ - docker.pkg.github.com/boozallen/sdp-docs/builder \ - generate --generator booz-allen-site-generator \ - --to-dir $(BUILDDIR) \ - $(PLAYBOOK) - -jpi: ## builds the jpi via gradle - ./gradlew clean jpi - -test: ## runs the plugin's test suite - ./gradlew clean test - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - echo "Make command $@ not found" \ No newline at end of file From 275db281b1907161713fc854cfa377db14c08781 Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Sun, 14 Mar 2021 11:37:32 -0400 Subject: [PATCH 06/10] update --- build.gradlee | 126 -------------------------------------------------- 1 file changed, 126 deletions(-) delete mode 100644 build.gradlee diff --git a/build.gradlee b/build.gradlee deleted file mode 100644 index ae7c245e2..000000000 --- a/build.gradlee +++ /dev/null @@ -1,126 +0,0 @@ -plugins { - id 'groovy' - id 'org.jenkins-ci.jpi' version '0.42.0' - id 'jacoco' - id "com.diffplug.gradle.spotless" version "3.29.0" - id 'codenarc' -} - -repositories { - jcenter() - maven { - url('https://repo.jenkins-ci.org/public/') - } -} - -group = 'org.jenkins-ci.plugins' -version = '2.0.4' -description = 'Allows users to create tool-agnostic, templated pipelines to be shared by multiple teams' - -jenkinsPlugin { - coreVersion = '2.138.1' - shortName = 'templating-engine' - displayName = 'Templating Engine' - url = 'https://github.com/jenkinsci/templating-engine-plugin' - disabledTestInjection = false - localizerOutputDir = "${project.buildDir}/generated-src/localizer" - configureRepositories = false - configurePublishing = true - developers { - developer { - id 'steven-terrana' - name 'Steven Terrana' - email 'terrana_steven@bah.com' - } - developer { - id 'carlosokieffebah' - name 'Carlos Okieffe' - email 'okieffe_carlos@bah.com' - } - } -} - -dependencies { - // plugin dependencies - implementation 'org.jenkins-ci.plugins.workflow:workflow-multibranch:2.20' - implementation 'org.jenkins-ci.plugins.workflow:workflow-api:2.28' - implementation 'org.jenkins-ci.plugins:branch-api:2.0.20' - implementation 'org.jenkins-ci.plugins:scm-api:2.2.7' - implementation 'org.jenkins-ci.plugins:junit:1.24' - implementation 'org.jenkins-ci.plugins:github-branch-source:2.5.1' - implementation 'org.jgrapht:jgrapht-core:1.4.0' - - // unit test dependencies - testImplementation 'junit:junit:4.12' - testImplementation 'org.spockframework:spock-core:1.3-groovy-2.4' - testImplementation 'net.bytebuddy:byte-buddy:1.10.7' // used by Spock - testImplementation 'org.objenesis:objenesis:3.1' // used by Spock - testImplementation(group: 'org.jenkins-ci.plugins', name: 'git', version:'3.9.3', classifier:'tests') { - exclude(module: 'httpclient') - exclude(module: 'annotation-indexer') - } - - testImplementation(group: "org.jenkins-ci.main", name: "jenkins-test-harness", version: "2.71") - - // test plugins - testImplementation(group: "org.jenkins-ci.plugins.workflow", name: "workflow-support", classifier: "tests") - testImplementation(group: "org.jenkins-ci.plugins", name: "scm-api", version: "2.3.0", classifier: "tests") - testImplementation(group: 'org.jenkins-ci.plugins', name: 'git', version:'3.9.3') { - exclude(module: 'httpclient') - exclude(module: 'annotation-indexer') - } - testImplementation 'org.jenkins-ci.plugins:token-macro:1.12.1' - testImplementation 'org.jenkins-ci.plugins.workflow:workflow-aggregator:2.6' - testImplementation 'org.jenkins-ci.plugins.workflow:workflow-step-api:2.19' -} - -jacocoTestReport { - reports { - html.enabled true - } -} - -spotless{ - groovy{ - target = fileTree("src/main/groovy") + fileTree(dir: "src/main/resources", include: "**/*.groovy") + fileTree("src/test/groovy") - trimTrailingWhitespace() - indentWithSpaces() - endWithNewline() - licenseHeaderFile 'groovy.header' - } -} - -codenarc { - toolVersion = '1.6.1' - configFile = file('./config/codenarc/rules.groovy') - -} - -codenarcMain{ - source = fileTree("src/main/groovy") + fileTree(dir: "src/main/resources", include: "**/*.groovy") -} - -codenarcTest{ - configFile = file('./config/codenarc/rulesTest.groovy') -} - -task codenarc { - description = "Evaluate code against CodeNarc" - dependsOn = [ 'codenarcMain', 'codenarcTest' ] -} - -sourceSets { - main{ - java{ - srcDirs = [] - } - groovy { - srcDirs = ["src/main/groovy", "src/main/java"] - exclude "**/package-info.groovy" - } - } -} - -groovydoc{ - source fileTree("src/main/groovy") -} From 1de075a3e9d3d2832ce79730b992ec37066d6154 Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Sun, 14 Mar 2021 15:17:13 -0400 Subject: [PATCH 07/10] update --- .../primitives/ReservedVariableName.groovy | 10 +- .../init/primitives/TemplateBinding.groovy | 20 +++- .../init/primitives/TemplatePrimitive.groovy | 14 ++- .../injectors/ApplicationEnvironment.groovy | 11 ++- .../init/primitives/injectors/Keyword.groovy | 11 ++- .../init/primitives/injectors/Stage.groovy | 11 ++- .../primitives/injectors/StepWrapper.groovy | 11 ++- .../primitives/TemplateBindingSpec.groovy | 97 +++++++++---------- 8 files changed, 111 insertions(+), 74 deletions(-) diff --git a/src/main/groovy/org/boozallen/plugins/jte/init/primitives/ReservedVariableName.groovy b/src/main/groovy/org/boozallen/plugins/jte/init/primitives/ReservedVariableName.groovy index f8d4cdeb2..9f7ac8d55 100644 --- a/src/main/groovy/org/boozallen/plugins/jte/init/primitives/ReservedVariableName.groovy +++ b/src/main/groovy/org/boozallen/plugins/jte/init/primitives/ReservedVariableName.groovy @@ -39,12 +39,14 @@ abstract class ReservedVariableName implements ExtensionPoint{ abstract String getExceptionMessage() - void throwPreLockException() throws Exception{ - throw new Exception(getExceptionMessage()) + void throwPreLockException(String msg) throws Exception{ + msg += getExceptionMessage() + throw new Exception(msg) } - void throwPostLockException() throws Exception{ - throw new Exception(getExceptionMessage()) + void throwPostLockException(String msg) throws Exception{ + msg += getExceptionMessage() + throw new Exception(msg) } } diff --git a/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBinding.groovy b/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBinding.groovy index 5218c93ca..83fbf9fd0 100644 --- a/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBinding.groovy +++ b/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBinding.groovy @@ -50,7 +50,8 @@ class TemplateBinding extends Binding implements Serializable{ setVariable(STEPS, new DSL(owner)) /** * for jte namespace, we need to bypass the exception throwing logic - * that would be triggered by "jte" as a ReservedVariableName + * that would be triggered by "jte" as a ReservedVariableName which is + * why we use `variables.put()` instead of `setVariable()` */ variables.put(registry.getVariableName(), registry) } @@ -86,17 +87,23 @@ class TemplateBinding extends Binding implements Serializable{ if (!collisionTarget) { throw new JTEException("Something weird happened. Unable to determine source of binding collision.") } + String preface + if(value in TemplatePrimitive){ + preface = "Failed to create ${value.getDescription()}. " + } else { + preface = "Failed to create variable '${name}' with value ${value}. " + } if (locked) { // during pipeline execution: // always throw exceptions if overriding during pipeline execution // i.e., a template or library inadvertently create a variable // that collides - collisionTarget.throwPostLockException() + collisionTarget.throwPostLockException(preface) } else if (!permissiveInitialization || reservedVar) { // during initialization: // throw an exception if the initialization mode is strict // always throw exception if the collision target is a reserved variable - collisionTarget.throwPreLockException() + collisionTarget.throwPreLockException(preface) } } @@ -116,6 +123,13 @@ class TemplateBinding extends Binding implements Serializable{ throw new MissingPropertyException(name, this.getClass()) } + /** + * The registry tracks TemplatePrimitives that have been + * put into the binding. When `jte.permissive_initialization` is + * set to true, there may be multiple primitives with the same + * name. When that's the case, JTE requires that each primitive + * be accessed via its long-name using primitive namespacing. + */ List primitives = registry.getPrimitivesByName(name) if(primitives.size() >= 2 && locked){ List msg = [ diff --git a/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplatePrimitive.groovy b/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplatePrimitive.groovy index 88d2fb4d7..009971f67 100644 --- a/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplatePrimitive.groovy +++ b/src/main/groovy/org/boozallen/plugins/jte/init/primitives/TemplatePrimitive.groovy @@ -34,12 +34,12 @@ abstract class TemplatePrimitive implements Serializable{ /** * Invoked if an object with this class were to be overridden in the {@link TemplateBinding} during initialization */ - abstract void throwPreLockException() + abstract void throwPreLockException(String preface) /** * Invoked if an object with this class were to be overridden in the {@link TemplateBinding} after initialization */ - abstract void throwPostLockException() + abstract void throwPostLockException(String preface) /** * Returns the injector that creates the primitive @@ -59,4 +59,14 @@ abstract class TemplatePrimitive implements Serializable{ */ abstract String getName() + /** + * Returns the user-facing description of what this primitive is + *

+ * examples: + * - Library Step 'build' from the 'maven' library + * - Stage 'continuous_integration' + * @return the user-facing description of the primitive + */ + abstract String getDescription() + } diff --git a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/ApplicationEnvironment.groovy b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/ApplicationEnvironment.groovy index 117b4d48b..24299a8fc 100644 --- a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/ApplicationEnvironment.groovy +++ b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/ApplicationEnvironment.groovy @@ -66,6 +66,7 @@ class ApplicationEnvironment extends TemplatePrimitive implements Serializable{ this.config = config.asImmutable() } + @NonCPS @Override String getDescription(){ return "Application Environment '${name}'" } @NonCPS @Override String getName(){ return name } @NonCPS @Override Class getInjector(){ return ApplicationEnvironmentInjector } @@ -80,12 +81,14 @@ class ApplicationEnvironment extends TemplatePrimitive implements Serializable{ } @NonCPS - void throwPreLockException(){ - throw new TemplateException ("Application Environment ${name} already defined.") + void throwPreLockException(String msg){ + msg += "Application Environment ${name} already defined." + throw new TemplateException(msg) } - void throwPostLockException(){ - throw new TemplateException ("Variable ${name} is reserved as an Application Environment.") + void throwPostLockException(String msg){ + msg += "Variable ${name} is reserved as an Application Environment." + throw new TemplateException(msg) } } diff --git a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Keyword.groovy b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Keyword.groovy index e564ea49b..d58f8b231 100644 --- a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Keyword.groovy +++ b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Keyword.groovy @@ -32,6 +32,7 @@ class Keyword extends TemplatePrimitive implements Serializable{ String preLockException = "Variable ${name} already exists as a Keyword." String postLockException = "Variable ${name} is reserved as a template Keyword." + @NonCPS @Override String getDescription(){ return "Keyword '${name}'" } @NonCPS @Override String getName(){ return name } @NonCPS @Override Class getInjector(){ return injector } @@ -40,12 +41,14 @@ class Keyword extends TemplatePrimitive implements Serializable{ } @NonCPS - void throwPreLockException(){ - throw new TemplateException(preLockException) + void throwPreLockException(String msg){ + msg += preLockException + throw new TemplateException(msg) } - void throwPostLockException(){ - throw new TemplateException(postLockException) + void throwPostLockException(String msg){ + msg += postLockException + throw new TemplateException(msg) } } diff --git a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Stage.groovy b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Stage.groovy index b48e4c5a4..06bb762dc 100644 --- a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Stage.groovy +++ b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/Stage.groovy @@ -42,6 +42,7 @@ class Stage extends TemplatePrimitive implements Serializable{ this.steps = steps } + @NonCPS @Override String getDescription(){ return "Stage '${name}'" } @NonCPS @Override String getName(){ return name } @NonCPS @Override Class getInjector(){ return injector } @@ -64,12 +65,14 @@ class Stage extends TemplatePrimitive implements Serializable{ } @NonCPS - void throwPreLockException(){ - throw new TemplateException ("The Stage ${name} is already defined.") + void throwPreLockException(String msg){ + msg += "The Stage ${name} is already defined." + throw new TemplateException(msg) } - void throwPostLockException(){ - throw new TemplateException ("The variable ${name} is reserved as a template Stage.") + void throwPostLockException(String msg){ + msg += "The variable ${name} is reserved as a template Stage." + throw new TemplateException(msg) } } diff --git a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/StepWrapper.groovy b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/StepWrapper.groovy index e8e357614..12f1e299d 100644 --- a/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/StepWrapper.groovy +++ b/src/main/resources/org/boozallen/plugins/jte/init/primitives/injectors/StepWrapper.groovy @@ -91,6 +91,7 @@ class StepWrapper extends TemplatePrimitive implements Serializable, Cloneable{ */ private HookContext hookContext + @NonCPS @Override String getDescription(){ return "Library Step '${name}' from the '${library}' library" } @NonCPS @Override String getName(){ return name } @NonCPS String getLibrary(){ return library } @NonCPS @Override Class getInjector(){ return injector } @@ -179,12 +180,14 @@ class StepWrapper extends TemplatePrimitive implements Serializable, Cloneable{ } @NonCPS - void throwPreLockException(){ - throw new TemplateException ("Library Step Collision. The step ${name} already defined via the ${library} library.") + void throwPreLockException(String msg){ + msg += "The step '${name}' already defined via the '${library}' library." + throw new TemplateException(msg) } - void throwPostLockException(){ - throw new TemplateException ("Library Step Collision. The variable ${name} is reserved as a library step via the ${library} library.") + void throwPostLockException(String msg){ + msg += "The variable '${name}' is reserved as a library step via the '${library}' library." + throw new TemplateException(msg) } /** diff --git a/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy b/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy index b481f3bec..d57d6cc78 100644 --- a/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy +++ b/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy @@ -43,14 +43,15 @@ class TemplateBindingSpec extends Specification{ String name Class injector + @NonCPS @Override String getDescription(){ return "Test Primitive ${name}" } @NonCPS @Override String getName(){ return name } @NonCPS @Override Class getInjector(){ return injector } - void throwPreLockException(){ + void throwPreLockException(String msg){ throw new TemplateException ("pre-lock exception") } - void throwPostLockException(){ + void throwPostLockException(String msg){ throw new TemplateException ("post-lock exception") } @@ -304,33 +305,33 @@ class TemplateBindingSpec extends Specification{ def "application env as argument for stage context"(){ given: String template = """ -broadway dev -""" + broadway dev + """ String config = """ -jte{ - permissive_initialization = true -} - -application_environments { - dev{ - long_name = "development" - } -} - -stages{ - broadway{ - temp_meth1 - } -} - -template_methods{ - temp_meth1 -} -""" + jte{ + permissive_initialization = true + } + + application_environments { + dev{ + long_name = "development" + } + } + + stages{ + broadway{ + temp_meth1 + } + } + + template_methods{ + temp_meth1 + } + """ WorkflowJob job = TestUtil.createAdHoc(jenkins, - template: template, - config: config + template: template, + config: config ) expect: @@ -339,32 +340,30 @@ template_methods{ def "permissive mode binding collision with ReservedVariable (stageContext) pre-lock throws pre-lock exception"(){ given: - String template = """ -broadway -""" + String template = "broadway" String config = """ -jte{ - permissive_initialization = true -} - -stages{ - broadway{ - temp_meth1 - } -} - -keywords{ - stageContext = "x" -} - -template_methods{ - temp_meth1 -} -""" + jte{ + permissive_initialization = true + } + + stages{ + broadway{ + temp_meth1 + } + } + + keywords{ + stageContext = "x" + } + + template_methods{ + temp_meth1 + } + """ WorkflowJob job = TestUtil.createAdHoc(jenkins, - template: template, - config: config + template: template, + config: config ) expect: From 15994107708fdc40952b0e3a123af78eb4261284 Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Sun, 14 Mar 2021 15:25:20 -0400 Subject: [PATCH 08/10] update --- .../jte/init/primitives/TemplateBindingSpec.groovy | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy b/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy index d57d6cc78..349009b3f 100644 --- a/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy +++ b/src/test/groovy/org/boozallen/plugins/jte/init/primitives/TemplateBindingSpec.groovy @@ -47,10 +47,12 @@ class TemplateBindingSpec extends Specification{ @NonCPS @Override String getName(){ return name } @NonCPS @Override Class getInjector(){ return injector } + @SuppressWarnings("UnusedMethodParameter") void throwPreLockException(String msg){ throw new TemplateException ("pre-lock exception") } + @SuppressWarnings("UnusedMethodParameter") void throwPostLockException(String msg){ throw new TemplateException ("post-lock exception") } @@ -311,19 +313,19 @@ class TemplateBindingSpec extends Specification{ jte{ permissive_initialization = true } - + application_environments { dev{ long_name = "development" } } - + stages{ broadway{ temp_meth1 } } - + template_methods{ temp_meth1 } @@ -345,17 +347,17 @@ class TemplateBindingSpec extends Specification{ jte{ permissive_initialization = true } - + stages{ broadway{ temp_meth1 } } - + keywords{ stageContext = "x" } - + template_methods{ temp_meth1 } From 59a74dcb2cd4c48732bb7a8c65cda184f678ae07 Mon Sep 17 00:00:00 2001 From: Steven Terrana Date: Mon, 15 Mar 2021 14:44:14 -0400 Subject: [PATCH 09/10] update justfile --- Justfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Justfile b/Justfile index 9ff5fc324..dce3e5376 100644 --- a/Justfile +++ b/Justfile @@ -49,7 +49,7 @@ docs: # publishes the jpi release version branch=`git branch --show-current`: #!/usr/bin/env bash - if [[ ! "{{branch}}" == "justfile" ]]; then + if [[ ! "{{branch}}" == "main" ]]; then echo "You can only cut a release from the 'main' branch." echo "Currently on branch '{{branch}}'" exit 1 @@ -88,4 +88,4 @@ reload: # watches the given path to commit all changes as they occur watch path: - watchexec 'cd {{path}} && git add -A && git commit -m "update"' -w {{path}} \ No newline at end of file + watchexec 'cd {{path}} && git add -A && git commit -m "update"' -w {{path}} From 5afa02a576a5d2489474b6b647c7ab7f9038f051 Mon Sep 17 00:00:00 2001 From: steven-terrana Date: Mon, 15 Mar 2021 14:51:04 -0400 Subject: [PATCH 10/10] Update CONTRIBUTING.adoc --- CONTRIBUTING.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 82c854b79..9b57c62ce 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -29,7 +29,7 @@ To run all the tests, run: just test ---- -The gradle test report is published to `build/target/tests/test/index.html` +The gradle test report is published to `build/reports/tests/test/index.html` ### Execute tests for a specific class @@ -183,4 +183,4 @@ just watch ~/local-libraries ---- to automatically commit changes to the libraries. -==== \ No newline at end of file +====