Skip to content
This repository was archived by the owner on Mar 21, 2025. It is now read-only.

Commit 6db04a4

Browse files
authored
Merge pull request #710 from opendevstack/feature/build-cache-simplification
Feature/build task overhaul
2 parents 6d2f321 + 830c3d6 commit 6db04a4

35 files changed

+521
-385
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ listed in the changelog.
2323

2424
- SonarQube doesn't scan FE-related code ([#716](https://github.com/opendevstack/ods-pipeline/issues/716))
2525

26+
### Changed
27+
28+
- Build tasks streamlining and avoidance of file copies (#678 fixed by [#710](https://github.com/opendevstack/ods-pipeline/pull/710)). This is an incompatible change. Build tasks were adjusted to (mostly) no longer copy build files in a dedicated location. Instead one should adjust the Dockerfile (or other downstream tasks) to directly consume the build outputs from their natural locations. In addition build task skipping now supports parameter `build-extra-inputs`. The package-image task `dockerfile` and `docker-dir` parameters have been changed to assume that the docker context and file are at the repository root. See the PR for further information and the issue for more context.
29+
2630
## [0.13.2] - 2023-07-18
2731

2832
### Fixed

build/package/scripts/build-npm.sh

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,19 @@ copyLintReport() {
1919
cp eslint-report.txt "${tmp_artifacts_dir}/lint-reports/${ARTIFACT_PREFIX}report.txt"
2020
}
2121

22-
# the copy commands are based on GNU cp tools
23-
# On a mac `brew install coreutils` gives `g` prefixed cmd line tools such as gcp
24-
# to use these define env variable GNU_CP=gcp before invoking this script.
25-
CP="${GNU_CP:-cp}"
26-
BUILD_DIR="dist"
27-
OUTPUT_DIR="docker"
2822
WORKING_DIR="."
2923
ARTIFACT_PREFIX=""
3024
DEBUG="${DEBUG:-false}"
31-
COPY_NODE_MODULES="false"
3225

3326
while [ "$#" -gt 0 ]; do
3427
case $1 in
3528

3629
--working-dir) WORKING_DIR="$2"; shift;;
3730
--working-dir=*) WORKING_DIR="${1#*=}";;
3831

39-
--output-dir) OUTPUT_DIR="$2"; shift;;
40-
--output-dir=*) OUTPUT_DIR="${1#*=}";;
41-
4232
--debug) DEBUG="$2"; shift;;
4333
--debug=*) DEBUG="${1#*=}";;
4434

45-
--build-dir) BUILD_DIR="$2"; shift;;
46-
--build-dir=*) BUILD_DIR="${1#*=}";;
47-
48-
--copy-node-modules) COPY_NODE_MODULES="$2"; shift;;
49-
--copy-node-modules=*) COPY_NODE_MODULES="${1#*=}";;
50-
5135
*) echo "Unknown parameter passed: $1"; exit 1;;
5236
esac; shift; done
5337

@@ -108,20 +92,6 @@ fi
10892

10993
echo "Building ..."
11094
npm run build
111-
# Copying most build output before testing so
112-
# that additional modules which may be installed by testing
113-
# is not included.
114-
# However copying package.json too early can confuse the tests.
115-
mkdir -p "${OUTPUT_DIR}"
116-
echo "Copying contents of ${BUILD_DIR} into ${OUTPUT_DIR}/dist ..."
117-
# see https://unix.stackexchange.com/questions/228597/how-to-copy-a-folder-recursively-in-an-idempotent-way-using-cp
118-
"$CP" -r "${BUILD_DIR}/." "${OUTPUT_DIR}/dist"
119-
120-
if [ "${COPY_NODE_MODULES}" = true ]; then
121-
echo "Copying node_modules to ${OUTPUT_DIR}/dist/node_modules ..."
122-
# note "${OUTPUT_DIR}/dist" exists now and node_modules name will be maintained.
123-
"$CP" -r node_modules "${OUTPUT_DIR}/dist"
124-
fi
12595

