dockerised tests

This commit is contained in:
Andrejus
2020-02-27 23:16:56 +00:00
parent 5074d56184
commit e2bd54995a
28 changed files with 488 additions and 66 deletions

4
.dockerignore Normal file
View File

@@ -0,0 +1,4 @@
.gitignore
.dockerignore
Dockerfile
README.md

5
.gitignore vendored
View File

@@ -1,2 +1,7 @@
# install
.dotlock
*.deb
# pytest
**/__pycache__
**/.pytest_cache

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.7.0

47
Dockerfile Normal file
View File

@@ -0,0 +1,47 @@
from ubuntu:bionic
# ---------------------------------------------------------------------------- #
# (usually) Cached steps
# ---------------------------------------------------------------------------- #
# Set variables up, FAST_MODE to prevent git and upgrade
ENV FAST_MODE="true"
ENV WORKSPACE="$HOME/workspace"
# Install sudo for compatibility, git since it is skipped, make
# Triple quiet mode (-qq implies -y, pipe to /dev/null)
RUN apt-get -qq update && \
apt-get -qq install sudo git make \
< /dev/null > /dev/null
# Create user with sudo priviledge
ENV USER="test-user"
RUN useradd --create-home -m $USER && \
adduser $USER sudo
RUN echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# ---------------------------------------------------------------------------- #
# Filesystem copy steps
# ---------------------------------------------------------------------------- #
# Copy dotfiles in
ADD --chown=test-user . "$WORKSPACE/dotfiles"
WORKDIR "$WORKSPACE/dotfiles"
# Allow execution
RUN chmod +x ./bootstrap.sh
# ---------------------------------------------------------------------------- #
# Install steps
# ---------------------------------------------------------------------------- #
# Run installer
USER test-user
RUN make install
# ---------------------------------------------------------------------------- #
# Test steps
# ---------------------------------------------------------------------------- #
# Run tests
RUN make test || true

View File

@@ -2,6 +2,18 @@
clean:
rm -f .dotlock
.PHONY: install
install:
bash bootstrap.sh
.PHONY: test
test:
bash test.sh
.PHONY: build
build:
docker build . -t dotfiles:latest
.PHONY: run
run:
bash bootstrap.sh
docker run -it dotfiles:latest /bin/bash

View File

@@ -17,6 +17,7 @@ Shell: 🐟 fish (+ fisher)
Tools:
* docker (+ docker-compose)
* keybase
* screenfetch
Languages:
* python (+ poetry, pyenv)

7
bash/.bashrc Normal file
View File

@@ -0,0 +1,7 @@
# pyenv
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
# poetry
export PATH="$HOME/.poetry/bin:$PATH"

View File

@@ -32,17 +32,24 @@
# $INSTALLER - installer file name
# @default "install.sh"
#
# $FAST_MODE - whether to skip git (and speed up install steps)
# @defualt unset
#
#
set -o pipefail
echo "setting up..."
# Variables: $REPOSITORY
if [ -z "$REPOSITORY" ]; then REPOSITORY="andrejusk/dotfiles"; fi
if [ -z "$REPOSITORY" ]; then
REPOSITORY="andrejusk/dotfiles"
fi
readonly repository_url="git@github.com:$REPOSITORY.git"
echo "using repository: $repository_url"
# Variables: $WORKSPACE
if [ -z "$WORKSPACE" ]; then WORKSPACE="$HOME/workspace"; fi
if [ -z "$WORKSPACE" ]; then
WORKSPACE="$HOME/workspace"
fi
readonly dotfiles_dir="$WORKSPACE/dotfiles"
echo "using dir: $dotfiles_dir"
@@ -51,6 +58,9 @@ if [ -z "$INSTALLER" ]; then INSTALLER="install.sh"; fi
readonly installer="$dotfiles_dir/$INSTALLER"
echo "using installer: $installer"
# Pull latest git if not skipped
if [ -z "$FAST_MODE" ]; then
# Ensure git is installed
if ! [ -x "$(command -v git)" ]; then
echo "installing git..."
@@ -58,7 +68,7 @@ if ! [ -x "$(command -v git)" ]; then
sudo apt-get install git -qqy
fi
# Ensure repository is up to date
# Ensure latest is pulled
echo "pulling latest..."
if [[ ! -d $dotfiles_dir ]]; then
mkdir -p "$dotfiles_dir"
@@ -68,6 +78,9 @@ else
git --git-dir="$dotfiles_dir/.git" rebase -q --autostash FETCH_HEAD
fi
fi
# Install dotfiles
cd "$dotfiles_dir"
source "$installer"
echo "done!"

