1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/bin/bash
# Common functions and variables for run-kontrol.sh and make-summary-deployment.sh
notif() { echo "== $0: $*" >&2 ; }
# usage function for the run-kontrol.sh script
usage_run_kontrol() {
echo "Usage: $0 [-h|--help] [container|local|dev] [script|tests]" 1>&2
echo "" 1>&2
echo " -h, --help Display this help message." 1>&2
echo "" 1>&2
echo "Execution modes:"
echo " container Run in docker container. Reproduce CI execution. (Default)" 1>&2
echo " local Run locally, enforces registered versions.json version for better reproducibility. (Recommended)" 1>&2
echo " dev Run locally, does NOT enforce registered version. (Useful for developing with new versions and features)" 1>&2
echo "" 1>&2
echo "Tests executed:"
echo " script Execute the tests recorded in run-kontrol.sh" 1>&2
echo " tests Execute the tests provided as arguments" 1>&2
exit 0
}
# usage function for the make-summary-deployment.sh script
usage_make_summary() {
echo "Usage: $0 [-h|--help] [container|local|dev]" 1>&2
echo "" 1>&2
echo " -h, --help Display this help message." 1>&2
echo "" 1>&2
echo "Execution modes:"
echo " container Run in docker container. Reproduce CI execution. (Default)" 1>&2
echo " local Run locally, enforces registered versions.json version for better reproducibility. (Recommended)" 1>&2
echo " dev Run locally, does NOT enforce registered version. (Useful for developing with new versions and features)" 1>&2
exit 0
}
# Set Run Directory <root>/packages/contracts-bedrock
WORKSPACE_DIR=$( cd "$SCRIPT_HOME/../../.." >/dev/null 2>&1 && pwd )
pushd "$WORKSPACE_DIR" > /dev/null || exit
# Variables
export KONTROL_FP_DEPLOYMENT="${KONTROL_FP_DEPLOYMENT:-false}"
export CONTAINER_NAME=kontrol-tests
if [ "$KONTROL_FP_DEPLOYMENT" = true ]; then
export CONTAINER_NAME=kontrol-fp-tests
fi
KONTROLRC=$(jq -r .kontrol < "$WORKSPACE_DIR/../../versions.json")
export KONTROL_RELEASE=$KONTROLRC
export LOCAL=false
export SCRIPT_TESTS=false
SCRIPT_OPTION=false
export CUSTOM_TESTS=0 # Store the position where custom tests start, interpreting 0 as no tests
CUSTOM_OPTION=0
export RUN_KONTROL=false # true if any functions are called from run-kontrol.sh
# General usage function, which discerns from which script is being called and displays the appropriate message
usage() {
if [ "$RUN_KONTROL" = "true" ]; then
usage_run_kontrol
else
usage_make_summary
fi
}
# Argument Parsing
# The logic behind argument parsing is the following (in order):
# - Execution mode argument: container (or empty), local, dev
# - Tests arguments (first if execution mode empty): script, specific test names
parse_args() {
if [ $# -eq 0 ]; then
export LOCAL=false
export SCRIPT_TESTS=false
export CUSTOM_TESTS=0
# `script` argument caps the total possible arguments to its position
elif { [ $# -gt 1 ] && [ "$1" == "script" ]; } || { [ $# -gt 2 ] && [ "$2" == "script" ]; }; then
usage
elif [ $# -eq 1 ]; then
SCRIPT_OPTION=false
CUSTOM_OPTION=0
parse_first_arg "$1"
elif [ $# -eq 2 ] && [ "$2" == "script" ]; then
if [ "$1" != "container" ] && [ "$1" != "local" ] && [ "$1" != "dev" ]; then
notif "Invalid first argument. Must be \`container\`, \`local\` or \`dev\`"
exit 1
fi
SCRIPT_OPTION=true
CUSTOM_OPTION=0
parse_first_arg "$1"
else
SCRIPT_OPTION=false
CUSTOM_OPTION=2
parse_first_arg "$1"
fi
}
# Parse the first argument passed to `run-kontrol.sh`
parse_first_arg() {
if [ "$1" == "container" ]; then
notif "Running in docker container (DEFAULT)"
export LOCAL=false
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=$CUSTOM_OPTION
elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
usage
elif [ "$1" == "local" ]; then
notif "Running with LOCAL install, .kontrolrc CI version ENFORCED"
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=$CUSTOM_OPTION
check_kontrol_version
elif [ "$1" == "dev" ]; then
notif "Running with LOCAL install, IGNORING .kontrolrc version"
export LOCAL=true
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=$CUSTOM_OPTION
elif [ "$1" == "script" ]; then
notif "Running in docker container (DEFAULT)"
export LOCAL=false
NEGATED_SCRIPT_TESTS=$([[ "${SCRIPT_OPTION}" == "true" ]] && echo false || echo true)
export SCRIPT_TESTS=$NEGATED_SCRIPT_TESTS
export CUSTOM_TESTS=$CUSTOM_OPTION
else
notif "Running in docker container (DEFAULT)"
export LOCAL=false
export SCRIPT_TESTS=$SCRIPT_OPTION
export CUSTOM_TESTS=1 # Store the position where custom tests start
fi
}
check_kontrol_version() {
if [ "$(kontrol version | awk -F': ' '{print$2}')" == "$KONTROLRC" ]; then
notif "Kontrol version matches $KONTROLRC"
export LOCAL=true
else
notif "Kontrol version does NOT match $KONTROLRC"
notif "Please run 'kup install kontrol --version v$KONTROLRC'"
exit 1
fi
}
conditionally_start_docker() {
if [ "$LOCAL" == false ]; then
# Is old docker container running?
if [ "$(docker ps -q -f name="$CONTAINER_NAME")" ]; then
# Stop old docker container
notif "Stopping old docker container"
clean_docker
fi
start_docker
fi
}
start_docker () {
docker run \
--name "$CONTAINER_NAME" \
--rm \
--interactive \
--detach \
--env FOUNDRY_PROFILE="$FOUNDRY_PROFILE" \
--workdir /home/user/workspace \
runtimeverificationinc/kontrol:ubuntu-jammy-"$KONTROL_RELEASE"
copy_to_docker
}
copy_to_docker() {
# Copy test content to container. We need to avoid copying node_modules because
# it results in the below error, so we copy the workspace to a temp directory
# and then copy it to the container.
# Error response from daemon: invalid symlink "/home/user/workspace/node_modules/@typescript-eslint/eslint-plugin" -> "../../../../node_modules/.pnpm/@typescript-eslint+eslint-plugin@6.19.1_@typescript-eslint+parser@6.19.1_eslint@8.56.0_typescript@5.3.3/node_modules/@typescript-eslint/eslint-plugin"
# Even though we use a bind mount, we still need to copy the files to the
# container because we are running Docker on a remote host.
if [ "$LOCAL" == false ]; then
TMP_DIR=$(mktemp -d)
cp -r "$WORKSPACE_DIR/." "$TMP_DIR"
rm -rf "$TMP_DIR/node_modules"
docker cp --follow-link "$TMP_DIR/." $CONTAINER_NAME:/home/user/workspace
rm -rf "$TMP_DIR"
docker exec --user root "$CONTAINER_NAME" chown -R user:user /home/user
fi
}
clean_docker(){
if [ "$LOCAL" = false ]; then
notif "Cleaning Docker Container"
docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true
docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true
sleep 2 # Give time for system to clean up container
else
notif "Not Running in Container. Done."
fi
}
docker_exec () {
docker exec --user user --workdir /home/user/workspace $CONTAINER_NAME "${@}"
}
run () {
if [ "$LOCAL" = true ]; then
notif "Running local"
# shellcheck disable=SC2086
"${@}"
else
notif "Running in docker"
docker_exec "${@}"
fi
return $? # Return the exit code of the command
}