Skip to content

Commit

Permalink
add CircleCI build and docs (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
svenevs committed Feb 14, 2019
1 parent 861e8dc commit e3530c7
Show file tree
Hide file tree
Showing 5 changed files with 310 additions and 2 deletions.
67 changes: 67 additions & 0 deletions .circleci/build_image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash

# Make sure we can execute `make` directly.
if ! [[ -f Makefile ]]; then
echo "This must be run from the root of the repository." >&2
exit 1
fi

# CI builds specify the target to build.
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <make target>" >& 2
exit 1
fi
target="$1"

# Bypass enabled, see .circleci/config.yml latex_target.
if [[ "$target" == "nonexistent" ]]; then
echo "Target was 'nonexistent', exiting early without failure."
exit 0
fi

# Determine PANDOC_VERSION for Makefile based on commit message. We are looking
# for if the string `release=X.Y` exists, if so then that is what we are going
# to build. Otherwise, build the `master` branch (which is the `edge` image).
# NOTE: cron jobs always build the :edge tag.
release_tag="$(git log --pretty="%s" -1 | grep -o 'release=[0-9]\.[0-9]')"
if [[ "$CIRCLE_CRON_JOB" == "true" ]] || [[ -z "$release_tag" ]]; then
version="edge"
else
version="$(echo "$release_tag" | cut -d = -f 2)"
fi

# Build the docker image. Make script exit with valid code (stop CI if fail).
PANDOC_VERSION="$version" make "$target" || exit 1

# Display the docker images for being able to review CI logs.
echo 'docker images:'
docker images

# Only do `docker push` if this is a CI build from the master branch of the
# pandoc/dockerfiles repository. Cannot just check git branch because users
# may open a Pull Request from a fork's master branch.
if [[ "$(git rev-parse HEAD)" == "$(git rev-parse origin/master)" ]]; then
# Setup the repository to upload to. The alpine and alpine-latex targets
# are special (the "core" images), and upload to a different repository.
# All other repository names shadow the make target names.
if [[ "$target" == "alpine" ]]; then
repository="core"
elif [[ "$target" == "alpine-latex" ]]; then
repository="latex"
else
repository="$target"
fi

# Login and push docker image.
(echo "$DOCKER_PASSWORD" | \
docker login -u="$DOCKER_USERNAME" --password-stdin) || exit 1
echo "Pushing docker image to 'pandoc/$repository:$version'"
docker push "pandoc/$repository:$version" || exit 1

# If this is a release=X.Y build, move the :latest tag.
if [[ "$version" != "edge" ]]; then
echo "Pushing docker image to 'pandoc/$repository:latest'"
docker tag "pandoc/$repository:$version" "pandoc/$repository:latest" || exit 1
docker push "pandoc/$repository:latest" || exit 1
fi
fi
87 changes: 87 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
version: 2.1
jobs:
# Any linting checks that can be performed go here.
lint:
machine: true
steps:
- run: sudo apt-get install shellcheck python-flake8
- checkout
- run: make lint
# Builds a docker image stack (see workflows below). If getting merged to the
# master branch then the built image(s) will also be pushed to docker hub.
build_stack:
machine: true
description: Build parameterized docker image stack
parameters:
core_target:
description: Makefile target to build core image (just pandoc)
type: string
latex_target:
description: Makefile target to build latex image (on top of core_target)
type: string
# This default value is checked for in build_image.sh. If this exact
# value is found, then the script will exit 0 rather than exit 1,
# allowing for future image stacks to only have a core_target with no
# latex target if desired.
default: "nonexistent"
cron_job:
description: Whether or not this is a cron build (forces edge tag build)
type: boolean
default: false
environment:
CIRCLE_CRON_JOB: << parameters.cron_job >>
steps:
- checkout
# First build the core image
- run:
# Set a 1 hour time limit. Build/push may get silent during parts.
no_output_timeout: 1h
command: |
./.circleci/build_image.sh << parameters.core_target >>
# After that is complete, now build the latex image.
- run:
# Set a 1 hour time limit. Build/push may get silent during parts.
no_output_timeout: 1h
command: |
./.circleci/build_image.sh << parameters.latex_target >>
# We need to be able to distinguish cron jobs, something that CircleCI does not
# currently support in their default environment variables. Defining all image
# stacks here, but they are to be enumerated separately in
#
# 1. workflows.build.jobs
# 2. workflows.monthly.jobs
#
# The only difference in usage between (1) and (2) is whether or not `cron_job`
# is getting set which leads to some duplication, but at this time there is no
# known solution for fixing this.
alpine_stack: &alpine_stack
core_target: alpine
latex_target: alpine-latex

# Setup builds for each commit, as well as monthly cron job.
workflows:
build:
jobs:
- lint
- build_stack:
<<: *alpine_stack
monthly:
# NOTE: make sure all `build_stack` calls here *also* set `cron_job: true`!
jobs:
- build_stack:
<<: *alpine_stack
cron_job: true
triggers:
- schedule:
# http://pubs.opengroup.org/onlinepubs/7908799/xcu/crontab.html
# Minute: 0
# Hour: 0
# Day of month: 1
# Month of year: * (any)
# Day of week: * (any)
cron: "0 0 1 * *"
filters:
branches:
only:
- master
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ alpine-latex:
--build-arg base_tag=$(PANDOC_VERSION) \
alpine/latex

.PHONY: lint
lint:
shellcheck $(shell find . -name "*.sh")
150 changes: 149 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,153 @@
pandoc Dockerfiles
==================
================================================================================

This repo contains a collection of Dockerfiles to build various
pandoc container images.

**Contents**

- [Available Images](#available-images)
- [Current `latest` Tag](#current-latest-tag)
- [Alpine Linux](#alpine-linux)
- [Maintenance Notes](#maintenance-notes)
- [Adding a new Image Stack](#adding-a-new-image-stack)
- [Managing new Pandoc Releases](#managing-new-pandoc-releases)
- [License](#license)

Available Images
================================================================================

Docker images hosted here have a "core" version and a "latex" version:

- core: `pandoc` and `pandoc-citeproc`, as well as the appropriate backend for
the full lua filtering backend (lua filters can call external modules).
- latex: builds on top of the core image, and provides an as-minimal-as-possible
latex installation in addition. This includes all packages that `pandoc`
_might_ use, and any libraries needed by these packages (such as image
libraries needed by the latex graphics packages).

From there, the tagging scheme is either `X.Y`, `latest`, or `edge`.

- `X.Y`: an official `pandoc` release (e.g., `2.6`). Once an `X.Y` tag is
pushed, it will not be re-built (unless there is a problem).
- `latest`: the `latest` tag points to the most recent `X.Y` release. For
example, if tags `2.5` and `2.6` were available online, `latest` would be the
same image as `2.6`.
- `edge`: the "bleeding edge" tag clones the `master` branch of `pandoc` and
`pandoc-citeproc`. This tag is a moving target, and will be re-built
_at least_ once a month. The CI scripts have a cron job to build each image
stack on the first of the month. However, changes to the `master` branch of
this repository may also result in the `edge` tag being updated sooner.

Current `latest` Tag
--------------------------------------------------------------------------------

The current `latest` tag for all images points to `pandoc` version `2.6`.

Alpine Linux
--------------------------------------------------------------------------------

- Core image: [`pandoc/core`](https://cloud.docker.com/u/pandoc/repository/docker/pandoc/core)
- To build locally: `make alpine`
- Latex image: [`pandoc/latex`](https://cloud.docker.com/u/pandoc/repository/docker/pandoc/latex)
- To build locally: `make alpine-latex`

Maintenance Notes
================================================================================

Adding a new Image Stack
--------------------------------------------------------------------------------

Suppose users desire a new image stack using a different base image. To make
the requirements clearer, assume the desire is to have a new image stack based
off `ubuntu`.

1. Create a top-level directory named `ubuntu`. The name of this directory
should be exactly the same as whatever the `FROM` clause will be, for
consistency and clarity.
2. Create `ubuntu/Dockerfile`. This `Dockerfile` will be the "core" `ubuntu`
image, it should only contain `pandoc` and `pandoc-citeproc`. Refer to the
[`alpine/Dockerfile`](alpine/Dockerfile) for assistance in how to create
multiple layers. The idea is to create a base image, install all build
dependencies and `pandoc` / `pandoc-citeproc`. Then create a new layer from
the original base image and copy from the intermediate build layer. This way
the `pandoc` / `pandoc-citeproc` are effectively the only additional items
on top of the original base image.
3. Add an `ubuntu` target to the `Makefile`.
4. Create `ubuntu/latex/Dockerfile` and install the latex dependencies. Use the
[`alpine/latex/Dockerfile`](alpine/latex/Dockerfile) as a reference for what
dependencies should be installed in addition to latex.
5. Add an `ubuntu-latex` target to the `Makefile`.
6. Now that your image stack has been defined (and tested!), update the CircleCI
[`.circleci/config.yml`](.circleci/config.yml) file to add a new build stack.
Specifically, search for `alpine_stack: &alpine_stack`. An example `diff`
for this `ubuntu` stack could look like this:

```diff
@@ -58,6 +58,9 @@ jobs:
alpine_stack: &alpine_stack
core_target: alpine
latex_target: alpine-latex
+ubuntu_stack: &ubuntu_stack
+ core_target: ubuntu
+ latex_target: ubuntu-latex

# Setup builds for each commit, as well as monthly cron job.
workflows:
@@ -66,12 +69,17 @@ workflows:
- lint
- build_stack:
<<: *alpine_stack
+ - build_stack:
+ <<: *ubuntu_stack
monthly:
# NOTE: make sure all `build_stack` calls here *also* set `cron_job: true`!
jobs:
- build_stack:
<<: *alpine_stack
cron_job: true
+ - build_stack:
+ <<: *ubuntu_stack
+ cron_job: true
```

**You should not need to edit anything else in this file!**
7. Update this file (README.md) to include a listing of this new image stack.
Create a new h2 heading (`Ubuntu Linux` in this example) underneath
`All Image Stacks` heading. Please keep this alphabetical. Please also make
sure to create a hyperlink under the `**Contents**` listing at the top of
this file for browsing convenience.
8. Open a Pull Request for review!

Managing new Pandoc Releases
--------------------------------------------------------------------------------

When `pandoc` has a new official release, the following steps must be performed
in this exact order:

1. Create a pull request from a branch. Edit the ``Current `latest` Tag``
section to include the new `pandoc` release number. Suppose
we are releasing image stacks for `pandoc` version 9.8:

```console
$ git checkout -b release/9.8
# ... edit current :latest ...
$ git add README.md
$ git commit -m 'release=9.8'
$ git push -u origin release/9.8
```

The important part is the commit message. The build script looks for exactly
`release=[0-9]\.[0-9]` in the message, and if found performs the additional
tagging to `:latest`. So the diff does not really matter, just the message.

Create a pull request first to make sure all image stacks build as expected.
2. Assuming the pull request build succeeds, merge to `master` branch. The only
time that `docker push` is performed is when a commit hits the `master`
branch of this repository.

License
================================================================================

Code in this repository is licensed under the
[GNU General Public License Version 2](LICENSE).
5 changes: 4 additions & 1 deletion alpine/latex/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ RUN apk --no-cache add librsvg \
texlive-luatex \
texlive-xetex \
texmf-dist-most \
xdvik
xdvik \
| grep 'Installing'
# NOTE: `grep 'Installing'` is to suppress latex post-install scripts from
# flooding the CI buffer.

0 comments on commit e3530c7

Please sign in to comment.