View File

@@ -1,9 +1,7 @@
# Ensure fisher is installed
if not functions -q fisher
set -q XDG_CONFIG_HOME; or set XDG_CONFIG_HOME ~/.config
curl https://git.io/fisher --create-dirs -sLo $XDG_CONFIG_HOME/fish/functions/fisher.fish
fish -c fisher
end
# Pyenv
export PATH="$HOME/.pyenv/bin:$PATH"
eval (pyenv init -)
eval (pyenv virtualenv-init -)
# Poetry
set -gx PATH $HOME/.poetry/bin $PATH

View File

@@ -1,5 +1,7 @@
curl
make
net-tools
openssh-client
openssh-server
screenfetch
software-properties-common

View File

@@ -4,15 +4,16 @@
#
# Install list of packages in ./00-apt-pkglist
#
readonly package_list_file="00-apt-pkglist"
# apt update and upgrade non-interactively
# apt update, upgrade if not fast
update
if [ -z "$FAST_MODE" ]; then
upgrade
fi
# Package installs
readonly package_list=$(cat $install_dir/$package_list_file) # Don't escape list
install $package_list
readonly package_list_file="$install_dir/00-apt-pkglist"
install_file $package_list_file
# Log version
cat /etc/os-release

11
install/01-bash.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
#
# After running this script:
# 1. bash dotfiles are symlinked
#
# 1. bash dotfiles are symlinked
readonly bash_source="$dotfiles_dir/bash"
readonly bash_target="$HOME"
link_folder "$bash_source" "$bash_target"
printf "bash dotfiles are linked\n"

View File

@@ -18,6 +18,11 @@ if not_installed "fish"; then
# Install fish
install fish
# Install fisher
set -q XDG_CONFIG_HOME; or set XDG_CONFIG_HOME ~/.config
curl https://git.io/fisher --create-dirs -sLo $XDG_CONFIG_HOME/fish/functions/fisher.fish
fish -c fisher
fi
printf "fish is installed\n"
fish --version

View File

@@ -15,14 +15,20 @@ if not_installed "pyenv"; then
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
xz-utils tk-dev libffi-dev liblzma-dev python-openssl git
# Add to install path
add_path "$HOME/.pyenv/bin"
# Install pyenv
# see https://github.com/pyenv/pyenv-installer
run "https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer" bash
run "https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer" \
"bash"
refresh
# Add to install path and refresh
export PATH="$HOME/.pyenv/bin:$PATH"
hash -r
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
fi
printf "pyenv is installed\n"
printf "pyenv is installed, upgrading...\n"
readonly pyenv_root=$(pyenv root)
git --git-dir="$pyenv_root" pull
pyenv --version

20
install/11-python.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
#
# After running this script:
# 1. python3 and pip3 are installed
#
# 1. python3 and pip3 are installed
if not_installed "pip3"; then
printf "Installing python3 and pip3...\n"
pyenv install 3.7.0
pyenv global 3.7.0
pyenv local 3.7.0
fi
printf "python3 and pip3 are installed, upgrading...\n"
pip3 install --upgrade pip
python3 --version
pip3 --version

View File

@@ -10,7 +10,9 @@ if not_installed "poetry"; then
printf "Installing poetry...\n"
# Install poetry
run "https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py" "python"
pip3 install --user poetry
fi
printf "poetry is installed\n"
printf "poetry is installed, upgrading...\n"
pip3 install --upgrade poetry
poetry --version

View File

