Skip to content

Commit

Permalink
Convert Makefile to Justfile and add CONTRIBUTING.adoc (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-terrana committed Mar 17, 2021
1 parent d12f03d commit 6e55e8d
Show file tree
Hide file tree
Showing 13 changed files with 386 additions and 100 deletions.
186 changes: 186 additions & 0 deletions CONTRIBUTING.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
: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 build the documentation for local preview

|===


## Running Tests

To run all the tests, run:

[source,bash]
----
just test
----

The gradle test report is published to `build/reports/tests/test/index.html`

### Execute tests for a specific class

To run tests for a specific Class, `StepWrapperSpec` for example, run:

[source,bash]
----
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:

[source, bash]
----
just jpi
----

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 <versionNumber>`.

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

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.
====
91 changes: 91 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# 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="*":
#!/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}}" == "main" ]]; 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}}

# 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}}
32 changes: 0 additions & 32 deletions Makefile

This file was deleted.

1 change: 1 addition & 0 deletions docs/modules/developer/nav.adoc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* xref:index.adoc[Developer Documentation]
** xref:CONTRIBUTING.adoc[Contributing]
** xref:initialization.adoc[Initialization Process]
1 change: 1 addition & 0 deletions docs/modules/developer/pages/CONTRIBUTING.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
}

Expand All @@ -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<String> primitives = registry.getPrimitivesByName(name)
if(primitives.size() >= 2 && locked){
List<String> msg = [
Expand Down
Loading

0 comments on commit 6e55e8d

Please sign in to comment.