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

Justfile #185

Merged
merged 10 commits into from
Mar 17, 2021
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
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:

Choose a reason for hiding this comment

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

tried running this locally:
Unable to find image 'docker.pkg.github.com/boozallen/sdp-docs/builder:latest' locally
docker: Error response from daemon: Head https://docker.pkg.github.com/v2/boozallen/sdp-docs/builder/manifests/latest: no basic auth credentials.
I have ~/.git-credentials for github.

Copy link
Author

Choose a reason for hiding this comment

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

docker login docker.pkg.github.com and then use your GH user/pat

we could try to automate that part too

Choose a reason for hiding this comment

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

hmm did not work

carlosokieffe@C02D80XNMD6V templating-engine-plugin % docker login docker.pkg.github.com                              
Username: cokieffebah
Password: 

Login Succeeded
carlosokieffe@C02D80XNMD6V templating-engine-plugin % 
carlosokieffe@C02D80XNMD6V templating-engine-plugin % git pull docker.pkg.github.com/boozallen/sdp-docs/builder:latest
fatal: 'docker.pkg.github.com/boozallen/sdp-docs/builder:latest' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
carlosokieffe@C02D80XNMD6V templating-engine-plugin % just 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 docs/html docs/antora-playbook-local.yml
Unable to find image 'docker.pkg.github.com/boozallen/sdp-docs/builder:latest' locally
docker: Error response from daemon: unauthorized: Your request could not be authenticated by the GitHub Packages service. Please ensure your access token is valid and has the appropriate scopes configured.
See 'docker run --help'.
error: Recipe `docs` failed on line 47 with exit code 125

Choose a reason for hiding this comment

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

I approved the PR. just noting the issues with the docs.

Copy link
Author

Choose a reason for hiding this comment

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

you accidentally ran git pull instead of docker pull.

when you authenticated, did you use your password or a PAT?

if a PAT, it would need to have the read:packages scope

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