blob: c1edcfee8df1338948cae473f6b5880405b6ea1a [file] [log] [blame]
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Bash sanity settings (error on exit, complain for undefined vars, error when pipe fails)
set -euo pipefail
MY_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
export AIRFLOW_SOURCES="${MY_DIR}"
# Directory where all CI scripts are located
export SCRIPTS_CI_DIR="${MY_DIR}/scripts/ci"
BUILD_CACHE_DIR="${MY_DIR}/.build"
FILES_DIR="${MY_DIR}/files"
TMP_DIR="${MY_DIR}/tmp"
mkdir -pv "${BUILD_CACHE_DIR}"
mkdir -pv "${TMP_DIR}"
mkdir -pv "${FILES_DIR}"
function save_to_file {
# shellcheck disable=SC2005
echo "$(eval echo "\$$1")" > "${BUILD_CACHE_DIR}/.$1"
}
function read_from_file {
cat "${BUILD_CACHE_DIR}/.$1" 2>/dev/null || true
}
export PYTHON_VERSION="${PYTHON_VERSION:=$(read_from_file PYTHON_VERSION)}"
# shellcheck source=scripts/ci/_utils.sh
. "${SCRIPTS_CI_DIR}/_utils.sh"
basic_sanity_checks
script_start
# Sets width of the screen
SEPARATOR_WIDTH="$(tput cols)"
# Name of the script
CMDNAME="$(basename -- "$0")"
# Update short and long options in the breeze-complete script
# This way autocomplete will work automagically with all options
# shellcheck source=breeze-complete
. "${MY_DIR}/breeze-complete"
# Whether to actually run docker compose with the command set given
ENTER_ENVIRONMENT="true"
# Whether to cleanup local image
CLEANUP_IMAGES="false"
# Skips mounting local Airflow sources
SKIP_MOUNTING_LOCAL_SOURCES="false"
# If set, we initialize local virtualenv and install all dependencies
INITIALIZE_LOCAL_VIRTUALENV=false
# If set, we setup autocomplete for breeze
SETUP_AUTOCOMPLETE=false
# Holds chosen command if the -x flag is used.
RUN_COMMAND=""
# Holds the test target if the -t flag is used.
TEST_TARGET=""
# Holds docker compose command if the -d flag is used.
DOCKER_COMPOSE_COMMAND=""
# If true, the docker images are rebuilt locally.
export AIRFLOW_CONTAINER_DOCKER_BUILD_NEEDED="false"
# By default we only pull images if we do not have them locally.
# This can be overridden by -p flag
export AIRFLOW_CONTAINER_FORCE_PULL_IMAGES="false"
# We use docker image caches by default to speed up the builds
export AIRFLOW_CONTAINER_USE_DOCKER_CACHE=${AIRFLOW_CONTAINER_USE_DOCKER_CACHE:="true"}
# By default we do not push images. This can be overridden by -u flag.
export AIRFLOW_CONTAINER_PUSH_IMAGES=${AIRFLOW_CONTAINER_PUSH_IMAGES:="false"}
# For local builds we fix file permissions only for setup-related files
export AIRFLOW_FIX_PERMISSIONS=${AIRFLOW_FIX_PERMISSIONS:="setup"}
# Skip building slim image locally - we only need full CI image
export AIRFLOW_CONTAINER_SKIP_CI_SLIM_IMAGE="true"
# Skip building full CI image locally - we only need slim image
export AIRFLOW_CONTAINER_SKIP_CI_IMAGE="false"
# Branch name of the base image used (usually master or v1-10-test or v1-10-stable)
export AIRFLOW_CONTAINER_BRANCH_NAME=${AIRFLOW_CONTAINER_BRANCH_NAME:=${DEFAULT_BRANCH}}
# Determine version of the Airflow from version.py
AIRFLOW_VERSION=$(cat airflow/version.py - << EOF | python
print(version.replace("+",""))
EOF
)
export AIRFLOW_VERSION
# Verbosity in running ci scripts
export VERBOSE="false"
# Enter environment by default, rather than run tests or bash command or docker compose or static checks
export RUN_TESTS="false"
export RUN_DOCKER_COMPOSE="false"
export RUN_IN_BASH="false"
export RUN_STATIC_CHECKS="false"
export RUN_BUILD_DOCS="false"
export AIRFLOW_CONTAINER_FORCE_DOCKER_BUILD=${AIRFLOW_CONTAINER_FORCE_DOCKER_BUILD:="false"}
# Files determining whether asciiart/cheatsheet are suppressed
SUPPRESS_CHEATSHEET_FILE="${MY_DIR}/.suppress_cheatsheet"
SUPPRESS_ASCIIART_FILE="${MY_DIR}/.suppress_asciiart"
function print_badge {
if [[ ! -f "${SUPPRESS_ASCIIART_FILE}" ]]; then
cat <<EOF
@&&&&&&@
@&&&&&&&&&&&@
&&&&&&&&&&&&&&&&
&&&&&&&&&&
&&&&&&&
&&&&&&&
@@@@@@@@@@@@@@@@ &&&&&&
@&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&
&&&&&&&&&
&&&&&&&&&&&&
@@&&&&&&&&&&&&&&&@
@&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&
&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&
&&&&&&
&&&&&&&
@&&&&&&&&
@&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
@&&&@ && @&&&&&&&&&&& &&&&&&&&&&&& && &&&&&&&&&& &&& &&& &&&
&&& &&& && @&& &&& && && &&& &&&@ &&& &&&&& &&&
&&& &&& && @&&&&&&&&&&&& &&&&&&&&&&& && && &&& &&& &&& &&@ &&&
&&&&&&&&&&& && @&&&&&&&&& && && &&@ &&& &&@&& &&@&&
&&& &&& && @&& &&&@ && &&&&&&&&&&& &&&&&&&&&&&& &&&& &&&&
&&&&&&&&&&&& &&&&&&&&&&&& &&&&&&&&&&&@ &&&&&&&&&&&& &&&&&&&&&&& &&&&&&&&&&&
&&& &&& && &&& && &&& &&&& &&
&&&&&&&&&&&&@ &&&&&&&&&&&& &&&&&&&&&&& &&&&&&&&&&& &&&& &&&&&&&&&&
&&& && && &&&& && &&& &&&& &&
&&&&&&&&&&&&& && &&&&@ &&&&&&&&&&&@ &&&&&&&&&&&& @&&&&&&&&&&& &&&&&&&&&&&
Branch name: ${AIRFLOW_CONTAINER_BRANCH_NAME}
Docker image: ${AIRFLOW_CONTAINER_DOCKER_IMAGE}
Airflow version: ${AIRFLOW_VERSION}
Python version: ${PYTHON_VERSION}
DockerHub user: ${DOCKERHUB_USER}
DockerHub repo: ${DOCKERHUB_REPO}
Backend: ${BACKEND}
Env: ${ENV}
EOF
if [[ ${ENV} == "kubernetes" ]]; then
cat <<EOF
Kubernetes version: ${KUBERNETES_VERSION}
Kubernetes mode: ${KUBERNETES_MODE}
EOF
fi
else
cat <<EOF
Branch name: ${AIRFLOW_CONTAINER_BRANCH_NAME}
Docker image: ${AIRFLOW_CONTAINER_DOCKER_IMAGE}
Airflow version: ${AIRFLOW_VERSION}
Python version: ${PYTHON_VERSION}
DockerHub user: ${DOCKERHUB_USER}
DockerHub repo: ${DOCKERHUB_REPO}
Backend: ${BACKEND}
Env: ${ENV}
EOF
if [[ ${ENV} == "kubernetes" ]]; then
cat <<EOF
Kubernetes version: ${KUBERNETES_VERSION}
Kubernetes mode: ${KUBERNETES_MODE}
EOF
fi
fi
}
function prepare_command_file() {
local FILE="${1}"
local CMD="${2}"
local TESTS="${3}"
local EXPANSION="${4-@}"
cat <<EOF > "${FILE}"
#!/usr/bin/env bash
cd "\$(pwd)" || exit
export DOCKERHUB_USER=${DOCKERHUB_USER}
export DOCKERHUB_REPO=${DOCKERHUB_REPO}
export COMPOSE_FILE="${COMPOSE_FILE}"
export PYTHON_VERSION="${PYTHON_VERSION}"
export BACKEND="${BACKEND}"
export ENV="${ENV}"
export KUBERNETES_VERSION="${KUBERNETES_VERSION}"
export KUBERNETES_MODE="${KUBERNETES_MODE}"
export AIRFLOW_VERSION="${AIRFLOW_VERSION}"
export RUN_TESTS="${TESTS}"
export WEBSERVER_HOST_PORT="${WEBSERVER_HOST_PORT}"
export POSTGRES_HOST_PORT="${POSTGRES_HOST_PORT}"
export MYSQL_HOST_PORT="${MYSQL_HOST_PORT}"
docker-compose --log-level INFO ${CMD}\$${EXPANSION}"
EOF
chmod u+x "${FILE}"
}
# Default values
_BREEZE_DEFAULT_ENV="docker"
_BREEZE_DEFAULT_BACKEND="sqlite"
_BREEZE_DEFAULT_KUBERNETES_VERSION="v1.13.0"
_BREEZE_DEFAULT_KUBERNETES_MODE="git_mode"
usage() {
echo """
Usage: ${CMDNAME} [FLAGS] \\
[-k]|[-S <STATIC_CHECK>]|[-F <STATIC_CHECK>]|[-O]|[-e]|[-a]|[-b]|[-t <TARGET>]|[-x <COMMAND>]|[-d <COMMAND>] \\
-- <EXTRA_ARGS>
The swiss-knife-army tool for Airflow testings. It allows to perform various test tasks:
* Enter interactive environment when no command flags are specified (default behaviour)
* Stop the interactive environment with -k, --stop-environment command
* Run static checks - either for currently staged change or for all files with
-S, --static-check or -F, --static-check-all-files commanbd
* Build documentation with -O, --build-docs command
* Setup local virtualenv with -e, --setup-virtualenv command
* Setup autocomplete for itself with -a, --setup-autocomplete command
* Build docker image with -b, --build-only command
* Run test target specified with -t, --test-target connad
* Execute arbitrary command in the test environmenrt with -x, --execute-command command
* Execute arbitrary docker-compose command with -d, --docker-compose command
** Commands
By default the script enters IT environment and drops you to bash shell,
but you can also choose one of the commands to run specific actions instead:
-k, --stop-environment
Bring down running docker compose environment. When you start the environment, the docker
containers will continue running so that startup time is shorter. But they take quite a lot of
memory and CPU. This command stops all running containers from the environment.
-O, --build-docs
Build documentation.
-S, --static-check <STATIC_CHECK>
Run selected static checks for currently changed files. You should specify static check that
you would like to run or 'all' to run all checks. One of
[${_BREEZE_ALLOWED_STATIC_CHECKS:=}].
You can pass extra arguments including options to to the pre-commit framework as
<EXTRA_ARGS> passed after --. For example:
'${0} --static-check mypy' or
'${0} --static-check mypy -- --files tests/core.py'
You can see all the options by adding --help EXTRA_ARG:
'${0} --static-check mypy -- --help'
-F, --static-check-all-files <STATIC_CHECK>
Run selected static checks for all applicable files. You should specify static check that
you would like to run or 'all' to run all checks. One of
[${_BREEZE_ALLOWED_STATIC_CHECKS:=}].
You can pass extra arguments including options to the pre-commit framework as
<EXTRA_ARGS> passed after --. For example:
'${0} --static-check-all-files mypy' or
'${0} --static-check-all-files mypy -- --verbose'
You can see all the options by adding --help EXTRA_ARG:
'${0} --static-check-all-files mypy -- --help'
-e, --initialize-local-virtualenv
Initializes locally created virtualenv installing all dependencies of Airflow.
This local virtualenv can be used to aid autocompletion and IDE support as
well as run unit tests directly from the IDE. You need to have virtualenv
activated before running this command.
-a, --setup-autocomplete
Sets up autocomplete for breeze commands. Once you do it you need to re-enter the bash
shell and when typing breeze command <TAB> will provide autocomplete for parameters and values.
-b, --build-only
Only build docker images but do not enter the airflow-testing docker container.
-t, --test-target <TARGET>
Run the specified unit test target. There might be multiple
targets specified separated with comas. The <EXTRA_ARGS> passed after -- are treated
as additional options passed to nosetest. For example:
'${0} --test-target tests.core -- --logging-level=DEBUG'
-x, --execute-command <COMMAND>
Run chosen command instead of entering the environment. The command is run using
'bash -c \"<command with args>\" if you need to pass arguments to your command, you need
to pass them together with command surrounded with \" or '. Alternatively you can pass arguments as
<EXTRA_ARGS> passed after --. For example:
'${0} --execute-command \"ls -la\"' or
'${0} --execute-command ls -- --la'
-d, --docker-compose <COMMAND>
Run docker-compose command instead of entering the environment. Use 'help' command
to see available commands. The <EXTRA_ARGS> passed after -- are treated
as additional options passed to docker-compose. For example
'${0} --docker-compose pull -- --ignore-pull-failures'
** General flags
-h, --help
Shows this help message.
-P, --python <PYTHON_VERSION>
Python version used for the image. This is always major/minor version.
One of [${_BREEZE_ALLOWED_PYTHON_VERSIONS:=}]. Default is the python3 or python on the path.
-E, --env <ENVIRONMENT>
Environment to use for tests. It determines which types of tests can be run.
One of [${_BREEZE_ALLOWED_ENVS:=}]. Default: ${_BREEZE_DEFAULT_ENV:=}
-B, --backend <BACKEND>
Backend to use for tests - it determines which database is used.
One of [${_BREEZE_ALLOWED_BACKENDS:=}]. Default: ${_BREEZE_DEFAULT_BACKEND:=}
-K, --kubernetes-version <KUBERNETES_VERSION>
Kubernetes version - only used in case of 'kubernetes' environment.
One of [${_BREEZE_ALLOWED_KUBERNETES_VERSIONS:=}]. Default: ${_BREEZE_DEFAULT_KUBERNETES_VERSION:=}
-M, --kubernetes-mode <KUBERNETES_MODE>
Kubernetes mode - only used in case of 'kubernetes' environment.
One of [${_BREEZE_ALLOWED_KUBERNETES_MODES:=}]. Default: ${_BREEZE_DEFAULT_KUBERNETES_MODE:=}
-s, --skip-mounting-source-volume
Skips mounting local volume with sources - you get exactly what is in the
docker image rather than your current local sources of airflow.
-v, --verbose
Show verbose information about executed commands (enabled by default for running test)
-y, --assume-yes
Assume 'yes' answer to all questions.
-n, --assume-no
Assume 'no' answer to all questions.
-C, --toggle-suppress-cheatsheet
Toggles on/off cheatsheet displayed before starting bash shell
-A, --toggle-suppress-asciiart
Toggles on/off asciiart displayed before starting bash shell
** Dockerfile management flags
-D, --dockerhub-user
DockerHub user used to pull, push and build images. Default: ${_BREEZE_DEFAULT_DOCKERHUB_USER:=}.
-H, --dockerhub-repo
DockerHub repository used to pull, push, build images. Default: ${_BREEZE_DEFAULT_DOCKERHUB_REPO:=}.
-r, --force-build-images
Forces building of the local docker images. The images are rebuilt
automatically for the first time or when changes are detected in
package-related files, but you can force it using this flag.
-R, --force-build-images-clean
Force build images without cache. This will remove the pulled or build images
and start building images from scratch. This might take a long time.
-p, --force-pull-images
Forces pulling of images from DockerHub before building to populate cache. The
images are pulled by default only for the first time you run the
environment, later the locally build images are used as cache.
-u, --push-images
After building - uploads the images to DockerHub
It is useful in case you use your own DockerHub user to store images and you want
to build them locally. Note that you need to use 'docker login' before you upload images.
-c, --cleanup-images
Cleanup your local docker cache of the airflow docker images. This will not reclaim space in
docker cache. You need to 'docker system prune' (optionally with --all) to reclaim that space.
"""
}
#################### Parsing options/arguments
if ! PARAMS=$(getopt \
-o "${_BREEZE_GETOPT_SHORT_OPTIONS:=}" \
-l "${_BREEZE_GETOPT_LONG_OPTIONS:=}" \
--name "$CMDNAME" -- "$@")
then
usage
exit 1
fi
eval set -- "${PARAMS}"
unset PARAMS
# Parse Flags.
# Please update short and long options in the breeze-complete script
# This way autocomplete will work out-of-the-box
while true
do
case "${1}" in
-h|--help)
usage;
exit 0 ;;
-P|--python)
export PYTHON_VERSION="${2}";
echo
echo "Python version: ${PYTHON_VERSION}"
echo
shift 2 ;;
-E|--env)
export ENV="${2}";
echo
echo "Environment: ${ENV}"
echo
shift 2 ;;
-B|--backend)
export BACKEND="${2}";
echo
echo "Backend: ${BACKEND}"
echo
shift 2 ;;
-K|--kubernetes-version)
export KUBERNETES_VERSION="${2}";
echo
echo "Kubernetes version: ${KUBERNETES_VERSION}"
echo
shift 2 ;;
-M|--kubernetes-mode)
export KUBERNETES_MODE="${2}";
echo
echo "Kubernetes mode: ${KUBERNETES_MODE}"
echo
shift 2 ;;
-s|--skip-mounting-local-sources)
SKIP_MOUNTING_LOCAL_SOURCES="true"
echo "Skip mounting local sources: ${SKIP_MOUNTING_LOCAL_SOURCES}"
echo
shift ;;
-b|--build-only)
ENTER_ENVIRONMENT="false"
export AIRFLOW_CONTAINER_FORCE_DOCKER_BUILD="true"
echo "Only build. Do not enter airflow-testing container"
echo
shift ;;
-v|--verbose)
VERBOSE="true"
echo "Verbose output"
echo
shift ;;
-y|--assume-yes)
export FORCE_ANSWER_TO_QUESTIONS="yes"
echo "Assuming 'yes' answer to all questions."
echo
shift ;;
-n|--assume-no)
export FORCE_ANSWER_TO_QUESTIONS="no"
echo "Assuming 'no' answer to all questions."
echo
shift ;;
-C|--toggle-suppress-cheatsheet)
if [[ -f "${SUPPRESS_CHEATSHEET_FILE}" ]]; then
rm -f "${SUPPRESS_CHEATSHEET_FILE}"
else
touch "${SUPPRESS_CHEATSHEET_FILE}"
fi
echo "Toggle suppress cheatsheet"
echo
shift ;;
-A|--toggle-suppress-asciiart)
if [[ -f "${SUPPRESS_ASCIIART_FILE}" ]]; then
rm -f "${SUPPRESS_ASCIIART_FILE}"
else
touch "${SUPPRESS_ASCIIART_FILE}"
fi
echo "Toggle suppress asciiart"
echo
shift ;;
-r|--force-build-images)
echo
echo "Force build images"
echo
export AIRFLOW_CONTAINER_FORCE_DOCKER_BUILD="true"
shift ;;
-R|--force-build-images-clean)
echo
echo "Clean build of images without cache"
echo
export AIRFLOW_CONTAINER_USE_DOCKER_CACHE=false
export AIRFLOW_CONTAINER_USE_PULLED_IMAGES_CACHE=false
export AIRFLOW_CONTAINER_FORCE_DOCKER_BUILD="true"
CLEANUP_IMAGES="true"
shift ;;
-p|--force-pull-images)
echo
echo "Force pulling images before build. Uses pulled images as cache."
echo
export AIRFLOW_CONTAINER_FORCE_PULL_IMAGES="true"
export AIRFLOW_CONTAINER_FORCE_DOCKER_BUILD="true"
shift ;;
-u|--push-images)
if [[ "${AIRFLOW_FIX_PERMISSIONS}" != "all" ]]; then
echo >&2
echo >&2 "ERROR: Disable fix permissions when pushing"
echo >&2
echo >&2 "You cannot push images if you have AIRFLOW_FIX_PERMISSIONS set to other value than 'all'"
echo >&2 "Your docker context is most likely wrong in this case"
echo >&2 "You need to set AIRFLOW_FIX_PERMISSIONS to false"
echo >&2 "And run the build again"
echo >&2
exit 1
fi
echo
echo "Pushing images to DockerHub"
echo
export AIRFLOW_CONTAINER_PUSH_IMAGES="true"
export AIRFLOW_CONTAINER_FORCE_DOCKER_BUILD="true"
shift ;;
-c|--cleanup-images)
echo
echo "Cleanup the images"
echo
CLEANUP_IMAGES=true
shift ;;
-D|--dockerhub-user)
export DOCKERHUB_USER="${2}"
echo
echo "Dockerhub user ${DOCKERHUB_USER}"
echo
shift 2 ;;
-H|--dockerhub-repo)
export DOCKERHUB_REPO="${2}"
echo
echo "Dockerhub repo ${DOCKERHUB_REPO}"
echo
shift 2 ;;
-e|--initialize-local-virtualenv)
echo
echo Initializing local virtualenv
echo
INITIALIZE_LOCAL_VIRTUALENV="true"
SETUP_AUTOCOMPLETE="false"
ENTER_ENVIRONMENT=:"false"
shift ;;
-a|--setup-autocomplete)
echo
echo Setting up autocomplete
echo
INITIALIZE_LOCAL_VIRTUALENV="false"
SETUP_AUTOCOMPLETE="true"
ENTER_ENVIRONMENT=:"false"
shift ;;
-t|--test-target)
export TEST_TARGET="${2}"
export RUN_IN_BASH="false"
export RUN_TESTS="true"
export RUN_DOCKER_COMPOSE="false"
export RUN_STATIC_CHECKS="false"
export RUN_BUILD_DOCS="false"
shift 2 ;;
-d|--docker-compose)
export DOCKER_COMPOSE_COMMAND="${2}"
export RUN_IN_BASH="false"
export RUN_TESTS="false"
export RUN_DOCKER_COMPOSE="true"
export RUN_STATIC_CHECKS="false"
export RUN_BUILD_DOCS="false"
shift 2 ;;
-k|--stop-environment)
export DOCKER_COMPOSE_COMMAND="down"
export RUN_IN_BASH="false"
export RUN_TESTS="false"
export RUN_BUILD_DOCS="false"
export RUN_DOCKER_COMPOSE="true"
export RUN_STATIC_CHECKS="false"
shift ;;
-x|--execute-command)
export RUN_COMMAND="${2}"
export RUN_IN_BASH="true"
export RUN_TESTS="false"
export RUN_BUILD_DOCS="false"
export RUN_DOCKER_COMPOSE="false"
export RUN_STATIC_CHECKS="false"
shift 2 ;;
-S|--static-check )
export ENTER_ENVIRONMENT="false"
export RUN_TESTS="false"
export RUN_DOCKER_COMPOSE="false"
export RUN_STATIC_CHECKS="true"
export RUN_BUILD_DOCS="false"
export STATIC_CHECK="${2}"
export EXTRA_STATIC_CHECK_OPTIONS=("--show-diff-on-failure")
export STATIC_CHECK_ALL_FILES="false"
shift 2 ;;
-F|--static-check-all-files)
export ENTER_ENVIRONMENT="false"
export RUN_TESTS="false"
export RUN_DOCKER_COMPOSE="false"
export RUN_STATIC_CHECKS="true"
export RUN_BUILD_DOCS="false"
export STATIC_CHECK="${2}"
export STATIC_CHECK_ALL_FILES="true"
export EXTRA_STATIC_CHECK_OPTIONS=("--all-files" "--show-diff-on-failure")
shift 2 ;;
-O|--build-docs)
export ENTER_ENVIRONMENT="false"
export RUN_TESTS="false"
export RUN_DOCKER_COMPOSE="false"
export RUN_STATIC_CHECKS="false"
export RUN_BUILD_DOCS="true"
shift 1 ;;
--)
shift ;
break ;;
*)
usage
echo >&2
echo >&2 "ERROR: Unknown argument ${1}"
echo >&2
exit 1
;;
esac
done
echo
printf '=%.0s' $(seq "${SEPARATOR_WIDTH}")
echo
CMDNAME="$(basename -- "$0")"
# Cleans up the answer that was given last time, whether to force/
cleanup_last_force_answer
export ENV="${ENV:=$(read_from_file ENV)}"
export BACKEND="${BACKEND:=$(read_from_file BACKEND)}"
export KUBERNETES_VERSION="${KUBERNETES_VERSION:=$(read_from_file KUBERNETES_VERSION)}"
export KUBERNETES_MODE="${KUBERNETES_MODE:=$(read_from_file KUBERNETES_MODE)}"
# Here you read DockerHub user/account that you use
# You can populate your own images in DockerHub this way and work with the,
# You can override it with "-d" option and it will be stored in .build directory
export DOCKERHUB_USER="${DOCKERHUB_USER:=$(read_from_file DOCKERHUB_USER)}"
export DOCKERHUB_USER="${DOCKERHUB_USER:=${_BREEZE_DEFAULT_DOCKERHUB_USER}}"
# Here you read DockerHub repo that you use
# You can populate your own images in DockerHub this way and work with them
# You can override it with "-d" option and it will be stored in .build directory
export DOCKERHUB_REPO="${DOCKERHUB_REPO:=$(read_from_file DOCKERHUB_REPO)}"
export DOCKERHUB_REPO="${DOCKERHUB_REPO:=${_BREEZE_DEFAULT_DOCKERHUB_REPO}}"
# Default environment for tests
export ENV=${ENV:-${_BREEZE_DEFAULT_ENV}}
# Default backend for tests
export BACKEND=${BACKEND:-${_BREEZE_DEFAULT_BACKEND}}
# Default version of Kubernetes to use
export KUBERNETES_VERSION=${KUBERNETES_VERSION:=${_BREEZE_DEFAULT_KUBERNETES_VERSION}}
# Default mode of Kubernetes to use
export KUBERNETES_MODE=${KUBERNETES_MODE:=${_BREEZE_DEFAULT_KUBERNETES_MODE}}
#################### Check python version ##########################################
if [[ ${_BREEZE_ALLOWED_PYTHON_VERSIONS:=} != *" ${PYTHON_VERSION} "* ]]; then
echo >&2
echo >&2 "ERROR: Allowed Python versions: [${_BREEZE_ALLOWED_PYTHON_VERSIONS}]. Is: '${PYTHON_VERSION}'."
echo >&2
echo >&2 "Switch to virtualenv with the supported python version or specify python with --python flag."
echo >&2
exit 1
fi
#################### Check environments ##########################################
if [[ ${_BREEZE_ALLOWED_ENVS:=} != *" ${ENV} "* ]]; then
echo >&2
echo >&2 "ERROR: Allowed environments are [${_BREEZE_ALLOWED_ENVS}]. Used: '${ENV}'"
echo >&2
exit 1
fi
#################### Check backends ##########################################
if [[ ${_BREEZE_ALLOWED_BACKENDS:=} != *" ${BACKEND} "* ]]; then
echo >&2
echo >&2 "ERROR: Allowed backends are [${_BREEZE_ALLOWED_BACKENDS}]. Used: '${BACKEND}'"
echo >&2
exit 1
fi
#################### Check environments ##########################################
if [[ ${_BREEZE_ALLOWED_KUBERNETES_VERSIONS} != *" ${KUBERNETES_VERSION} "* ]]; then
echo >&2
echo >&2 "ERROR: Allowed kubernetes versions" \
"are [${_BREEZE_ALLOWED_KUBERNETES_VERSIONS}]. Used: '${KUBERNETES_VERSION}'"
echo >&2
exit 1
fi
#################### Check environments ##########################################
if [[ ${_BREEZE_ALLOWED_KUBERNETES_MODES} != *" ${KUBERNETES_MODE} "* ]]; then
echo >&2
echo >&2 "ERROR: Allowed kubernetes modes" \
"are [${_BREEZE_ALLOWED_KUBERNETES_MODES}]. Used: '${KUBERNETES_MODE}'"
echo >&2
exit 1
fi
# Those files are mounted into container when run locally
# .bash_history is preserved and you can modify .bash_aliases and .inputrc
# according to your liking
touch "${MY_DIR}/.bash_history"
touch "${MY_DIR}/.bash_aliases"
touch "${MY_DIR}/.inputrc"
save_to_file BACKEND
save_to_file ENV
save_to_file KUBERNETES_VERSION
save_to_file KUBERNETES_MODE
save_to_file PYTHON_VERSION
save_to_file DOCKERHUB_USER
save_to_file DOCKERHUB_REPO
#################### Cleanup image if requested ########################################
if [[ "${CLEANUP_IMAGES}" == "true" ]]; then
export AIRFLOW_CONTAINER_CLEANUP_IMAGES=true
"${MY_DIR}/scripts/ci/local_ci_cleanup.sh"
exit 0
fi
#################### Initializes local virtualenv ########################################
if [[ ${INITIALIZE_LOCAL_VIRTUALENV} == "true" ]]; then
# Check if we are in virtualenv
set +e
echo -e "import sys\nif not hasattr(sys,'real_prefix'):\n sys.exit(1)" | "python${PYTHON_VERSION}"
RES=$?
set -e
if [[ ${RES} != "0" ]]; then
echo >&2
echo >&2 "ERROR: Initializing local virtualenv only works when you have virtualenv activated"
echo >&2
echo >&2 "Please enter your local virtualenv before (for example using 'workon') "
echo >&2
exit 1
else
# If no Airflow Home defined - fallback to ${HOME}/airflow
AIRFLOW_HOME_DIR=${AIRFLOW_HOME:=${HOME}/airflow}
echo
echo "Initializing the virtualenv: $(command -v python)!"
echo
echo "This will wipe out ${AIRFLOW_HOME_DIR} and reset all the databases!"
echo
"${MY_DIR}/confirm" "Proceeding with the initialization"
echo
pushd "${MY_DIR}"
SYSTEM=$(uname -s)
echo "#######################################################################"
echo " If you have trouble installing all dependencies you might need to run:"
echo
if [[ ${SYSTEM} == "Darwin" ]]; then
echo " brew install sqlite mysql postgresql"
else
echo " sudo apt-get install openssl sqlite libmysqlclient-dev libmysqld-dev postgresql --confirm"
fi
echo
echo "#######################################################################"
pip install -e ".[devel]"
popd
echo
echo "Wiping and recreating ${AIRFLOW_HOME_DIR}"
echo
rm -rvf "${AIRFLOW_HOME_DIR}"
mkdir -p "${AIRFLOW_HOME_DIR}"
echo
echo "Resetting AIRFLOW sqlite database"
echo
unset AIRFLOW__CORE__UNIT_TEST_MODE
airflow db reset -y
echo
echo "Resetting AIRFLOW sqlite unit test database"
echo
export AIRFLOW__CORE__UNIT_TEST_MODE=True
airflow db reset -y
exit 0
fi
fi
#################### Sets up autocomplete for breeze commands ########################################
if [[ ${SETUP_AUTOCOMPLETE} == "true" ]]; then
echo
echo "Installing bash/zsh completion for local user"
echo "Note that completion for zsh is just limited to flags - without their values"
echo
set +e
grep ".bash_completion.d" "${HOME}/.bashrc" >/dev/null 2>&1
RES=$?
set -e
if [[ "${RES}" == "0" ]]; then
echo >&2
echo >&2 "ERROR: Bash completion already setup before."
echo >&2
exit 1
fi
"${MY_DIR}/confirm" "This will create ~/.bash_completion.d/ directory and modify ~/.bashrc and ~/.zshrc file"
echo
echo
mkdir -pv ~/.bash_completion.d
ln -sf "${MY_DIR}/breeze-complete" "${HOME}/.bash_completion.d/"
touch ~/.bashrc
cat >>~/.bashrc <<"EOF"
for BCFILE in ~/.bash_completion.d/* ; do
. ${BCFILE}
done
EOF
cat >>~/.zshrc <<"EOF"
autoload compinit && compinit
autoload bashcompinit && bashcompinit
source ~/.bash_completion.d/breeze-complete
EOF
if [[ "${OSTYPE}" == "darwin"* ]]; then
# For MacOS we have to handle the special case where terminal app DOES NOT run .bashrc by default
# But re-runs .bash_profile :(
# See https://scriptingosx.com/2017/04/about-bash_profile-and-bashrc-on-macos/
set +e
grep ".bashrc" "${HOME}/.bash_profile"
RES=$?
set -e
if [[ "${RES}" == "0" ]]; then
echo " Seems you already source .bashrc in your .bash_profile so not adding it."
else
"${MY_DIR}/confirm" "This will modify ~/.bash_profile and source .bashrc from it"
echo
echo
cat >>~/.bash_profile <<"EOF"
if [ -r ~/.bashrc ]; then
source ~/.bashrc
fi
EOF
fi
fi
echo
echo
echo "Breeze bash completion installed to ~/.bash_completion.d/breeze-complete"
echo
echo
echo "Please re-enter bash or run '. ~/.bash_completion.d/breeze-complete'"
echo
exit 0
fi
MAIN_DOCKER_COMPOSE_FILE=${SCRIPTS_CI_DIR}/docker-compose.yml
KUBERNETES_DOCKER_COMPOSE_FILE=${SCRIPTS_CI_DIR}/docker-compose-kubernetes.yml
BACKEND_DOCKER_COMPOSE_FILE=${SCRIPTS_CI_DIR}/docker-compose-${BACKEND}.yml
LOCAL_DOCKER_COMPOSE_FILE=${SCRIPTS_CI_DIR}/docker-compose-local.yml
COMPOSE_FILE=${MAIN_DOCKER_COMPOSE_FILE}:${BACKEND_DOCKER_COMPOSE_FILE}
if [[ "${ENV}" == "kubernetes" ]]; then
COMPOSE_FILE=${COMPOSE_FILE}:${KUBERNETES_DOCKER_COMPOSE_FILE}
fi
if [[ "${SKIP_MOUNTING_LOCAL_SOURCES}" != "true" ]]; then
COMPOSE_FILE=${COMPOSE_FILE}:${LOCAL_DOCKER_COMPOSE_FILE}
fi
export COMPOSE_FILE
CI_ENTRYPOINT_FILE="/opt/airflow/scripts/ci/in_container/entrypoint_ci.sh"
DC_RUN_COMMAND="run --service-ports --rm airflow-testing \"${CI_ENTRYPOINT_FILE} "
DC_RUN_COMMAND_ONLY_AT="run --no-deps --service-ports --rm airflow-testing \"${CI_ENTRYPOINT_FILE} "
LAST_DC_RUN_FILE="cmd_run"
LAST_DC_RUN_ONLY_AT_FILE="cmd_only_at_run"
LAST_DC_TEST_FILE="test_run"
LAST_DC_FILE="dc"
# Prepare script for "run command"
prepare_command_file "${BUILD_CACHE_DIR}/${LAST_DC_RUN_FILE}" "${DC_RUN_COMMAND}" "false" '*'
# Prepare script for "run command"
prepare_command_file "${BUILD_CACHE_DIR}/${LAST_DC_RUN_ONLY_AT_FILE}" "${DC_RUN_COMMAND_ONLY_AT}" "false" '*'
# Prepare script for "run test"
prepare_command_file "${BUILD_CACHE_DIR}/${LAST_DC_TEST_FILE}" "${DC_RUN_COMMAND}" "true" '*'
# Prepare script for "run docker compose command"
prepare_command_file "${BUILD_CACHE_DIR}/${LAST_DC_FILE}" '"' "false"
rebuild_ci_image_if_needed
rebuild_ci_slim_image_if_needed
rebuild_checklicence_image_if_needed
export AIRFLOW_CONTAINER_DOCKER_IMAGE=\
${DOCKERHUB_USER}/${DOCKERHUB_REPO}:${AIRFLOW_CONTAINER_BRANCH_NAME}-python${PYTHON_VERSION}-ci
printf '=%.0s' $(seq "${SEPARATOR_WIDTH}")
if [[ "${TEST_TARGET}" == "." ]]; then
TEST_TARGET=""
fi
print_badge
function print_line {
printf '#%.0s' $(seq "${SEPARATOR_WIDTH}")
}
if [[ ! -f ${SUPPRESS_CHEATSHEET_FILE} ]]; then
echo
echo
print_line
echo
echo " Airflow Breeze CHEATSHEET"
echo
print_line
echo
echo
print_line
echo
echo " Quick scripts:"
echo " * Enter the full environment : ${BUILD_CACHE_DIR}/${LAST_DC_RUN_FILE}"
echo " * Run command in full environment : ${BUILD_CACHE_DIR}/${LAST_DC_RUN_FILE} "\
"[command with args] [bash options]"
echo " * Run command airflow-testing only : ${BUILD_CACHE_DIR}/${LAST_DC_RUN_ONLY_AT_FILE} "\
"[command with args] [bash options]"
echo " * Run tests in the full environment : ${BUILD_CACHE_DIR}/${LAST_DC_TEST_FILE} "\
"[test target] [nosetest options]"
echo " * Run Docker compose command : ${BUILD_CACHE_DIR}/${LAST_DC_FILE} "\
"[docker compose command] [docker-compose options]"
echo
set +e
if ! command -v breeze; then
print_line
echo
echo " Adding breeze to your path:"
echo " When you exit the environment, you can add sources of airflow to the path - you can"
echo " run breeze or the scripts above from any directory by calling 'breeze' commands directly"
echo
echo " export PATH=\${PATH}:\"${MY_DIR}\""
echo
fi
set -e
print_line
echo
echo " Port forwarding:"
echo
echo " Ports are forwarded to the running docker containers for webserver and database"
echo " * ${WEBSERVER_HOST_PORT} -> forwarded to airflow webserver -> airflow-testing:8080"
echo " * ${POSTGRES_HOST_PORT} -> forwarded to postgres database -> postgres:5432"
echo " * ${MYSQL_HOST_PORT} -> forwarded to mysql database -> mysql:3306"
echo
echo " Here are links to those services that you can use on host:"
echo " * Webserver: http://127.0.0.1:28080"
echo " * Postgres: jdbc:postgresql://127.0.0.1:25433/airflow?user=postgres&password=airflow"
echo " * Mysql: jdbc:mysql://localhost:23306/airflow?user=root"
echo
else
echo
fi
# shellcheck disable=SC2034 # Unused variables left for comp_breeze usage
if ! typeset -f "_comp_breeze" > /dev/null; then
print_line
echo
echo " You can setup autocomplete by running '$0 --setup-autocomplete'"
echo
echo
fi
print_line
echo
echo " You can toggle ascii/cheatsheet by adding this flag:"
echo " * --toggle-suppress-cheatsheet"
echo " * --toggle-suppress-asciiart"
echo
print_line
echo
echo
echo
echo
if [[ ${ENTER_ENVIRONMENT} == "true" ]]; then
if [[ ${RUN_TESTS} == "true" ]]; then
"${BUILD_CACHE_DIR}/${LAST_DC_TEST_FILE}" "\"${TEST_TARGET}\"" "$@"
elif [[ ${RUN_DOCKER_COMPOSE} == "true" ]]; then
"${BUILD_CACHE_DIR}/${LAST_DC_FILE}" "${DOCKER_COMPOSE_COMMAND}" "$@"
elif [[ ${RUN_IN_BASH} == "true" ]]; then
"${BUILD_CACHE_DIR}/${LAST_DC_RUN_FILE}" "${RUN_COMMAND}" "$@"
else
"${BUILD_CACHE_DIR}/${LAST_DC_RUN_FILE}"
fi
else
if [[ ${RUN_STATIC_CHECKS} == "true" ]]; then
echo
echo "Making sure pre-commit is installed"
echo
if command -v pip3 >/dev/null; then
PIP_BIN=pip3
elif command -v pip >/dev/null; then
PIP_BIN=pip
else
echo >&2
echo >&2 "ERROR: You need to have pip or pip3 in your PATH"
echo >&2
S
exit 1
fi
"${PIP_BIN}" install --upgrade pre-commit >/dev/null 2>&1
# Add ~/.local/bin to the path in case pip is run outside of virtualenv
export PATH="${PATH}":~/.local/bin
if [[ ${STATIC_CHECK} == "all" ]]; then
echo
echo "Running: pre-commit run" "${EXTRA_STATIC_CHECK_OPTIONS[@]}" "$@"
echo
pre-commit run "${EXTRA_STATIC_CHECK_OPTIONS[@]}" "$@"
else
echo
echo "Running: pre-commit run" "${STATIC_CHECK}" "${EXTRA_STATIC_CHECK_OPTIONS[@]}" "$@"
echo
pre-commit run "${STATIC_CHECK}" "${EXTRA_STATIC_CHECK_OPTIONS[@]}" "$@"
fi
elif [[ ${RUN_BUILD_DOCS} == "true" ]]; then
run_docs
fi
fi
script_end