12696
echo "Testing ..."
12797
npm run test
@@ -135,15 +105,3 @@ cp build/coverage/clover.xml "${tmp_artifacts_dir}/code-coverage/${ARTIFACT_PREF
135105
cp build/coverage/coverage-final.json "${tmp_artifacts_dir}/code-coverage/${ARTIFACT_PREFIX}coverage-final.json"
136106

137107
cp build/coverage/lcov.info "${tmp_artifacts_dir}/code-coverage/${ARTIFACT_PREFIX}lcov.info"
138-
139-
# Doing this earlier can confuse jest.
140-
# test build_javascript_app_with_custom_build_directory fails with
141-
# jest-haste-map: Haste module naming collision: src
142-
# The following files share their name; please adjust your hasteImpl:
143-
# * <rootDir>/package.json
144-
# * <rootDir>/docker/package.json
145-
# No tests found, exiting with code 1
146-
# While one could demand to change the config of the test, there is no need
147-
# to copy this earlier
148-
echo "Copying package.json and package-lock.json to ${OUTPUT_DIR}/dist ..."
149-
cp package.json package-lock.json "${OUTPUT_DIR}/dist"

build/package/scripts/build-python.sh

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ urlencode() {
1313
done
1414
}
1515

16-
OUTPUT_DIR="docker"
1716
MAX_LINE_LENGTH="120"
1817
WORKING_DIR="."
1918
ARTIFACT_PREFIX=""
@@ -32,9 +31,6 @@ while [ "$#" -gt 0 ]; do
3231
--pre-test-script) PRE_TEST_SCRIPT="$2"; shift;;
3332
--pre-test-script=*) PRE_TEST_SCRIPT="${1#*=}";;
3433

35-
--output-dir) OUTPUT_DIR="$2"; shift;;
36-
--output-dir=*) OUTPUT_DIR="${1#*=}";;
37-
3834
--debug) DEBUG="$2"; shift;;
3935
--debug=*) DEBUG="${1#*=}";;
4036

@@ -89,7 +85,3 @@ mkdir -p "${tmp_artifacts_dir}/xunit-reports"
8985
cp report.xml "${tmp_artifacts_dir}/xunit-reports/${ARTIFACT_PREFIX}report.xml"
9086
mkdir -p "${tmp_artifacts_dir}/code-coverage"
9187
cp coverage.xml "${tmp_artifacts_dir}/code-coverage/${ARTIFACT_PREFIX}coverage.xml"
92-
93-
echo "Copying src and requirements.txt to ${OUTPUT_DIR}/app ..."
94-
cp -rv src "${OUTPUT_DIR}/app"
95-
cp -rv requirements.txt "${OUTPUT_DIR}/app"

build/package/scripts/cache-build.sh

Lines changed: 118 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,157 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
2+
# avoids ancient bash on macos
23
set -eu
34
# Copy build to cache
45

5-
66
# the copy commands are based on GNU cp tools
77
# On a mac `brew install coreutils` gives `g` prefixed cmd line tools such as gcp
88
# to use these define env variable GNU_CP=gcp before invoking this script.
99
CP="${GNU_CP:-cp}"
1010
LS="${GNU_LS:-ls}"
1111

12-
OUTPUT_DIR="docker"
13-
WORKING_DIR="."
14-
CACHE_BUILD_KEY=
15-
CACHE_LOCATION_USED_PATH=
16-
DEBUG="${DEBUG:-false}"
12+
join() {
13+
local IFS="$1"
14+
shift
15+
echo "$*"
16+
}
17+
18+
splitAtColon() {
19+
# colon is
20+
echo "$1" | tr ":" "\n"
21+
}
22+
# https://stackoverflow.com/a/918931
23+
24+
outputs_str=
25+
extra_inputs_str=
26+
declare -a outputs
27+
outputs=()
28+
declare -a inputs
29+
inputs=()
30+
working_dir="."
31+
cache_build="true"
32+
cache_build_key=
33+
cache_location_used_path=
34+
debug="${DEBUG:-false}"
35+
dry_run=false
36+
1737

1838
while [ "$#" -gt 0 ]; do
1939
case $1 in
2040