@@ -27,6 +27,10 @@ if not_installed "docker"; then
# Install
install docker-ce
# Chown
sudo chown "$USER":"$USER" "$HOME/.docker" -R
sudo chmod g+rwx "$HOME/.docker" -R
fi
printf "docker is installed\n"
docker --version
@@ -37,12 +41,12 @@ if not_installed "docker-compose"; then
printf "Installing docker-compose...\n"
# Docker-compose
readonly docker_compose_url="https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m)"
sudo curl -L "$docker_compose_url" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
pip3 install --user docker-compose
fi
printf "docker-compose is installed\n"
printf "docker-compose is installed, upgrading\n"
pip3 install --upgrade docker-compose
docker-compose --version
# 3. docker group exists

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env bash
#
# After running this script:
# 1. python is installed
#
# 1. python is installed
if not_installed "python"; then
printf "Installing python...\n"
pyenv install -s 3.7.0
pyenv global 3.7.0
fi
printf "python is installed\n"

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Clean up
sudo apt-get -qqy autoremove
sudo apt-get -qqy autoclean
sudo apt-get -y autoremove
sudo apt-get -y autoclean

9
test.sh Normal file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
#
# Invokes all test scripts.
#
set -euo pipefail
cd ./tests
poetry install
poetry run pytest

212
tests/poetry.lock generated Normal file
View File

