diff --git a/README.md b/README.md index 53c6a06..a59883d 100644 --- a/README.md +++ b/README.md @@ -112,11 +112,35 @@ jobs: DOCKER_USER: ${{ secrets.DOCKER_USER }} DOCKER_PASS: ${{ secrets.DOCKER_PASS }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build image & push to Docker Hub run: ./build.sh ``` +Alternatively you may skip the local `build.sh` script and use this repository +as a step action directly. + +```yaml +jobs: + build: + runs-on: ubuntu-latest + # needs: test # you can declare a `test` job and uncomment this to test the app before building + env: + DOCKER_REPOSITORY: 'dockerhub_org/dockerhub_repo' + DOCKER_USER: ${{ secrets.DOCKER_USER }} + DOCKER_PASS: ${{ secrets.DOCKER_PASS }} + steps: + - uses: actions/checkout@v3 + - uses: manastech/ci-docker-builder@ + # with: + # skip-login: + # repository: "" + # repository-suffix: "" + # tag-suffix: "" + # build-directory: "" + # build-options: "" +``` + ## Functions ### `dockerSetup [--skip-login]` @@ -152,7 +176,9 @@ It can receive these optional arguments: * `-r `: Override the repository where the image is pushed * `-s `: Override the repository by adding a suffix to the one specified by the environment variable + * `-t `: Append a suffix to the image tags (e.g. `-next`) * `-d `: Build from the specified directory + * `-o ""`: Options to directly pass to the docker build command This function can be called several times to build different images within the same build. For example: diff --git a/action.js b/action.js new file mode 100644 index 0000000..5002d07 --- /dev/null +++ b/action.js @@ -0,0 +1,34 @@ +const process = require("process") +const { spawn } = require("child_process") +const fs = require("fs") + +// basic implementation of @action/core.getInput() +function getInput(name) { + return process.env[`INPUT_${name.toUpperCase()}`].trim() +} + +// collect action inputs: +let setupOpts = [] +if (getInput("skip-login") === "true") setupOpts.push("--skip-login") + +let buildOpts = [], value +if ((value = getInput("repository")) !== "") buildOpts.push(`-r ${value}`) +if ((value = getInput("repository-suffix")) !== "") buildOpts.push(`-s ${value}`) +if ((value = getInput("tag-suffix")) !== "") buildOpts.push(`-t ${value}`) +if ((value = getInput("build-directory")) !== "") buildOpts.push(`-d ${value}`) +if ((value = getInput("build-options")) !== "") buildOpts.push(`-o "${value}"`) + +// generate a local build.sh script: +fs.writeFileSync("build.sh", `#! bash +source ${__dirname}/build.sh +dockerSetup ${setupOpts.join(" ")} +echo $VERSION > VERSION +dockerBuildAndPush ${buildOpts.join(" ")} +`) + +// execute it: +const build = spawn("bash", ["build.sh"], { maxBuffer: 100 * 1024 * 1024 }) +build.stdout.on("data", data => { process.stdout.write(data) }) +build.stderr.on("data", data => { process.stderr.write(data) }) +build.on("error", error => { console.error(error) }) +build.on("exit", code => { process.exit(code) }) diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..d9cf1c2 --- /dev/null +++ b/action.yml @@ -0,0 +1,27 @@ +# Metadata for the GitHub Action +name: CI Docker Builder +author: Manas +description: Build and publish Docker image(s) + +inputs: + skip-login: + type: boolean + + repository: + type: string + + repository-suffix: + type: string + + tag-suffix: + type: string + + build-directory: + type: string + + build-options: + type: string + +runs: + using: node16 + main: action.js diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 index 3321a5f..97add9e --- a/build.sh +++ b/build.sh @@ -67,7 +67,7 @@ dockerSetup() { VERSION="dev-${COMMIT::7} (build $BUILD_NUMBER)" DOCKER_TAG="dev" ;; - + "$STABLE_BRANCH") VERSION="rc-${COMMIT::7} (build $BUILD_NUMBER)" DOCKER_TAG="rc" @@ -116,8 +116,10 @@ dockerBuildAndPush() { local REPO=$DOCKER_REPOSITORY local DIR="." local OPTIND + local TAG_SUFFIX + local BUILD_OPTS - while getopts ":r:d:s:" opt "$@"; do + while getopts ":r:d:s:t:o:" opt "$@"; do case ${opt} in r) REPO=$OPTARG @@ -131,21 +133,30 @@ dockerBuildAndPush() { DIR=$OPTARG ;; + t) + TAG_SUFFIX=$OPTARG + ;; + + o) + BUILD_OPTS=$OPTARG + ;; + *) ;; esac done - local IMAGE="${REPO}:${DOCKER_TAG}" + local IMAGE="${REPO}:${DOCKER_TAG}${TAG_SUFFIX}" echo "Building image ${IMAGE} from ${DIR}" - docker build -t "${IMAGE}" "${DIR}" + # shellcheck disable=SC2086 + docker build ${BUILD_OPTS} -t "${IMAGE}" "${DIR}" echo "Pushing ${IMAGE}" docker push "${IMAGE}" if [[ -n "$EXTRA_DOCKER_TAG" ]]; then - __dockerTagAndPush "$EXTRA_DOCKER_TAG" + __dockerTagAndPush "${EXTRA_DOCKER_TAG}${TAG_SUFFIX}" fi if [[ -n "$DOCKER_TAG_AS_LATEST" ]]; then diff --git a/test/test-suite.sh b/test/test-suite.sh index 6285ed0..7c02e70 100644 --- a/test/test-suite.sh +++ b/test/test-suite.sh @@ -83,18 +83,6 @@ testMainAsDefaultDevelopmentBranch() { assertNull "${DOCKER_CALLS[1]}" } -testStableBranchDoesNotHaveADefault() { - branch "stable" - dockerSetup > /dev/null - - assertEquals "0" "$?" - assertNull "$VERSION" - assertNull "$DOCKER_TAG" - assertNull "$EXTRA_DOCKER_TAG" - assertNull "$DOCKER_TAG_AS_LATEST" - assertNull "${DOCKER_CALLS[0]}" -} - testCustomStableBranch() { branch "stable" STABLE_BRANCH=stable dockerSetup > /dev/null @@ -168,6 +156,30 @@ testBuildWithExtraTagAndLatest() { assertNull "${DOCKER_CALLS[6]}" } +testBuildWithTagSuffix() { + DOCKER_TAG="tag" + EXTRA_DOCKER_TAG="extra" + DOCKER_TAG_AS_LATEST="true" + dockerBuildAndPush -t "-next" > /dev/null + + assertEquals "build -t repository:tag-next ." "${DOCKER_CALLS[0]}" + assertEquals "push repository:tag-next" "${DOCKER_CALLS[1]}" + assertEquals "tag repository:tag-next repository:extra-next" "${DOCKER_CALLS[2]}" + assertEquals "push repository:extra-next" "${DOCKER_CALLS[3]}" + assertEquals "tag repository:tag-next repository:latest" "${DOCKER_CALLS[4]}" + assertEquals "push repository:latest" "${DOCKER_CALLS[5]}" + assertNull "${DOCKER_CALLS[6]}" +} + +testBuildWithBuildOptions() { + DOCKER_TAG="tag" + dockerBuildAndPush -o "--build-arg gemfile=Gemfile.next" > /dev/null + + assertEquals "build --build-arg gemfile=Gemfile.next -t repository:tag ." "${DOCKER_CALLS[0]}" + assertEquals "push repository:tag" "${DOCKER_CALLS[1]}" + assertNull "${DOCKER_CALLS[2]}" +} + testBuildCustomRepo() { DOCKER_TAG="tag" dockerBuildAndPush -r myrepo > /dev/null