21-
--working-dir) WORKING_DIR="$2"; shift;;
22-
--working-dir=*) WORKING_DIR="${1#*=}";;
41+
--working-dir) working_dir="$2"; shift;;
42+
--working-dir=*) working_dir="${1#*=}";;
43+
44+
--cached-outputs) outputs_str="$2"; shift;;
45+
--cached-outputs=*) outputs_str="${1#*=}";;
46+
47+
--build-extra-inputs) extra_inputs_str="$2"; shift;;
48+
--build-extra-inputs=*) extra_inputs_str="${1#*=}";;
2349

24-
--output-dir) OUTPUT_DIR="$2"; shift;;
25-
--output-dir=*) OUTPUT_DIR="${1#*=}";;
50+
--cache-build) cache_build="$2"; shift;;
51+
--cache-build=*) cache_build="${1#*=}";;
2652

27-
--cache-build-key) CACHE_BUILD_KEY="$2"; shift;;
28-
--cache-build-key=*) CACHE_BUILD_KEY="${1#*=}";;
53+
--cache-build-key) cache_build_key="$2"; shift;;
54+
--cache-build-key=*) cache_build_key="${1#*=}";;
2955

30-
--cache-location-used-path) CACHE_LOCATION_USED_PATH="$2"; shift;;
31-
--cache-location-used-path=*) CACHE_LOCATION_USED_PATH="${1#*=}";;
56+
--cache-location-used-path) cache_location_used_path="$2"; shift;;
57+
--cache-location-used-path=*) cache_location_used_path="${1#*=}";;
3258

33-
--debug) DEBUG="$2"; shift;;
34-
--debug=*) DEBUG="${1#*=}";;
59+
--debug) debug="$2"; shift;;
60+
--debug=*) debug="${1#*=}";;
61+
62+
--dry-run) dry_run=true;;
3563

3664
*) echo "Unknown parameter passed: $1"; exit 1;;
3765
esac; shift; done
3866

39-
if [ -z "${CACHE_BUILD_KEY}" ]; then
67+
if [ -z "${cache_build_key}" ]; then
4068
echo "Param --cache-build-key is required."; exit 1;
41-
elif [ -z "${CACHE_LOCATION_USED_PATH}" ]; then
69+
elif [ -z "${cache_location_used_path}" ]; then
4270
echo "Param --cache-location-used-path is required."; exit 1;
4371
fi
4472

45-
CP_VERBOSITY_FLAGS=
46-
if [ "${DEBUG}" == "true" ]; then
73+
cp_verbosity_flags=
74+
if [ "${debug}" == "true" ]; then
4775
set -x
48-
CP_VERBOSITY_FLAGS="-v"
76+
cp_verbosity_flags="-v"
4977
fi
5078

51-
ROOT_DIR=$(pwd)
52-
53-
git_sha_working_dir=""
54-
if [ "${WORKING_DIR}" == "." ]; then
55-
git_sha_working_dir=$(git rev-parse "HEAD:")
56-
else
57-
git_sha_working_dir=$(git rev-parse "HEAD:$WORKING_DIR")
79+
if [ "$cache_build" != "true" ]; then
80+
echo "Build skipping is not enabled. Continuing with a regular build (cache_build==$cache_build)"
81+
exit 0
5882
fi
59-
cache_location_dir="$ROOT_DIR/.ods-cache/build-task/$CACHE_BUILD_KEY/$git_sha_working_dir"
6083

61-
if [ "${WORKING_DIR}" != "." ]; then
62-
cd "${WORKING_DIR}"
84+
# note leads to undefined variable if extra_inputs_str is empty on ancient bash
85+
IFS=":" read -r -a extra_inputs <<< "$extra_inputs_str"
86+
inputs=("$working_dir")
87+
for f in "${extra_inputs[@]}"; do
88+
inputs+=( "$f" )
89+
done
90+
91+
IFS=":" read -r -a outputs <<< "$outputs_str"
92+
93+
root_dir=$(pwd)
94+
95+
declare -a git_shas # relative to root
96+
for f in "${inputs[@]}"; do
97+
if [ "${f}" == "." ]; then
98+
git_shas+=( "$(git rev-parse --short "HEAD:")" )
99+
else
100+
git_shas+=( "$(git rev-parse --short "HEAD:$f")")
101+
fi
102+
done
103+
# shellcheck disable=SC2048,SC2086
104+
git_sha_combined=$(join "-" ${git_shas[*]})
105+
cache_location_dir="$root_dir/.ods-cache/build-task/$cache_build_key/$git_sha_combined"
106+
107+
if [ "${working_dir}" != "." ]; then
108+
cd "${working_dir}"
63109
fi
64110

