-
Notifications
You must be signed in to change notification settings - Fork 0
/
justfile
286 lines (222 loc) · 9.15 KB
/
justfile
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
set dotenv-load
# NOTES #
# - Prepend a statement with '!' to ignore errors in a line's exit code
@_default:
# list all the commands in this justfile
just --list -u
# VARIABLES #
default_cpu_arch := "x86_64"
newest_supported_otp := "26.0.2"
image_name := "arcanemachine/phoenix-todo-list"
# colors
color_error := "\\033[91m"
color_info := "\\033[96m"
color_success := "\\033[32m"
color_reset := "\\033[39m"
# SHORTCUTS #
@SHORTCUTS_____________________:
echo "This command doesn't do anything. It's used as a separator when listing the 'just' commands."
# run a postgres container
@postgres:
docker run --name postgres --rm -e POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} -p 5432:5432 -v postgres:/var/lib/postgresql/data postgres
# setup the project (elixir-fetch-dependencies + db-setup)
@setup: elixir-dependencies-fetch db-setup
# start a dev server (elixir-dependencies-fetch + db-migrate + server-dev-start-interactive)
@dev: elixir-dependencies-fetch db-migrate server-dev-start-interactive
# run all tests (test-elixir + test-js-unit + test-js-e2e)
@test:
just test-elixir
just test-js
just test-e2e
just _echo_success "All tests completed successfully"
# create a release (elixir-release-create)
@release: elixir-release-create
# start a prod server (server-prod-migrate + server-dev-start)
@prod: server-prod-migrate server-prod-start
# create a release and build a docker image (docker-build)
@build: docker-build
# push the image to docker hub (docker-push)
@push: docker-push
# almost one-liner to deploy a release (must still use ansible playbook to pull image on server) (test + release + build + push)
@deploy:
@./support/scripts/deploy
just _echo_success "done"
# COMMANDS #
@COMMANDS______________________:
echo "This command doesn't do anything. It's used as a separator when listing the 'just' commands."
# remove stale versions of static assets
@assets-prune:
echo "Pruning digested assets..."
@mix phx.digest.clean --all
# copy caddyfile, then validate and reload caddy [environment: dev|vagrant|staging|prod]
@caddyfile-copy-validate-reload environment:
echo "Copying the Caddyfile, then validating and reloading Caddy..."
@./support/scripts/caddyfile-copy-validate-reload {{ environment }}
# create the database with 'mix' and run initial migrations
@db-setup:
echo "Setting up the database..."
@mix ecto.setup
# create the database with 'mix'
@db-create:
echo "Creating the database..."
@mix ecto.create
# run database migrations with 'mix'
@db-migrate:
echo "Running database migrations..."
@mix ecto.migrate
# drop the database with 'mix'
@db-drop:
echo "Dropping the database..."
@mix ecto.drop
# reset the database with 'mix'
@db-reset:
echo "Resetting the database..."
@mix ecto.reset
# run an action on a postgres container [action (default: 'up')]
@docker-postgres action="up":
echo "Running the '{{ action }}' action on a Postgres container..."
./support/scripts/containers/compose--postgres {{ action }}
# build a docker image
@docker-build image_name=image_name:
echo "Building a Docker image '{{ image_name }}'..."
# build untagged image
@docker build -t {{ image_name }} .
# build an architecture-specific image
printf "\n\{{ color_info }}Building '$(uname -m)' image...{{ color_reset }}\n\n"
docker build -t "{{ image_name }}:$(uname -m)" .
# build versioned image
just _echo_info "Building a versioned image..."
docker build -t "{{ image_name }}:$(just version-project)-erlang-$(just version-otp)-$(uname -m)" .
# build 'latest' image to Docker Hub if we are on the 'x86_64' CPU architecture
if [ "$(uname -m)" = "{{ default_cpu_arch }}" ] && \
[ "$(just version-otp)" = "{{ newest_supported_otp }}" ]; then \
just _echo_info "Building the 'latest' image on Docker Hub since we're using the default CPU architecture ({{ default_cpu_arch }}) architecture and our latest supported version of OTP ({{ newest_supported_otp }})..."; \
docker build -t "{{ image_name }}:latest" .; \
fi
# push container image to Docker Hub
@docker-push image_name=image_name:
echo "Pushing image(s) to Docker Hub..."
# push architecture-specific image to Docker Hub
just _echo_info "Pushing architecture-specific image to Docker Hub..."
@docker push "{{ image_name }}:$(uname -m)"
# push versioned image to Docker Hub
just _echo_info "Pushing versioned image to Docker Hub..."
@docker push "{{ image_name }}:$(just version-project)-erlang-$(just version-otp)-$(uname -m)"
# push 'latest' image to Docker Hub if we are on the 'x86_64' CPU architecture
if [ "$(uname -m)" = "{{ default_cpu_arch }}" ] && [ "$(just version-otp)" = "{{ newest_supported_otp }}" ]; then \
just _echo_info "Updating the 'latest' image on Docker Hub since we're using the default CPU architecture ({{ default_cpu_arch }}) architecture and our latest supported version of OTP ({{ newest_supported_otp }})..."; \
docker push '{{ image_name }}:latest'; \
fi
# generate environment file [args (e.g.): --help]
@dotenv-generate args="":
echo "Generating new environment file..." > /dev/stderr
@./support/scripts/dotenv-generate {{ args }}
# fetch Elixir dependencies (`mix deps.get`)
@elixir-dependencies-fetch:
echo "Fetching Elixir dependencies..."
@mix deps.get
# get info about an Elixir Hex package
@elixir-package-info package_name:
echo "Checking for info about the '{{ package_name }}' Hex package..."
@mix hex.info {{ package_name }}
# update a specific Elixir Hex package
@elixir-package-update package_name:
echo "Updating Elixir Hex package '{{ package_name }}'..."
@mix deps.update {{ package_name }}
# update all Elixir dependencies
@elixir-package-update-all:
echo "Updating all Elixir dependencies..."
@mix deps.update --all
# check for Elixir Hex package updates
@elixir-package-update-list:
echo "Listing Elixir package updates..."
@! mix hex.outdated
# create a release
@elixir-release-create:
echo "Creating an Elixir release..."
@./support/scripts/elixir-release-create
# generate a grafana dashboard for a given prom_ex plugin [plugin_name (e.g.): application|beam|...]
@grafana-dashboard-generate plugin_name:
mix prom_ex.dashboard.export --dashboard {{ plugin_name }}.json --stdout
# install JS dependencies via 'npm'
@js-dependencies-install:
echo "Installing JS dependencies via 'npm'..."
cd assets && npm install
# run a basic loadtest with 'k6'
@loadtest-k6:
echo "Running a basic load test with 'k6'..."
@./support/scripts/loadtest-k6 --basic
# run a basic loadtest with 'wrk' (must have 'wrk' installed)
@loadtest-wrk:
echo "Running a basic load test with 'wrk'..."
@./support/scripts/loadtest-wrk
# generate an OpenAPI schema [format: json|yaml]
@openapi-schema-generate format="json":
echo "Generating '{{ format }}' schema in 'priv/static/static/'..."
@mix openapi.spec.{{ format }} --spec TodoListWeb.ApiSpec
@mv openapi.{{ format }} priv/static/static
# run pre-commit hooks (must have 'pre-commit' installed)
@pre-commit:
echo "Running pre-commit hooks..."
@pre-commit run --all-files
# start a dev server
@server-dev-start:
echo "Starting a dev server..."
mix phx.server
# start an interactive dev server with shell/debugging capabilities
@server-dev-start-interactive:
echo "Starting an interactive dev server with shell/debugging capabilities..."
iex -S mix phx.server
# run migrations on the prod server
@server-prod-migrate:
echo "Running migrations on the prod server..."
@./_build/prod/rel/todo_list/bin/migrate
# start the prod server
@server-prod-start:
echo "Starting prod server..."
@./_build/prod/rel/todo_list/bin/server
# stop the prod server
@server-prod-stop:
echo "Stopping prod server..."
@./_build/prod/rel/todo_list/bin/todo_list stop
# spawn an IEx shell
@shell:
echo "Spawning IEx shell...";
iex -S mix
# run Elixir tests
@test-elixir:
echo "Running Elixir tests..."
@./support/scripts/test-elixir
# run Elixir tests (in watch mode)
@test-elixir-watch:
echo "Running Elixir tests in watch mode..."
@./support/scripts/test-elixir-watch
# run Javascript unit tests with Vitest
@test-js:
echo "Running Javascript unit tests..."
@./support/scripts/test-js
# run Javascript unit tests with Vitest (in watch mode)
@test-js-watch:
echo "Running Javascript unit tests in watch mode..."
@./support/scripts/test-js-watch
# run end-to-end (E2E) tests with Playwright [args (e.g.): --help]
test-e2e args="":
@echo "Running E2E tests..."
./support/scripts/test-e2e {{ args }}
# run end-to-end (E2E) tests with Playwright (in watch mode) [args (e.g.): --help]
@test-e2e-watch args="":
echo "Running E2E tests in watch mode..."
@./support/scripts/test-e2e-watch {{ args }}
# print the OTP version number
@version-otp:
erl -eval '{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().' -noshell
# print the project version number
@version-project:
mix eval 'IO.puts(TodoList.MixProject.project[:version])'
# PRIVATE HELPERS #
@_echo_error val:
echo "{{ color_error }}Error: {{ val }}{{ color_reset }}"
@_echo_info val:
echo "{{ color_info }}{{ val }}{{ color_reset }}"
@_echo_success val:
echo "{{ color_success }}{{ val }}{{ color_reset }}"