-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add image building and tagged testing to CI #350
base: main
Are you sure you want to change the base?
Changes from 11 commits
96bbc24
42683d3
36facda
79cb6d6
f9d266f
6e5122d
49536db
bb69c94
db82883
fe3ad44
1783048
6122bde
2ed3ffa
82fb8e6
1666e46
fdd90b9
bbbb1c1
f1247c7
67f958f
cab5ebb
bc6d094
4b34844
2cb85e1
6091289
fed8b44
3e0c027
a9eba5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
#!/bin/bash | ||
|
||
TAG="$1" | ||
[[ -z "${TAG}" ]] && TAG="integration_tests" | ||
|
||
NOW="$(date +"%Y-%m-%d_%H_%M_%S")" | ||
ARCH="amd64" | ||
[[ "$(uname -m)" = "arm64" ]] && ARCH="arm64" | ||
|
||
RUNDIR="apps/integration/runs/${NOW}" | ||
GIT_LOGFILE="${RUNDIR}/git.log" | ||
DOCKER_LOGFILE="${RUNDIR}/docker.log" | ||
POETRY_LOGFILE="${RUNDIR}/poetry.log" | ||
PYTEST_LOGFILE="${RUNDIR}/pytest.log" | ||
QUERY_LOGFILE="${RUNDIR}/test_queries.log" | ||
|
||
main() { | ||
[[ ! -d ".git" ]] && die "Please run this script from sycamore root!" | ||
mkdir -p "${RUNDIR}" | ||
echo "Building/testing tag ${TAG}" >&2 | ||
echo "Get the newest git commits" >&2 | ||
if [[ checkout_main_if_new ]]; then | ||
echo "Changes detected. Running Tests" >&2 | ||
poetry install --no-root > "${POETRY_LOGFILE}" 2>&1 \ | ||
&& build_images > "${DOCKER_LOGFILE}" 2>&1 \ | ||
&& runtests > "${PYTEST_LOGFILE}" 2>&1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd indent these one more level to reduce confusion. |
||
local passed_tests=$? | ||
push_images >> "${DOCKER_LOGFILE}" 2>&1 | ||
handle_outputs $passed_tests | ||
else | ||
echo "No changes detected. Skipping integration tests" >&2 | ||
fi | ||
} | ||
|
||
error() { | ||
echo "ERROR: $@" >&2 | ||
} | ||
|
||
checkout_main_if_new() { | ||
old_sha="$(git rev-parse HEAD)" | ||
git fetch origin main > "${GIT_LOGFILE}" 2>&1 | ||
new_sha="$(git rev-parse FETCH_HEAD)" | ||
if [[ "${old_sha}" != "${new_sha}" ]]; then | ||
[[ -z $(git status --porcelain) ]] \ | ||
|| { echo "Working tree not clean" > "${GIT_LOGFILE}" && return 1; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does the semicolon do at the end? I see it a lot in this file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure, I copied it from the stack overflow I found on grouping. Although I guess I could clean this up a lot by turning the -z into a -n and the || into && and ungrouping it. echo > file will never fail, right? |
||
git pull --rebase origin main >> "${GIT_LOGFILE}" 2>&1 | ||
return 0 | ||
else | ||
return 1 | ||
fi | ||
} | ||
|
||
build_images() { | ||
echo "Building all images" >&2 | ||
docker-build-hub apps/crawler/crawler/http/Dockerfile \ | ||
&& docker-build-hub apps/crawler/crawler/s3/Dockerfile \ | ||
&& docker-build-hub apps/importer/Dockerfile.buildx \ | ||
&& docker-build-hub apps/opensearch/Dockerfile \ | ||
&& docker-build-hub apps/jupyter/Dockerfile.buildx --build-arg=TAG="${TAG}" \ | ||
&& docker-build-hub apps/demo-ui/Dockerfile.buildx \ | ||
&& docker-build-hub apps/remote-processor-service/Dockerfile.buildx \ | ||
&& return 0 | ||
return 1 | ||
} | ||
|
||
handle_outputs() { | ||
echo "Handling test outputs" >&2 | ||
local passed_tests="$1" | ||
mv test-output.log "${QUERY_LOGFILE}" | ||
[[ ${passed_tests} = 0 ]] && touch "${RUNDIR}/passed" | ||
[[ ${passed_tests} != 0 ]] && touch "${RUNDIR}/failed" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if...else would seem more clear here. |
||
aws s3 cp -r "${RUNDIR}" "s3://sycamore-ci/${ARCH}" | ||
} | ||
|
||
push_images() { | ||
echo "Pushing tested images to dockerhub" >&2 | ||
docker-push-hub apps/crawler/crawler/http/Dockerfile \ | ||
&& docker-push-hub apps/crawler/crawler/s3/Dockerfile \ | ||
&& docker-push-hub apps/importer/Dockerfile.buildx \ | ||
&& docker-push-hub apps/opensearch/Dockerfile \ | ||
&& docker-push-hub apps/jupyter/Dockerfile.buildx \ | ||
&& docker-push-hub apps/demo-ui/Dockerfile.buildx \ | ||
&& docker-push-hub apps/remote-processor-service/Dockerfile.buildx \ | ||
&& return 0 | ||
return 1 | ||
} | ||
|
||
runtests() { | ||
docker system prune -f --volumes | ||
docker compose up reset | ||
poetry run pytest apps/integration/ -p integration.conftest --noconftest --docker-tag "${TAG}" | ||
# this is a complicated command, so: | ||
# -p integration.conftest - load conftest with plugins, to capture the custom command line arg (--docker-tag) | ||
# --noconftest - don't load conftest at pytest runtime; it's already loaded | ||
# --docker-tag - specify tag of containers to test | ||
return $? | ||
} | ||
|
||
docker-build-hub() { | ||
local docker_file="$1" | ||
[[ -n "${docker_file}" ]] || { error "missing ${docker_file}" && return 1;} | ||
local repo_name="$(_docker-repo-name "${docker_file}")" | ||
[[ -n "${repo_name}" ]] || { error "empty repo name" && return 1;} | ||
shift | ||
|
||
echo | ||
echo "Building in sycamore and pushing to docker hub with repo name '${repo_name}'" | ||
docker buildx build "$(_docker-build-args)" -t "${repo_name}:${TAG}" -f "${docker_file}" \ | ||
--cache-to type=registry,ref="${repo_name}:build-cache",mode=max \ | ||
--cache-from type=registry,ref="${repo_name}:build-cache" \ | ||
"$@" --load . || { error "buildx failed" && return 1;} | ||
echo "Successfully built using docker file $docker_file" | ||
} | ||
|
||
docker-push-hub() { | ||
local docker_file="$1" | ||
[[ -n "${docker_file}" ]] || { error "missing ${docker_file}" && return 1;} | ||
local repo_name="$(_docker-repo-name "${docker_file}")" | ||
[[ -n "${repo_name}" ]] || { error "empty repo name" && return 1;} | ||
|
||
echo | ||
echo "Pushing image to docker hub for repo '${repo_name}" | ||
docker push "${repo_name}:${TAG}" || { error "docker push failed" && return 1;} | ||
echo "Successfully pushed image previously built from dockerfile ${docker_file}" | ||
} | ||
|
||
_docker-repo-name() { | ||
local docker_file="$1" | ||
echo "Finding repo name in: ${docker_file}" >&2 | ||
local repo_name="$(grep '^# Repo name: ' "${docker_file}" | awk '{print $4}')" | ||
if (( $(wc -w <<< ${repo_name}) != 1 )); then | ||
echo "Unable to find repo name in ${docker_file}" 1>&2 | ||
exit 1 | ||
fi | ||
echo "${repo_name}" | ||
} | ||
|
||
_docker-build-args() { | ||
local branch="$(git branch --show-current)" | ||
local rev="$(git rev-parse --short HEAD)" | ||
local date="$(git show -s --format=%ci HEAD | sed -e 's/ /_/g')" | ||
local diff=unknown | ||
if [[ -z $(git status --porcelain) ]]; then | ||
diff=clean | ||
else | ||
diff="pending_changes_$(git diff HEAD | shasum | awk '{print $1}')" | ||
fi | ||
echo "--build-arg=GIT_BRANCH=${branch} --build-arg=GIT_COMMIT=${rev}--${date} --build-arg=GIT_DIFF=${diff}" | ||
} | ||
|
||
main |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The square brackets here are superfluous. Nowadays, this stuff is built-in for speed, but check out
/bin
on a unixy box and you'll see an executable called[
. That's a pretty big clue about how this stuff works. It turns out that[
is just like/bin/test
; they share a man page, which is worth skimming. The other important thing to note is the;
which terminates the conditional command, which can be a pipeline. Blah blah blah...