65-
rm -rvf "$cache_location_dir" # should be empty as otherwise cache should be used.
66-
mkdir -p "$cache_location_dir"
111+
if [ "${dry_run}" == "true" ]; then
112+
echo "(skipping ensuring empty cache location dir at $cache_location_dir)"
113+
else
114+
rm -rvf "$cache_location_dir" # should be empty as otherwise cache should be used.
115+
mkdir -p "$cache_location_dir"
116+
fi
67117

68118
# Copying ods artifacts which are mostly reports (see artifacts.adoc)
69119
# TODO: consistent casing and naming across scripts regarding dir variables
120+
70121
cache_of_artifacts_dir="$cache_location_dir/artifacts"
71-
tmp_artifacts_dir="${ROOT_DIR}/.ods/tmp-artifacts"
72-
echo "Copying build artifacts to cache: $tmp_artifacts_dir -> $cache_of_artifacts_dir"
73-
mkdir -p "$cache_of_artifacts_dir"
74-
"$CP" -v -r "$tmp_artifacts_dir/." "$cache_of_artifacts_dir"
122+
tmp_artifacts_dir="${root_dir}/.ods/tmp-artifacts"
123+
echo "Copying ods build artifacts to cache: $tmp_artifacts_dir -> $cache_of_artifacts_dir"
124+
if [ "${dry_run}" == "true" ]; then
125+
echo "(skipping copying ods build artifacts)"
126+
else
127+
mkdir -p "$cache_of_artifacts_dir"
128+
"$CP" -v -r "$tmp_artifacts_dir/." "$cache_of_artifacts_dir"
129+
fi
75130

76131
# Copying build output
77-
cache_of_output_dir="$cache_location_dir/output"
78-
echo "Copying build output to cache: $OUTPUT_DIR to $cache_of_output_dir"
79-
mkdir -p "$cache_of_output_dir"
80-
start_time=$SECONDS
81-
"$CP" $CP_VERBOSITY_FLAGS -r "$OUTPUT_DIR/." "$cache_of_output_dir"
82-
elapsed=$(( SECONDS - start_time ))
83-
echo "Copying took $elapsed seconds"
84-
if [ "${DEBUG}" == "true" ]; then
85-
echo "-- ls OUTPUT IN CACHE -- "
86-
$LS -Ral "$cache_of_output_dir"
132+
for i in "${!outputs[@]}"; do
133+
cache_of_output_dir="$cache_location_dir/output/$i"
134+
output_dir="${outputs[$i]}"
135+
echo "Copying build output to cache: $output_dir to $cache_of_output_dir"
136+
if [ "${dry_run}" == "true" ]; then
137+
echo "(skipping copying build outputs)"
138+
else
139+
mkdir -p "$cache_of_output_dir"
140+
start_time=$SECONDS
141+
"$CP" $cp_verbosity_flags -r "$output_dir/." "$cache_of_output_dir"
142+
elapsed=$(( SECONDS - start_time ))
143+
echo "Copying took $elapsed seconds"
144+
if [ "${debug}" == "true" ]; then
145+
echo "-- ls OUTPUT IN CACHE -- "
146+
$LS -Ral "$cache_of_output_dir"
147+
fi
148+
fi
149+
done
150+
151+
if [ "${dry_run}" == "true" ]; then
152+
echo "(skipping saving $cache_location_dir in $cache_location_used_path)"
153+
echo "(skipping touch of $cache_location_dir/.ods-last-used-stamp"
154+
else
155+
echo "$cache_location_dir" > "$cache_location_used_path"
156+
touch "$cache_location_dir/.ods-last-used-stamp"
87157
fi
88-
89-
echo "$cache_location_dir" > "$CACHE_LOCATION_USED_PATH"
90-
touch "$cache_location_dir/.ods-last-used-stamp"

0 commit comments

Comments
 (0)