Using Git client-side hooks to run DITA publishing pipelines
This topic describes how to use Git client-side hooks to execute DITA commands and publishing workflows, with an emphasis on using the Oxygen's Git Client.
Prerequisites
- Oxygen's Git client is based on the JGit library. When running on Windows, this library relies on CYGWIN to run the Git hooks. CYGWIN must be installed and added to the path.
- If you are running on Windows, you either need an Oxygen Git client version 2.0.0 or one newer than
2.1.1 (at the time this post is written, 2.1.1 was the latest version, but a new one will
soon be released). We are basically avoiding versions that come bundled with JGit 5.6.0,
which has this known issue.If you need to install version 2.0.0 of the plugin, since this version is no longer available in the add-on, you have to install it manually:
- Uninstall the current Oxygen Git client version, if one is present.
- Download Oxygen Git client version 2.0.0.
- Unzip it inside {oxygenInstallDir}/plugins. Make sure you don't create any intermediate folders. The path should be like this: {oxygenInstallDir}/git.support-2.0.0/plugin.xml.
- The DITA-OT command utility needs to be added to the path so that the presented script will work.
What is a Git hook?
Git has a way to fire off custom scripts when certain important actions occur. There are two groups of these hooks: client-side and server-side. Client-side hooks are triggered by operations such as committing and merging, while server-side hooks run on network operations such as receiving pushed commits. You can read more about what types of hooks are available at Customizing Git - Git Hooks.
Using a client side hook with a DITA project
The main scenario we are focusing on in this topic is about using client-side hooks while working with DITA and storing it in a Git repository, and how to enable Oxygen’s built-in Git Client to execute these hooks.
The hooks are all stored in the hooks
subdirectory of the Git
directory, which is .git/hooks
by default. A useful client-side hook is the
pre-commit hook. It’s used to inspect the snapshot that’s about to be
committed, to see if you’ve forgotten something, to make sure tests like Oxygen's Validate and Check for completeness run properly, or to examine whatever you need
to inspect in the code.
To make it easier to follow, though, we will use a use case reported by one of Oxygen's users. That is to generate a Markdown version of the documentation whenever you commit something. When I tried to do the same thing myself, I encountered some challenges and I think it will help others if they read how I managed to solve it.
Installing a pre-commit hook
Git automatically populates the .git/hooks
directory with example
scripts when you initialize a repository. All we need to do is rename
pre-commit.sample to simply pre-commit and put in it the script
we are interested in.
The content of the pre-commit file is something like this: we assume that the map to publish is called README.ditamap and it is located inside the project root directory.
#!/bin/sh set -x echo "Start hook" export GIT_HOOKS_DIR=`cd "\`dirname "\\\`readlink "$0" || echo $0\\\`"\`" && pwd` # We assume the hooks directory is the default one: wc/.git/hooks export ROOT_DIR="$GIT_HOOKS_DIR/../.." # OS specific support. $var _must_ be set to either true or false. cygwin=false; case "`uname`" in CYGWIN*) cygwin=true ;; esac # For some reasons, if we let a cygwin path pass, the dita pipeline fails with: # Error: Failed to run pipeline: [DOTA069F][FATAL] Input file 'file:/cygdrive/c/Users/.../git-hooks-sample/.git/hooks/../../README.ditamap' cannot be located or read. Ensure that file was specified properly and that you have permission to access it. # It works if we pass it instead as: C:/Users/.../git-hooks-sample/README.ditamap # Considering the fact that the dita script just passes the --input further on to ANT, it might have something to do with cygwin processing performed in ANT. if $cygwin; then ROOT_DIR=`cygpath --mixed "$ROOT_DIR"` fi dita --input=$ROOT_DIR/README.ditamap --format=markdown --output=$ROOT_DIR/docs/ # Exit with status of last command exit
ROOT_DIR=`cygpath --mixed "$ROOT_DIR"`
, the DITA publishing
pipeline fails
with:Error: Failed to run pipeline: [DOTA069F][FATAL] Input file 'file:/cygdrive/c/Users/.../git-hooks-sample/.git/hooks/../../README.ditamap' cannot be located or read. Ensure that file was specified properly and that you have permission to access it.
Buildfile: \cygdrive\d\tools\dita-ot-3.4\build.xml does not exist!
# Add build script to arguments ant_exec_args="$ant_exec_args \"-buildfile\" \"$DITA_HOME/build.xml\" \"-main\" \"org.dita.dost.invoker.Main\""
############################################## BUILD_FILE="$DITA_HOME/build.xml" if $cygwin ; then BUILD_FILE=`cygpath --mixed "$BUILD_FILE"` fi ############################################### # Add build script to arguments ant_exec_args="$ant_exec_args \"-buildfile\" \"$BUILD_FILE\" \"-main\" \"org.dita.dost.invoker.Main\""
That's it. Each time you commit something in this repository, the Markdown version of your documentation gets generated.