From 23944d281f6666c22cb19c0e1edde25f2f47f0db Mon Sep 17 00:00:00 2001 From: Dmytro Serdiuk Date: Wed, 10 Jun 2020 12:49:12 +0300 Subject: [PATCH] Use `bats-core` instead of `bats` There is a separate Docker worker that allows running Bats tests based on version 1.2.0 of `bats-core` project. This modification allows receiving updates to the test runner. All testing procedure is reworked in a way that `workflows` file is responsible for running Docker workers for testing while scripts, located at `.workflows` directory, just run the needed workflows without pointing to an environment. `tests/git-elegant.bats` was updated as in Bash 3.x (which is used in the Bats worker) is not possible to get the last element of the array. So, `show-commands` in the tests is replaced with `prune-repository` as the last command produces the same amount of lines comparing to the fact that adding or removing of command will affect the output of `show-commands`. #135 --- .workflows/bats-pipeline.bash | 12 --- .workflows/bats/Dockerfile | 15 +++ .workflows/bats/bats-workflows.bash | 38 ++++++++ .workflows/ci-pipeline.bash | 55 ----------- .workflows/installation-workflows.bash | 53 +++++++++++ Dockerfile | 14 --- README.md | 2 +- tests/git-elegant.bats | 46 +++++----- workflows | 121 ++++++++++++++++++------- 9 files changed, 216 insertions(+), 140 deletions(-) delete mode 100755 .workflows/bats-pipeline.bash create mode 100644 .workflows/bats/Dockerfile create mode 100755 .workflows/bats/bats-workflows.bash delete mode 100755 .workflows/ci-pipeline.bash create mode 100755 .workflows/installation-workflows.bash delete mode 100644 Dockerfile diff --git a/.workflows/bats-pipeline.bash b/.workflows/bats-pipeline.bash deleted file mode 100755 index 1fb44f4..0000000 --- a/.workflows/bats-pipeline.bash +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -set -e -# Runs bats tests -# usage: ./script [command name] -if [[ -f version ]]; then - rm -v version -fi -if [[ -n "${1}" ]]; then - bats --tap $(find tests -type f -name "*${1}*") -else - bats --tap tests -fi diff --git a/.workflows/bats/Dockerfile b/.workflows/bats/Dockerfile new file mode 100644 index 0000000..afbcef3 --- /dev/null +++ b/.workflows/bats/Dockerfile @@ -0,0 +1,15 @@ +ARG bashversion=3.2.57 +FROM bash:${bashversion} +LABEL maintainer="Dmytro Serdiuk " \ + description="The image serves the environment for the testing of Elegant Git." +VOLUME /elegant-git +WORKDIR /elegant-git +ENV EG_ENABLE_TESTING true +ARG gitversion=2.26.2 +RUN apk add --no-cache git~=${gitversion} +ARG batsversion=v1.2.0 +RUN git clone --branch ${batsversion} --single-branch --depth 1 https://github.com/bats-core/bats-core.git; \ + cd bats-core && ./install.sh /usr/local && cd - && rm -r bats-core +COPY bats-workflows.bash /bats-workflows.bash +ENTRYPOINT [ "/bats-workflows.bash" ] +CMD ["help"] diff --git a/.workflows/bats/bats-workflows.bash b/.workflows/bats/bats-workflows.bash new file mode 100755 index 0000000..f67896b --- /dev/null +++ b/.workflows/bats/bats-workflows.bash @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -e +# Runs bats tests +# usage: ./script [command name] +if [[ -f version ]]; then + rm -v version +fi + +all_tests() { + exec bats --tap --recursive tests +} + +some_tests() { + exec bats --tap $(find tests -type f -name "*${1}*") +} + +usage() { + cat < + +Available commands: + help prints this message + all_tests runs all Bats tests + some_tests runs Bats tests matchinh a pattern + +MESSAGE +} + +main() { + case ${1} in + all_tests) all_tests ;; + some_tests) shift; some_tests "${@}" ;; + help) usage ;; + *) "${@}" ;; + esac +} + +main "${@}" diff --git a/.workflows/ci-pipeline.bash b/.workflows/ci-pipeline.bash deleted file mode 100755 index e1762e4..0000000 --- a/.workflows/ci-pipeline.bash +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -# This script is destructive! That's why it will work only if a specific variable is set. -# It's recommended to run it within a docker container only. -# Usage: -# ./ci-pipeline.bash runs quality pipeline -# ./ci-pipeline.bash --version prints tooling version -set -e - -fail() { - echo $@ - exit 1 -} - -pipeline() { - .workflows/bats-pipeline.bash || fail "Unit tests are failed." - ( - echo "Installation...." - git config --global user.name "Elegant Git" - git config --global user.email elegant.git@email.com - git config --global core.editor vi - git config --global elegant-git.acquired true - ./install.bash /usr/local src - echo "'Unknown command' testing..." - git elegant unknown-command | grep "Unknown command: git elegant unknown-command" - echo "Check installation of version's file..." - git elegant --version || exit 1 - ) || fail "Installation test is failed." -} - -say-version() { - echo "<<< $@ >>>" - echo "$($@)" - echo "" -} - -main() { - case $1 in - --version) - say-version "bats --version" - say-version "python --version" - say-version "pip freeze" - ;; - testing) - if [[ -z $EG_ENABLE_TESTING ]]; then - echo "Testing is disabled!" - exit 1 - fi - pipeline - ;; - *) - echo "Available commands: --version or testing"; exit 1 - esac -} - -main $@ diff --git a/.workflows/installation-workflows.bash b/.workflows/installation-workflows.bash new file mode 100755 index 0000000..54a52be --- /dev/null +++ b/.workflows/installation-workflows.bash @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# This script is destructive! That's why it will work only if a specific variable is set. +# It's recommended to run it within a docker container only. +# Usage: +# ./installation-workflows.bash runs quality pipeline +# ./installation-workflows.bash prints tooling version +set -e + +install() { + echo "Installation...." + git config --global user.name "Elegant Git" + git config --global user.email elegant.git@email.com + git config --global core.editor vi + git config --global elegant-git.acquired true + ./install.bash /usr/local src +} + +smoke-tests() { + echo "'Unknown command' testing..." + git elegant unknown-command | grep "Unknown command: git elegant unknown-command" + echo "Check installation of version's file..." + git elegant --version || exit 1 +} + +check-env() { + if [[ -z ${EG_ENABLE_TESTING} ]]; then + echo "Testing is disabled! Looks like the environment is not ready..." + exit 1 + fi +} + +usage() { + cat < + +Available commands: + help prints this message + install runs the installation process + smoke-tests runs smoke tests of the installation + +MESSAGE +} + +main() { + case $1 in + install) check-env && install ;; + smoke-tests) check-env && smoke-tests ;; + help) usage ;; + *) echo "Available commands: --version or testing"; exit 1 ;; + esac +} + +main "$@" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index ed579dc..0000000 --- a/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ruby:2.4.1-alpine3.6 -RUN apk update && \ - apk upgrade && \ - apk add --no-cache bats=0.4.0-r2 build-base libffi-dev ncurses git python3 && \ - ln -sf $(which python3) /usr/bin/python && \ - ln -sf $(which pip3) /usr/bin/pip && pip install --upgrade pip -LABEL maintainer="Dmytro Serdiuk " \ - description="Run the image without arguments to get the desciption." \ - version=5 -COPY docs/requirements.txt / -RUN pip install --no-cache -r requirements.txt && rm -r requirements.txt -WORKDIR /eg -ENV EG_ENABLE_TESTING true -CMD [".workflows/ci-pipeline.bash", "--version"] diff --git a/README.md b/README.md index dcd5285..02a0481 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ Run `unset GED` to switch debug off. ### Testing procedure A testing procedure consists of 3 steps: -1. unit testing using [bats](https://github.com/sstephenson/bats) +1. unit testing using [bats-core](https://github.com/bats-core/bats-core) 2. installation testing 3. validation of documentation correctness diff --git a/tests/git-elegant.bats b/tests/git-elegant.bats index 062006a..bda09c3 100644 --- a/tests/git-elegant.bats +++ b/tests/git-elegant.bats @@ -43,49 +43,49 @@ teardown(){ @test "'git elegant': a version is displayed correctly" { check git-elegant --version - [[ ${lines[@]} =~ "/eg/tests/../libexec/../version" ]] + [[ ${lines[@]} =~ "/elegant-git/tests/../libexec/../version" ]] } @test "'git elegant': workflows are loaded correctly when a command is executed from root directory" { repo "mkdir -p .workflows .git/.workflows" - repo "echo echo ahead git > .git/.workflows/show-commands-ahead" - repo "echo echo ahead no > .workflows/show-commands-ahead" - repo "echo echo after git > .git/.workflows/show-commands-after" - repo "echo echo after no > .workflows/show-commands-after" + repo "echo echo ahead git > .git/.workflows/prune-repository-ahead" + repo "echo echo ahead no > .workflows/prune-repository-ahead" + repo "echo echo after git > .git/.workflows/prune-repository-after" + repo "echo echo after no > .workflows/prune-repository-after" repo "chmod +x .git/.workflows/* .workflows/*" repo "ls -lah .git/.workflows/* .workflows/*" - check git-elegant show-commands + check git-elegant prune-repository [[ ${status} -eq 0 ]] - [[ ${lines[0]} =~ ".git/.workflows/show-commands-ahead" ]] + [[ ${lines[0]} =~ ".git/.workflows/prune-repository-ahead" ]] [[ ${lines[1]} == "ahead git" ]] - [[ ${lines[2]} =~ ".workflows/show-commands-ahead" ]] + [[ ${lines[2]} =~ ".workflows/prune-repository-ahead" ]] [[ ${lines[3]} == "ahead no" ]] - [[ ${lines[-4]} =~ ".git/.workflows/show-commands-after" ]] - [[ ${lines[-3]} == "after git" ]] - [[ ${lines[-2]} =~ ".workflows/show-commands-after" ]] - [[ ${lines[-1]} == "after no" ]] + [[ ${lines[6]} =~ ".git/.workflows/prune-repository-after" ]] + [[ ${lines[7]} == "after git" ]] + [[ ${lines[8]} =~ ".workflows/prune-repository-after" ]] + [[ ${lines[9]} == "after no" ]] } @test "'git elegant': workflows are loaded correctly when a command is executed from non-root directory" { repo mkdir -p .workflows .git/.workflows - repo "echo echo ahead git > .git/.workflows/show-commands-ahead" - repo "echo echo ahead no > .workflows/show-commands-ahead" - repo "echo echo after git > .git/.workflows/show-commands-after" - repo "echo echo after no > .workflows/show-commands-after" + repo "echo echo ahead git > .git/.workflows/prune-repository-ahead" + repo "echo echo ahead no > .workflows/prune-repository-ahead" + repo "echo echo after git > .git/.workflows/prune-repository-after" + repo "echo echo after no > .workflows/prune-repository-after" repo "chmod +x .git/.workflows/* .workflows/*" repo "ls -lah .git/.workflows/* .workflows/*" repo "mkdir -p some/path" repo "cd some/path" - check git-elegant show-commands + check git-elegant prune-repository [[ ${status} -eq 0 ]] - [[ ${lines[0]} =~ ".git/.workflows/show-commands-ahead" ]] + [[ ${lines[0]} =~ ".git/.workflows/prune-repository-ahead" ]] [[ ${lines[1]} == "ahead git" ]] - [[ ${lines[2]} =~ ".workflows/show-commands-ahead" ]] + [[ ${lines[2]} =~ ".workflows/prune-repository-ahead" ]] [[ ${lines[3]} == "ahead no" ]] - [[ ${lines[-4]} =~ ".git/.workflows/show-commands-after" ]] - [[ ${lines[-3]} == "after git" ]] - [[ ${lines[-2]} =~ ".workflows/show-commands-after" ]] - [[ ${lines[-1]} == "after no" ]] + [[ ${lines[6]} =~ ".git/.workflows/prune-repository-after" ]] + [[ ${lines[7]} == "after git" ]] + [[ ${lines[8]} =~ ".workflows/prune-repository-after" ]] + [[ ${lines[9]} == "after no" ]] } @test "'git elegant': workflows are ignored if --no-workflows is set before a command" { diff --git a/workflows b/workflows index 396b9a8..25187c4 100755 --- a/workflows +++ b/workflows @@ -3,13 +3,33 @@ set -e source ./libexec/plugins/text +bash_3_2_57=3.2.57 bash_5_0_17=5.0.17 python_3_8_3=3.8.3 +git_2_26_2=2.26.2 +bashes=( + ${bash_5_0_17} + ${bash_3_2_57} +) +gits=( + ${git_2_26_2} +) +base_testing_worker=bash${bash_3_2_57}-git${git_2_26_2} eg_docker_organization=beeshive eg_documents_repository=${eg_docker_organization}/elegant-git-docs-workflows eg_documents_image=${eg_documents_repository}:python${python_3_8_3}-bash${bash_5_0_17} -WORKER_IMAGE=${eg_docker_organization}/elegant-git-ci:5 +eg_bats_repository=${eg_docker_organization}/elegant-git-bats-worker +eg_bats_image=${eg_bats_repository}:${base_testing_worker} + + +--publish-worker() { + info-text "Select image to push:" + select tag in $(docker image ls --filter reference=${1} --format "{{.Repository}}:{{.Tag}}"); do + docker push ${tag} + break + done +} # docs workflows prepare-docs-worker() { @@ -24,11 +44,7 @@ prepare-docs-worker() { } publish-docs-worker() { - info-text "Select image to push:" - select tag in $(docker image ls --filter reference=${eg_documents_repository} --format "{{.Repository}}:{{.Tag}}"); do - docker push ${tag} - break - done + --publish-worker ${eg_documents_repository} } generate-docs() { @@ -53,25 +69,58 @@ serve-docs() { repository() { info-text "Start container..." - docker run -idt --rm --name repository --workdir /tmp/elegant-git-repo -v $PWD:/eg ${WORKER_IMAGE} bash + docker run --interactive --tty --detach --rm \ + --name repository \ + --workdir /tmp/elegant-git-repo \ + --mount type=bind,source=$(pwd),target=/elegant-git \ + ${eg_bats_image} bash info-text "Init repository..." - docker exec -it repository bash -c "source /eg/tests/addons-repo.bash;source /eg/tests/addons-common.bash; repo-new" + docker exec --interactive --tty repository bash -c " + cd /elegant-git + source tests/addons-repo.bash + source tests/addons-common.bash + repo-new + " info-text "Install Elegant Git..." - docker exec -it repository bash -c " - cd /eg - git config --global user.name \"Elegant Git\" - git config --global user.email elegant.git@email.com - git config --global core.editor vi - git config --global elegant-git.acquired true - ./install.bash /usr/local src + docker exec --interactive --tty repository bash -c " + cd /elegant-git + .workflows/installation-workflows.bash install " info-text "Ready! Enjoy experiments..." docker attach repository } # testing workflows +prepare-bats-worker() { + info-text "Select Bash and Git version:" + select bashv in ${bashes[*]}; do + bashversion=${bashv} + break + done + select gitv in ${gits[*]}; do + gitversion=${gitv} + break + done + local batsversion=v1.2.0 + docker build --tag ${eg_bats_repository}:bash${bashversion}-git${gitversion} \ + --label bashversion=${bashversion} \ + --label gitversion=${gitversion} \ + --label batsversion=${batsversion} \ + --build-arg bashversion=${bashversion} \ + --build-arg gitversion=${gitversion} \ + --build-arg batsversion=${batsversion} \ + .workflows/bats +} + +publish-bats-worker() { + --publish-worker ${eg_bats_repository} +} + testing() { - docker run -it --rm -v $PWD:/eg ${WORKER_IMAGE} .workflows/bats-pipeline.bash "$@" + echo $@ + docker run --interactive --rm \ + --mount type=bind,source=$(pwd),target=/elegant-git \ + ${eg_bats_image} some_tests "$@" } __fail() { @@ -95,24 +144,24 @@ test-docs-site() { } || __fail "Unable to build the documentation site." } +test-installation() { + ( + docker run --interactive --rm \ + --mount type=bind,source=$(pwd),target=/elegant-git \ + ${eg_bats_image} bash -c " + .workflows/installation-workflows.bash install + .workflows/installation-workflows.bash smoke-tests + " + ) || __fail "Installation test is failed." +} + ci() { - docker run --rm -v $PWD:/eg ${WORKER_IMAGE} .workflows/ci-pipeline.bash testing + docker run --interactive --rm \ + --mount type=bind,source=$(pwd),target=/elegant-git \ + ${eg_bats_image} all_tests test-commands-docs test-docs-site -} - -prepare-worker() { - if [[ -z ${1} ]]; then - error-text "Please specify a tag for Docker image (like '2')" - fi - docker build --no-cache -t beeshive/elegant-git-ci:${1} . -} - -publish-worker() { - if [[ -z ${1} ]]; then - error-text "Please specify a tag for Docker image (like '2')" - fi - docker push beeshive/elegant-git-ci:${1} + test-installation } robot() { @@ -161,13 +210,14 @@ Available commands: preview-docs runs a site with the current documentation (http://localhost) serve-docs runs 'generate-docs' and 'preview-docs' testing modifications - prepare-worker builds a new worker image - publish-worker pushes a new worker image + prepare-bats-worker builds a new '${eg_bats_image}' image + publish-bats-worker pushes the '${eg_bats_image}' image testing runs bats tests; accepts a optional pattern for tests filtering ("${BASH_SOURCE[0]} testing work" run all tests which have the word in the test name) test-commands-docs checks if the commands docs are up to date test-docs-site checks if the docs site can be built + test-installation checks if installation works fine ci runs CI quality assessment workflow robot runs tests for updated "libexec/git-elegant*" or "tests/git-elegant*.bats" files @@ -183,15 +233,16 @@ commands=( generate-docs preview-docs serve-docs + prepare-bats-worker + publish-bats-worker testing test-commands-docs test-docs-site + test-installation usage robot repository ci - prepare-worker - publish-worker ) main() {