@@ -0,0 +1,212 @@
[[package]]
category = "dev"
description = "Atomic file writes."
marker = "sys_platform == \"win32\""
name = "atomicwrites"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.3.0"
[[package]]
category = "dev"
description = "Classes Without Boilerplate"
name = "attrs"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "19.3.0"
[package.extras]
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
docs = ["sphinx", "zope.interface"]
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
[[package]]
category = "dev"
description = "Cross-platform colored terminal text."
marker = "sys_platform == \"win32\""
name = "colorama"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.3"
[[package]]
category = "dev"
description = "Read metadata from Python packages"
marker = "python_version < \"3.8\""
name = "importlib-metadata"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
version = "1.5.0"
[package.dependencies]
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "rst.linker"]
testing = ["packaging", "importlib-resources"]
[[package]]
category = "dev"
description = "More routines for operating on iterables, beyond itertools"
name = "more-itertools"
optional = false
python-versions = ">=3.5"
version = "8.2.0"
[[package]]
category = "dev"
description = "Core utilities for Python packages"
name = "packaging"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "20.1"
[package.dependencies]
pyparsing = ">=2.0.2"
six = "*"
[[package]]
category = "dev"
description = "plugin and hook calling mechanisms for python"
name = "pluggy"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.13.1"
[package.dependencies]
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12"
[package.extras]
dev = ["pre-commit", "tox"]
[[package]]
category = "dev"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
name = "py"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.8.1"
[[package]]
category = "dev"
description = "Python parsing module"
name = "pyparsing"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "2.4.6"
[[package]]
category = "dev"
description = "pytest: simple powerful testing with Python"
name = "pytest"
optional = false
python-versions = ">=3.5"
version = "5.3.5"
[package.dependencies]
atomicwrites = ">=1.0"
attrs = ">=17.4.0"
colorama = "*"
more-itertools = ">=4.0.0"
packaging = "*"
pluggy = ">=0.12,<1.0"
py = ">=1.5.0"
wcwidth = "*"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12"
[package.extras]
checkqa-mypy = ["mypy (v0.761)"]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[[package]]
category = "dev"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.14.0"
[[package]]
category = "dev"
description = "Measures number of Terminal column cells of wide-character codes"
name = "wcwidth"
optional = false
python-versions = "*"
version = "0.1.8"
[[package]]
category = "dev"
description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version < \"3.8\""
name = "zipp"
optional = false
python-versions = ">=3.6"
version = "3.0.0"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["jaraco.itertools", "func-timeout"]
[metadata]
content-hash = "76f248e0ec62688089444c71c5e62af7c3ca83978a893d09e6592e3621985fab"
python-versions = "^3.7"
[metadata.files]
atomicwrites = [
{file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"},
{file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"},
]
attrs = [
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
]
colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
]
importlib-metadata = [
{file = "importlib_metadata-1.5.0-py2.py3-none-any.whl", hash = "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b"},
{file = "importlib_metadata-1.5.0.tar.gz", hash = "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302"},
]
more-itertools = [
{file = "more-itertools-8.2.0.tar.gz", hash = "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507"},
{file = "more_itertools-8.2.0-py3-none-any.whl", hash = "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c"},
]
packaging = [
{file = "packaging-20.1-py2.py3-none-any.whl", hash = "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73"},
{file = "packaging-20.1.tar.gz", hash = "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334"},
]
pluggy = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
]
py = [
{file = "py-1.8.1-py2.py3-none-any.whl", hash = "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0"},
{file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"},
]
pyparsing = [
{file = "pyparsing-2.4.6-py2.py3-none-any.whl", hash = "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"},
{file = "pyparsing-2.4.6.tar.gz", hash = "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f"},
]
pytest = [
{file = "pytest-5.3.5-py3-none-any.whl", hash = "sha256:ff615c761e25eb25df19edddc0b970302d2a9091fbce0e7213298d85fb61fef6"},
{file = "pytest-5.3.5.tar.gz", hash = "sha256:0d5fe9189a148acc3c3eb2ac8e1ac0742cb7618c084f3d228baaec0c254b318d"},
]
six = [
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
]
wcwidth = [
{file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"},
{file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"},
]
zipp = [
{file = "zipp-3.0.0-py3-none-any.whl", hash = "sha256:12248a63bbdf7548f89cb4c7cda4681e537031eda29c02ea29674bc6854460c2"},
{file = "zipp-3.0.0.tar.gz", hash = "sha256:7c0f8e91abc0dc07a5068f315c52cb30c66bfbc581e5b50704c8a2f6ebae794a"},
]

15
tests/pyproject.toml Normal file
View File

@@ -0,0 +1,15 @@
[tool.poetry]
name = "dotfiles-test"
version = "0.0.0"
description = "Verifies dotfiles install"
authors = ["andrejus <hi@andrejus.uk>"]
[tool.poetry.dependencies]
python = "^3.7"
[tool.poetry.dev-dependencies]
pytest = "^5.3.5"
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

43
tests/test_binaries.py Normal file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env python3
#
# Verifies dotfiles install
#
from distutils.spawn import find_executable
from typing import List
import pytest
# List of binaries to test
binaries: List[str] = [
# shells
"sh", "bash", "fish",
# tools
"git",
"keybase",
"docker", "docker-compose",
"screenfetch",
# languages
"pyenv",
"python3",
"poetry",
]
def binary_in_path(binary: str) -> bool:
"""
Helper function to check whether `binary` is in PATH.
"""
return find_executable(binary) is not None
@pytest.mark.parametrize("binary", binaries)
def test_binaries(binary: str):
"""
Asserts all binaries are in PATH.
"""
assert binary_in_path(binary)

View File

@@ -4,20 +4,27 @@
#
update() {
sudo apt-get update -y
sudo apt-get update -qq
}
# Non-interactive upgrade
upgrade() {
DEBIAN_FRONTEND=noninteractive \
sudo apt-get dist-upgrade -y \
sudo apt-get dist-upgrade -qq \
-o Dpkg::Options::="--force-confdef" \
-o Dpkg::Options::="--force-confold"
}
# @arg $1 packages to install
install() {
sudo apt-get install -y $1
sudo apt-get install -qq $1
refresh
}
# @arg $1 package list file to install
install_file() {
sudo apt-get install -qq $(cat $1)
refresh
}
# @arg $1 repository to add
@@ -41,6 +48,7 @@ run() {
# @arg $1 source folder
# @arg $2 target folder
link_folder() {
mkdir -p $2
cp -srf $1/. $2
}
@@ -51,6 +59,18 @@ not_installed() {
! [ -x "$(command -v $1)" ]
}
# Refreshes PATH
refresh() {
hash -r
}
# Add to PATH and refresh
# @arg $1 path to add to PATH
add_path() {
export PATH="$1:$PATH"
refresh
}
# Colors
C_BLACK='\033[0;30m'
C_DGRAY='\033[1;30m'