Solver is a command-line interface (CLI) that helps authors create O'Reilly Challenges. Solver helps authors organize the verifications, the myriad of hints, and provides an enhanced solutions mechanism for rapid testing. Solver is not required, but it can shorten your time for producing quality Challenges.
The usage of Solver for O'Reilly Challenge authors is detailed in the Katacoda Documentation.
The command line offers information on the commands via solver --help
.
If you are an author using this utility, your feedback is important, and please feel free to add issues in this project for reporting problems or suggesting ideas.
As an author there are two places where Solver can help you:
- Locally in your development environment when creating the content
- At runtime, within the challenge.
Solver is a tool that both supports your challenge development and execution.
These two installations types are covered in the documentation at Challenges Solver Utility.
The solver CLI utility binary is targeted for Linux. To use Solver while you are developing your challenge on Windows or macOS one option is to run the utility from the published container for solver. Here is a bash function that you can apply if you decide to use a bash terminal on Windows or macOS:
function solver() {
SOLVER_IMAGE=ghcr.io/javajon/solver:0.5.4 ## <-- Set to the latest semver release @ https://bit.ly/3sSEiBD
SCENARIOS_ROOT=~/my-scenarios ## <-- Set to your base source directory for your challenges and scenarios
if [[ ! "$(pwd)" =~ ^$SCENARIOS_ROOT.* ]]; then
echo "Please run this from $SCENARIOS_ROOT or one of its scenario or challenge subdirectory."
return 1;
fi
SUBDIR=$(echo $(pwd) | grep -oP "^$SCENARIOS_ROOT\K.*") ## <-- change to ggrep if on macOS
docker run --rm -it -v "$SCENARIOS_ROOT":/workdir -w /workdir/$SUBDIR $SOLVER_IMAGE "$@";
}
The above function expects GNU grep. This is not the version installed by default on macOS. You can easily install the GNU version by using homebrew and then just changing the call to grep
in the above function to ggrep
.
On Windows, another option is wsl2.
The remaining instructions are for developers of this utility, not for authors of the challenges.
This command-line tool is written in Java. Picocli is leveraged for the CLI framework. Quarkus with Graal creates a fast and efficient Linux binary. The project is built with Gradle and CI/CD is automated using GitHub actions.
You can run your application in developer mode that enables live coding using:
./gradlew quarkusDev
The application can be packaged using:
./gradlew build
It produces the quarkus-run.jar
file in the build/quarkus-app/
directory.
Be aware that it’s not an über-jar as the dependencies are copied into the build/quarkus-app/lib/
directory.
If you want to build an über-jar, execute the following command:
./gradlew build -Dquarkus.package.type=uber-jar
The application is now runnable using java -jar build/quarkus-app/quarkus-run.jar
.
You can create a native executable using:
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.native-image-xmx=8g
Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true -Dquarkus.native.native-image-xmx=8g
If the quarkusBuild
fails with an exit code 137 out of memory message, the error message suggests increasing the xmx heap size. Others indicate this is a problem with your local docker engine. Consider a purge of your docker engine caches docker purge system --all
followed with a full host reboot.
With either of the above, you can then execute your native executable with:
./build/solver-[version]-runner
This binary, renamed to solver
, may be used by a Challenge.
If you are a developer or tester of the Solver utility below are some techniques to run it locally or copy it to a Challenge without the GitOps process.
You can run solver
from Linux shells, but without the context of an O'Reilly Challenge, it is like watching Fred Flintstone drive a car with his feet with no engine. You're not fooling anyone, Fred.
./gradlew build -Dquarkus.package.type=uber-jar && java -jar build/quarkus-app/quarkus-run.jar --help
The solver
command-line tool cannot be loaded via the scenario's assets as there is a size limit at 9MB and the CLI tool is too large of an asset. Instead, there is a wget
command in the init-background.sh
script that installs Solver when the challenge starts. This incurs a slight vulnerability if GitHub fails to deliver the requested CLI binary artifact from the release page then the challenge will break and the learner will have to reload the scenario. This source may change and remains on the roadmap.
Ensure the wget
pulls a specific version of Solver and your challenge is tested with that specific version in place.
For fast, local, iterative development and testing of the Solver tool with a live challenge it's best to copy the updated Solver binary directly to the challenge. There are a variety of places where a binary can be uploaded. Here is an example using the public service transfer.sh
- Build the binary with
./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true
- Identify the binary to copy:
export SOLVER_RUNNER=build/solver-$(git describe --tags $(git rev-list --tags --max-count=1))-$(git rev-parse --abbrev-ref HEAD)-runner
- Upload the executable to an ephemeral cloud directory:
STORAGE_URL=$(curl --upload-file $SOLVER_RUNNER https://transfer.sh/solver) && echo $STORAGE_URL
- Copy the resulting storage URL to your clipboard.
- Start Challenge
- Copy
solver
binary into Challenge using the clipboard pasted URL:curl -o solver <pasted-url>
- Make executable, copy, and verify:
chmod +x solver && cp solver /usr/local/bin && solver --version
Some of these public services throttle throughput over repeated usage. You can also use gdrive to download artifacts from Google drive. Never use these for the published challenges.
To compress the binary before transfer use UPX. The releases are compressed with this UPX tool:
- Install UPX with
sudo apt-get update && yes | sudo apt-get install upx
- Compress the executable with:
upx --best --lzma $solver
Solver uses SemVer and the versions are tracked and bumped automatically. A release is created for any commit with a new SemVer git tag. There are GitHub actions to build, tag, and create releases. The SemVer tagging, bumping, and releasing process is based on the GitHub action jefflinse/pr-semver-bump.
Direct commits are not permitted to the main branch via a GitHub branch rule. Only PRs are committed to main. A Merged pull request (PR) triggers the automated SemVer advancement and a new release. With this comes the PR comments and PR labels and direct the bumping of the major, minor, and patch numbers. When a PR is merged to main
, it must be labeled with either major
, minor
, or patch
. When a new SemVer tag is created a new GitHub release is created with the update solver
binary. This technique follows some best practices for automated GitOps. Branch names can be reused, such as update
. The workflow for the PR roughly follows this flow:
git checkout -b update
(make changes)
git add .
git commit -m "(the reasons for the new release)"
git push --set-upstream origin update
In GitHub merge the pull request and be sure to add the label patch release, as described here.
-
To learn more about building native executables, see Building Quarkus Apps with Gradle.
-
This Java application uses Picocli (guide) as a very helpful framework for developing intuitive and consistent command-line applications.
-
More about Command line application with multiple Commands.
-
An excellent alternative to Quarkus is Micronaut that is a similar build process since it's also based on Graal. Micronaut also works well with Picocli.
This project was inspired by the try-picocli-gradle repository.