From 1bcbefd20b5c1c6f0bb099d0ef1803e40c99c4d3 Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Mon, 15 Jan 2024 15:48:14 -0800 Subject: [PATCH] ci(docker-build): add python layer --- .github/citools/common/gh-setup-env | 20 ++ .github/citools/includes/wrapper-library | 27 +++ .github/citools/python/python-lint-formatter | 26 +++ .github/citools/python/python-setup-config | 24 ++ .github/citools/python/python-setup-install | 219 ++++++++++++++++++ .github/citools/python/python-setup-verify | 59 +++++ .../citools/python/python-test-with-coverage | 50 ++++ .github/docker/layer-18.00-exercism-python.sh | 69 ++++++ Dockerfile | 2 + 9 files changed, 496 insertions(+) create mode 100755 .github/citools/python/python-lint-formatter create mode 100755 .github/citools/python/python-setup-config create mode 100755 .github/citools/python/python-setup-install create mode 100755 .github/citools/python/python-setup-verify create mode 100755 .github/citools/python/python-test-with-coverage create mode 100755 .github/docker/layer-18.00-exercism-python.sh diff --git a/.github/citools/common/gh-setup-env b/.github/citools/common/gh-setup-env index 8cf05fb6..339c5e7b 100755 --- a/.github/citools/common/gh-setup-env +++ b/.github/citools/common/gh-setup-env @@ -131,6 +131,26 @@ main() { print_ruler + source /etc/profile.d/python.sh || track_errors + + printf "Adding Python paths to GITHUB_PATH...\n" + printf "%s\n" "/usr/local/pyenv/bin" "/usr/local/pyenv/shims" | tee -a "${GITHUB_PATH}" + + echo Adding source /etc/profile.d/ruby.sh to ~/.bashrc + echo '. /etc/profile.d/ruby.sh' | tee -a "${HOME}/.bashrc" || track_errors + printf "\n" + + printf "Setup Ruby symlinks for github user:\n" + cd "${HOME}" || track_errors + if [[ ! -d .pyenv ]]; then + ln -sv "/usr/local/pyenv" .pyenv || track_errors + fi + ls -l ~/.pyenv + cd - || track_errors + printf "\n" + + print_ruler + tail -n 1000 -v "${GITHUB_PATH}" print_ruler diff --git a/.github/citools/includes/wrapper-library b/.github/citools/includes/wrapper-library index 07e55f61..411d523d 100644 --- a/.github/citools/includes/wrapper-library +++ b/.github/citools/includes/wrapper-library @@ -207,3 +207,30 @@ show_tool_versions_node() { # md_code_tag printf "\n" } # show_tool_versions_node() + +show_tool_versions_python_short() { + # md_code_tag text + printf "Python versions:\n" + printf "\n" + python --version | paste /dev/null - + pyenv --version | paste /dev/null - + pip --version | paste /dev/null - + pdm --version | paste /dev/null - + # md_code_tag + printf "\n" +} # show_tool_versions_python_short() + +show_tool_versions_python() { + show_tool_versions_python_short + + if [[ -z ${GITHUB_ACTIONS} ]]; then + return + fi + + # md_code_tag text + printf "Installed Python packages:\n" + printf "\n" + pip list | paste /dev/null - + # md_code_tag + printf "\n" +} # show_tool_versions_python() diff --git a/.github/citools/python/python-lint-formatter b/.github/citools/python/python-lint-formatter new file mode 100755 index 00000000..5d6f3e26 --- /dev/null +++ b/.github/citools/python/python-lint-formatter @@ -0,0 +1,26 @@ +#!/bin/bash +# +# .github/citools/python/python-lint-formatter +# + +# shellcheck disable=SC1091 +source ../../.github/citools/includes/wrapper-library || exit + +declare -i retval=0 + +main() { + printf "\nRunning Python Formatter\n\n" + + show_tool_versions_python_short + + print_ruler + + run_command ruff . + + print_ruler + + echo Exit code: "${retval}" + return "${retval}" +} + +time main "${@}" diff --git a/.github/citools/python/python-setup-config b/.github/citools/python/python-setup-config new file mode 100755 index 00000000..4c690f39 --- /dev/null +++ b/.github/citools/python/python-setup-config @@ -0,0 +1,24 @@ +#!/bin/bash +# +# .github/citools/python/python-setup-config +# + +# shellcheck disable=SC1091 +source ../../.github/citools/includes/wrapper-library || exit + +declare -i retval=0 + +main() { + printf "Setup Python Environment\n\n" + + print_ruler + + ../../.github/citools/common/gh-setup-env || track_errors + + print_ruler + + echo Exit code: "${retval}" + return "${retval}" +} + +time main "${@}" diff --git a/.github/citools/python/python-setup-install b/.github/citools/python/python-setup-install new file mode 100755 index 00000000..0c207cdf --- /dev/null +++ b/.github/citools/python/python-setup-install @@ -0,0 +1,219 @@ +#!/bin/bash +# +# .github/citools/python/python-setup-install +# + +# shellcheck disable=SC1091 +source ../../.github/citools/includes/wrapper-library || exit + +declare -i retval=0 + +main() { + printf "Ruby Installation\n\n" + + print_ruler + + echo Running: sudo apt update + time sudo apt update || track_errors + + print_ruler + + local -a debs + debs=( + autoconf + automake + bc + bison + build-essential + curl + g++ + gcc + git + gnupg + libc6-dev + libffi-dev + libgdbm-dev + libgmp-dev + libncurses5-dev + libreadline-dev + libsqlite3-dev + libssl-dev + libtool + libyaml-dev + make + pkg-config + sqlite3 + zlib1g-dev + ) + + echo Running: sudo apt install -y "${debs[@]}" + time sudo apt install -y "${debs[@]}" || track_errors + + print_ruler + + echo Running: export PYTHON_CONFIGURE_OPTS="--enable-shared" + export PYTHON_CONFIGURE_OPTS="--enable-shared" + + print_ruler + + export PYENV_ROOT="/usr/local/pyenv" + + echo Running: git clone --depth=1 https://github.com/pyenv/pyenv.git "${PYENV_ROOT}" + git clone --depth=1 https://github.com/pyenv/pyenv.git "${PYENV_ROOT}" || track_errors + + print_ruler + + { cd "${HOME}/.pyenv" && time src/configure && time make -C src; } || track_errors + + print_ruler + + printf "Configuring Shell: " + tee /etc/profile.d/python.sh <<-EOF + # + # /etc/profile.d/python.sh + # + + export PYENV_ROOT="/usr/local/pyenv" + + if [[ ! \${PATH} =~ \${PYENV_ROOT}/bin ]]; then + export PATH="\${PYENV_ROOT_ROOT}/bin:\${PATH}" + fi + + if command -v pyenv 1>/dev/null 2>&1; then + if [[ ! \${PATH} =~ \${PYENV_ROOT}/shims ]]; then + eval "\$(pyenv init --path)" + fi + + if [[ -z \${PYENV_SHELL} ]]; then + eval "\$(pyenv init -)" + fi + + if [[ ! \${PATH} =~ \${PYENV_ROOT}/plugins/pyenv-virtualenv/shims ]]; then + eval "\$(pyenv virtualenv-init -)" + fi + fi + EOF + printf "done\n" + + # shellcheck disable=SC1090 + source /etc/profile.d/python.sh || track_errors + printf "done\n" + + print_ruler + + echo Running: pyenv -v + time pyenv -v || track_errors + + print_ruler + + echo Running: pyenv install --list + time pyenv install --list || track_errors + + print_ruler + + local python_version + python_version="$(pyenv install --list 2>/dev/null | grep '^[3-9]+[.][0-9]+[.]' | tail -n 1)" || track_errors + + echo Running: pyenv install "${python_version}" + time pyenv install "${python_version}" || track_errors + + print_ruler + + echo Running: pyenv global "${python_version}" + time pyenv global "${python_version}" || track_errors + + print_ruler + + echo Running: python -v + time python -v || track_errors + + print_ruler + + local -a pip_packages + pip_packages=( + ansible-lint + bandit[toml] + black + coverage + dagger-io + db-sqlite3 + flake8 + flawfinder + flynt + ipykernel + ipython + isort + itsdangerous + jsonlint + jsonschema + mccabe + mypy + mypy-extensions + pep8 + pep8-naming + pexpect + proselint + prospector + pycobertura + pycodestyle + pydantic + pydocstyle + pyflakes + pylint + pylint-flask + pyright + pysqlite3 + pytest + pytest-cov + pytest-docker + pytest-randomly + python-dateutil + python-lsp-black + python-lsp-jsonrpc + python-lsp-ruff + python-lsp-server + python-utils + pytype + refurb + rich-cli + ruff + safety + textual[dev] + textualize_see + tmuxp + toml + tomli + tomlkit + typeguard + types-Pygments + types-colorama + types-docutils + types-mock + types-setuptools + typing_extensions + xmlformatter + yamlfix + yamllint + yapf + ) + + echo Running: pip install --upgrade pip + time pip install --upgrade pip || track_errors + + print_ruler + + echo Running: pip install --user pdm + time pip install --user pdm || track_errors + + print_ruler + + echo Running: pip install "${pip_packages[@]}" + time pip install "${pip_packages[@]}" || track_errors + + print_ruler + + echo Exit code: "${retval}" + return "${retval}" +} + +time main "${@}" diff --git a/.github/citools/python/python-setup-verify b/.github/citools/python/python-setup-verify new file mode 100755 index 00000000..c493c83d --- /dev/null +++ b/.github/citools/python/python-setup-verify @@ -0,0 +1,59 @@ +#!/bin/bash +# +# .github/citools/python/python-setup-verify +# + +# shellcheck disable=SC1091 +source ../../.github/citools/includes/wrapper-library || exit + +declare -i retval=0 + +declare -A python_cmds + +python_cmds=( + [python]=$( + command -v python >&/dev/null + echo "$?" + ) + [pyenv]=$( + command -v pyenv >&/dev/null + echo "$?" + ) + [pip]=$( + command -v pip >&/dev/null + echo "$?" + ) +) + +main() { + printf "Verifying Python Installation\n\n" + + print_ruler + + echo Running: source /etc/profile.d/python.sh + source /etc/profile.d/python.sh || track_errors + + print_ruler + + for key in "${!python_cmds[@]}"; do + if [[ ${python_cmds[${key}]} -ne 0 ]]; then + printf "ERROR: command [%s] not found.\n" "${key}" + ((retval++)) + fi + done + + if [[ ${retval} -ne 0 ]]; then + return "${retval}" + fi + + print_ruler + + show_tool_versions_python + + print_ruler + + echo Exit code: "${retval}" + return "${retval}" +} + +time main "${@}" diff --git a/.github/citools/python/python-test-with-coverage b/.github/citools/python/python-test-with-coverage new file mode 100755 index 00000000..51c09c0c --- /dev/null +++ b/.github/citools/python/python-test-with-coverage @@ -0,0 +1,50 @@ +#!/bin/bash +# +# .github/citools/python/python-test-with-coverage +# + +# shellcheck disable=SC1091 +source ../../.github/citools/includes/wrapper-library || exit + +declare -i retval=0 + +main() { + printf "\nRunning Python Tests With Coverage\n\n" + + show_tool_versions_python_short + + print_ruler + + run_command rm -rf ./coverage + + print_ruler + + run_command pytest --verbose --cov=. --cov-branch --cov-report={term-missing,xml:.coverage.xml} -p no:randomly || ((retval++)) + + print_ruler + + echo Running: coverage report --show-missing + coverage report --show-missing + + print_ruler + + echo Running: coverage annotate + coverage annotate + + print_ruler + + local coverage_line + coverage_line="$(xq -q coverage -a line-rate .coverage.xml)" + printf "Line Coverage: %.1f%%\n" "$(bc <<<"scale=1; ${coverage_line}* 100")" + + local coverage_branch + coverage_branch="$(xq -q coverage -a line-rate .coverage.xml)" + printf "Branch Coverage: %.1f%%\n" "$(bc <<<"scale=1; ${coverage_branch}* 100")" + + print_ruler + + echo Exit code: "${retval}" + return "${retval}" +} + +time main "${@}" diff --git a/.github/docker/layer-18.00-exercism-python.sh b/.github/docker/layer-18.00-exercism-python.sh new file mode 100755 index 00000000..200d6ce8 --- /dev/null +++ b/.github/docker/layer-18.00-exercism-python.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# +# .github/docker/layer-18.00-exercism-python.sh +# + +set -o pipefail + +# this path from for the container +# shellcheck disable=SC1091 +. /.github/docker/include + +# shellcheck disable=SC1091 +source /.github/citools/includes/wrapper-library || exit + +main() { + declare -i retval=0 + + layer_begin "${0}" "$@" + + export PYENV_ROOT="/usr/local/pyenv" + + echo Running: /.github/citools/python/python-setup-install + time /.github/citools/python/python-setup-install || track_errors + printf "\n" + + echo Running: /.github/citools/python/python-setup-config + time /.github/citools/python/python-setup-config || track_errors + printf "\n" + + echo Running: mv .pyenv "${PYENV_ROOT}" + time mv "${HOME}/.pyenv" "${PYENV_ROOT}" || track_errors + printf "\n" + + echo Running: ln -sv /usr/local/pyenv "${HOME}/.pyenv" + ln -sv "${PYENV_ROOT}" "${HOME}/.pyenv" || track_errors + printf "\n" + + echo Running: ln -sv /usr/local/pyenv "/etc/skel/.pyenv" + ln -sv "${PYENV_ROOT}" "/etc/skel/.pyenv" || track_errors + printf "\n" + + echo Checking installation: + ls -lh /usr/local/ "${PYENV_ROOT}" "${HOME}"/.pyenv /etc/skel/.pyenv + printf "\n" + + echo Adding source /etc/profile.d/python.sh to ~/.bashrc and /etc/skel/.bashrc + echo '. /etc/profile.d/python.sh' | tee -a "${HOME}/.bashrc" | tee -a "${HOME}/.profile" | tee -a /etc/skel/.bashrc + printf "\n" + + echo Running: source /etc/profile.d/python.sh + # shellcheck disable=SC1091 + source /etc/profile.d/python.sh || track_errors + printf "\n" + + echo Running: chgrp -R adm /usr/local/pyenv + chgrp -R adm "${PYENV_ROOT}" || track_errors + printf "\n" + + echo Running: setfacl -RPdm g:adm:w /usr/local/pyenv + setfacl -RPdm g:adm:w "${PYENV_ROOT}" || track_errors + printf "\n" + + layer_end "${0}" "$@" + + echo Running: return "${retval}" + return "${retval}" +} + +time main "${@}" |& tee "${HOME}"/layer-18.00-exercism-python.log diff --git a/Dockerfile b/Dockerfile index 366ac1d9..99454c16 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,6 +30,8 @@ RUN bash .github/docker/layer-16.00-exercism-go.sh ci-generic-debian && : 202401 RUN bash .github/docker/layer-17.00-exercism-ruby.sh ci-generic-debian && : 20231103-000 +RUN bash .github/docker/layer-18.00-exercism-python.sh ci-generic-debian && : 20231115-000 + RUN bash .github/docker/layer-25.00-tools-vscode.sh ci-generic-debian && : 20240102-000 RUN bash .github/docker/layer-35.00-tools-tailscale.sh ci-generic-debian && : 20240111-000