Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
557 lines (501 loc) · 23.8 KB
/
Copy pathMakefile
File metadata and controls
557 lines (501 loc) · 23.8 KB
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
# Target naming grammar
#
# <verb>[-<what>][-<how>]
#
# what The subject, broad to narrow: android > library > e2e. When a verb has
# targets for more than one platform, each starts with its platform
# (web, ios, android); otherwise it starts with whatever the target acts
# on (`fetch-translations`).
# how Same subject, different invocation: -fix, -watch, -ui, -dev, -host
#
# Mark a word when siblings compete for the same verb. Elide it only when
# there is exactly one member, or when the unmarked form is a true superset.
# An unmarked name must never mean a subset. `build` is the one exception: it
# builds only the web bundle, yet every other build target starts from it.
#
# Verbs name categories of operation. A verb with one member is fine when the
# category is real (`check-` asserts invariants, not code style); it is not
# fine when it is a synonym for a verb already in use.
#
# A namespace prefix may precede the verb when the targets wrap a single
# external tool that has its own verbs, so the mapping stays obvious and the
# family sorts together: `wp-env-start` mirrors `wp-env start`.
#
# Targets without a `## ` description are internal and hidden from `make help`.
.DEFAULT_GOAL := help
SIMULATOR_DESTINATION := OS=latest,name=iPhone 17
IOS_E2E_RESULT_BUNDLE := build/ios-e2e.xcresult
.PHONY: help
help: ## Display this help menu
@echo "Usage: make [target]"
@echo ""
@echo "Available targets:"
@grep -E '^[a-zA-Z0-9_-]+:.*?## ' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; \
{ names[NR] = $$1; descs[NR] = $$2; if (length($$1) > width) width = length($$1) } \
END { for (i = 1; i <= NR; i++) printf " \033[36m%-*s\033[0m %s\n", width, names[i], descs[i] }' | \
sort
@echo ""
define XCODEBUILD_CMD
@set -o pipefail && \
xcodebuild $(1) \
-scheme $(2) \
-sdk iphonesimulator \
-destination '${SIMULATOR_DESTINATION}' \
CODE_SIGNING_ALLOWED=NO \
$(3) \
| xcbeautify
endef
################################################################################
# Utility Targets
################################################################################
.PHONY: install-web-deps
install-web-deps: ## Install npm dependencies
# Skip unless...
# - node_modules doesn't exist
# - REFRESH_DEPS is set to true or 1
# - install-web-deps was invoked directly (not from a recursive `$(MAKE)`)
#
# `build`'s rebuild branch invokes this as `$(MAKE) _RECURSIVE_INVOKE=1
# install-web-deps`, which sets MAKECMDGOALS=install-web-deps in the
# child make. Without the sentinel, that recursive call would treat
# itself as a "direct invocation" and re-run `npm ci` every time `build`
# rebuilds — even when node_modules is already populated.
@if [ ! -d "node_modules" ] || [ "$(REFRESH_DEPS)" = "true" ] || [ "$(REFRESH_DEPS)" = "1" ] || { [ -z "$(_RECURSIVE_INVOKE)" ] && echo "$(MAKECMDGOALS)" | grep -q "^$@$$"; }; then \
echo "--- :npm: Installing NPM Dependencies"; \
npm ci; \
else \
echo "--- :white_check_mark: Skipping NPM dependencies installation (node_modules already exists). Use REFRESH_DEPS=1 to force refresh."; \
fi
.PHONY: fetch-translations
fetch-translations: ## Fetch and cache locale string files
# Skip when `dist/` already exists — translations are baked into the
# bundle at JS build time, so there is nothing for a downstream
# consumer to refresh until the bundle itself is rebuilt. This matters
# on CI agents that download `dist.tar.gz` from an upstream job:
# without it, every downstream `make` target that depends on `build`
# would re-fetch all ~50 locales from translate.wordpress.org only to
# discard the result when `build`'s recipe short-circuits.
#
# Use `REFRESH_L10N=1` (which still forces the fetch) for the explicit
# "I want fresh translations on disk" workflow — `rm -rf
# src/translations && make build` alone will not refetch, since `dist/`
# being present is read as "translations already shipped".
#
# Otherwise, skip unless...
# - src/translations doesn't contain any fetched bundles (only `.gitkeep` is committed)
# - REFRESH_L10N is set to true or 1
# - fetch-translations was invoked directly
@if [ -d "dist" ] && [ "$(REFRESH_L10N)" != "true" ] && [ "$(REFRESH_L10N)" != "1" ] && ! echo "$(MAKECMDGOALS)" | grep -q "^$@$$"; then \
echo "--- :white_check_mark: Skipping translations fetch (dist/ already built, translations baked in). Use REFRESH_L10N=1 to force refresh."; \
elif [ -z "$$(find src/translations -maxdepth 1 -name '*.json' -print -quit 2>/dev/null)" ] || [ "$(REFRESH_L10N)" = "true" ] || [ "$(REFRESH_L10N)" = "1" ] || echo "$(MAKECMDGOALS)" | grep -q "^$@$$"; then \
echo "--- :npm: Fetching Translations"; \
if ! npm run fetch-translations -- --force; then \
if [ "$(STRICT_L10N)" = "true" ] || [ "$(STRICT_L10N)" = "1" ]; then \
echo "--- :x: ERROR: Translation fetching failed and STRICT_L10N is enabled"; \
exit 1; \
else \
echo "--- :warning: WARNING: Translation fetching failed, but continuing anyway. Use STRICT_L10N=1 to make this fatal."; \
fi; \
fi; \
else \
echo "--- :white_check_mark: Skipping translations fetch (bundles already present in src/translations). Use REFRESH_L10N=1 to force refresh."; \
fi
.PHONY: install-web-e2e-deps
install-web-e2e-deps: install-web-deps ## Install web E2E test dependencies, including Playwright Chromium
@CHROMIUM_PATH=$$(npx playwright install --dry-run chromium 2>&1 | grep "Install location" | head -1 | sed 's/.*: *//'); \
if [ -d "$$CHROMIUM_PATH" ]; then \
echo "--- :white_check_mark: Playwright Chromium is already installed."; \
elif [ -n "$$CI" ]; then \
echo "--- :chromium: Installing Playwright Chromium"; \
npx playwright install chromium; \
else \
echo ""; \
echo "Playwright Chromium browser is not installed."; \
echo "It is required to run E2E tests."; \
echo ""; \
printf "Install it now? [Y/n] "; \
read -r answer; \
if [ "$$answer" != "n" ] && [ "$$answer" != "N" ]; then \
npx playwright install chromium; \
else \
echo "Skipping install. Run 'npx playwright install chromium' manually to install."; \
exit 1; \
fi; \
fi
.PHONY: clean
clean: ## Remove build artifacts and translation string files
npm run clean
################################################################################
# Build Targets
################################################################################
.PHONY: build
build: fetch-translations ## Build the web bundle and copy it into the iOS and Android projects
# Skip unless...
# - dist doesn't exist
# - REFRESH_JS_BUILD is set to true or 1
# - build was invoked directly
#
# `install-web-deps` is invoked from inside the rebuild branch rather
# than declared as a Make prereq so that downstream targets which
# depend on `build` (`test-android-library-unit`, `test-ios-library-host`, etc.) don't
# trigger an `npm ci` they don't actually need when `dist/` is already
# populated — e.g. on CI agents that just extracted an upstream
# `dist.tar.gz` and only intend to run gradle/xcodebuild/swift.
#
# Targets that legitimately use node_modules (`test-web-e2e` via
# `install-web-e2e-deps`, `lint-web`, `test-web-unit`, etc.) declare
# `install-web-deps` as their own prereq.
@if [ ! -d "dist" ] || [ "$(REFRESH_JS_BUILD)" = "true" ] || [ "$(REFRESH_JS_BUILD)" = "1" ] || echo "$(MAKECMDGOALS)" | grep -q "^$@$$"; then \
$(MAKE) _RECURSIVE_INVOKE=1 install-web-deps && \
echo "--- :node: Building Gutenberg" && \
npm run build && \
echo "--- :open_file_folder: Copying Build Products into place" && \
$(MAKE) copy-ios-dist && \
$(MAKE) copy-android-dist; \
else \
echo "--- :white_check_mark: Skipping JS build (dist already exists). Use REFRESH_JS_BUILD=1 to force refresh."; \
fi
.PHONY: copy-ios-dist
copy-ios-dist:
@rm -rf ./ios/Sources/GutenbergKitResources/Gutenberg/
@mkdir -p ./ios/Sources/GutenbergKitResources/Gutenberg
@cp -r ./dist/. ./ios/Sources/GutenbergKitResources/Gutenberg/
@touch ./ios/Sources/GutenbergKitResources/Gutenberg/.gitkeep
.PHONY: copy-android-dist
copy-android-dist:
@rm -rf ./android/Gutenberg/src/main/assets/
@cp -r ./dist/. ./android/Gutenberg/src/main/assets
.PHONY: build-ios-library
build-ios-library: build ## Build the Swift package for iOS
$(call XCODEBUILD_CMD, build, GutenbergKit)
# API that is unavailable in app extensions, such as `UIApplication.shared`,
# fails this build. CI runs it so the library stays usable from an extension.
.PHONY: build-ios-library-extension-safe
build-ios-library-extension-safe: build ## Build the Swift package for iOS with app-extension-safe API only
$(call XCODEBUILD_CMD, build, GutenbergKit, APPLICATION_EXTENSION_API_ONLY=YES)
.PHONY: build-ios-resources-xcframework
build-ios-resources-xcframework: build ## Build GutenbergKitResources XCFramework
# `build` short-circuits `copy-ios-dist` when `dist/` already exists (e.g. in
# CI, after extracting an upstream dist tarball), so call it explicitly here
# to guarantee the XCFramework ships the just-built dist rather than whatever
# was committed at HEAD.
@$(MAKE) copy-ios-dist
@echo "--- :swift: Building GutenbergKitResources XCFramework"
./build_xcframework.sh
.PHONY: publish-android-library-local
publish-android-library-local: build ## Build and publish the Android library to the local Maven repository
@echo "--- :android: Building Library"
./android/gradlew -p ./android :gutenberg:publishToMavenLocal -exclude-task prepareToPublishToS3
################################################################################
# Development Targets
################################################################################
.PHONY: serve
serve: install-web-deps ## Serve the production build locally
npm run preview
.PHONY: serve-dev
serve-dev: install-web-deps ## Serve the editor from the Vite development server
npm run dev
.PHONY: serve-dev-force
serve-dev-force: install-web-deps ## Serve the editor from the Vite development server, ignoring the cache and re-bundling
npm run dev:force
# Credentials come from ~/.config/wp/sites, WPCOM_TOKEN or ~/.wpcom-token, never
# a make variable, so that they stay out of shell history.
DEMO_APP_LOGIN = ./bin/demo-app-login.sh $(if $(SITE),--site "$(SITE)") $(if $(DEVICE),--device "$(DEVICE)")
.PHONY: login-ios-app
login-ios-app: ## Sign the iOS demo app into the sites in ~/.config/wp/sites and ~/.wpcom-token (optional: SITE for just one, DEVICE)
@$(DEMO_APP_LOGIN) --platform ios
.PHONY: login-android-app
login-android-app: ## Sign the Android demo app into the sites in ~/.config/wp/sites and ~/.wpcom-token (optional: SITE for just one, DEVICE)
@$(DEMO_APP_LOGIN) --platform android
################################################################################
# Local WordPress Environment Targets (wp-env)
################################################################################
.PHONY: wp-env-start
wp-env-start: install-web-deps ## Start the local WordPress environment
@bash bin/wp-env-guard.sh; \
status=$$?; \
if [ $$status -eq 0 ]; then \
npm run wp-env start -- --runtime=playground; \
elif [ $$status -ne 10 ]; then \
exit $$status; \
fi
@bash bin/wp-env-setup.sh
.PHONY: wp-env-stop
wp-env-stop: ## Stop the local WordPress environment
npm run wp-env stop
.PHONY: wp-env-clean
wp-env-clean: ## Stop wp-env and remove downloaded WordPress, plugin, and theme files, plus cached credentials
npm run wp-env destroy
@rm -f .wp-env.credentials.json
# `destroy` stops only the server named by its PID file, so report anything left
# holding the port rather than letting the next start fail on it.
@bash bin/wp-env-guard.sh > /dev/null || true
.PHONY: wp-env-config-android-urls
wp-env-config-android-urls: ## Report the Android emulator URL remap, or set it with MODE=on|off
@MODE=$(MODE) bash bin/wp-env-android.sh
.PHONY: wp-env-media-failure
wp-env-media-failure: ## Report the media upload failure simulation mode (set via MODE=off|recover|always)
@MODE=$(MODE) bash bin/wp-env-media-failure.sh
################################################################################
# Code Quality Targets
################################################################################
.PHONY: format
format: install-web-deps ## Format all supported files in place with Prettier
npm run format
.PHONY: lint-web
lint-web: install-web-deps ## Lint JavaScript code with ESLint and check formatting with Prettier
npm run lint:js
npm run format:check
# Reads `package-lock.json`, not the installed tree, so it needs no
# `install-web-deps` prerequisite -- which would otherwise report on a stale
# `node_modules` whenever one already exists.
.PHONY: check-wp-packages
check-wp-packages: ## Fail if any @wordpress package is installed more than once
npm run check:wp-packages
.PHONY: lint-web-fix
lint-web-fix: install-web-deps ## Lint and auto-fix JavaScript code with ESLint and format with Prettier
npm run lint:js:fix
npm run format
.PHONY: lint-android
lint-android: ## Lint Android code with Detekt
@echo "--- :android: Running Detekt"
./android/gradlew -p ./android detekt
# Runs SwiftLint via the BuildTools package plugin, which pins the SwiftLint version
# to `swiftlint_version` in .swiftlint.yml. SDKROOT is pinned to the macOS SDK so the
# plugin builds even when invoked from an environment that targets iOS.
#
# Set SWIFT_LINT_PATHS to lint specific files instead of the whole project, e.g.
# `make lint-ios SWIFT_LINT_PATHS=ios/Sources/GutenbergKit/Sources/EditorService.swift`.
# Only files are honored — passing a directory silently falls back to linting the
# whole project.
#
# Separate multiple files with newlines rather than spaces, so that paths
# containing spaces stay intact:
#
# make lint-ios SWIFT_LINT_PATHS="$(git diff --name-only -- '*.swift')"
#
# The plugin only honors explicit paths when the last argument is an existing
# file, so the paths must always be appended last — after flags like `--fix` — or
# the plugin silently falls back to linting the whole project.
#
# The paths are exported and re-split on newlines inside the recipe rather than
# expanded inline as $(SWIFT_LINT_PATHS). Inline expansion pastes the value into
# the recipe text, where the shell word-splits a path containing spaces into
# fragments that are not existing files — silently triggering that same
# whole-project fallback. Going through the environment avoids that entirely.
SWIFT_LINT_PATHS ?=
export SWIFT_LINT_PATHS
SWIFTLINT = IFS="$$(printf '\nx')"; IFS="$${IFS%x}"; \
set -f; set -- $${SWIFT_LINT_PATHS:+$$SWIFT_LINT_PATHS}; \
unset IFS; set +f; \
SDKROOT="$$(xcrun --sdk macosx --show-sdk-path)" \
swift package --package-path BuildTools plugin \
--allow-writing-to-directory "$(CURDIR)" --allow-writing-to-package-directory \
swiftlint --working-directory "$(CURDIR)" --quiet
.PHONY: lint-ios
lint-ios: ## Lint Swift code with SwiftLint
@echo "--- :swift: Running SwiftLint"
@$(SWIFTLINT) "$$@"
.PHONY: lint-ios-fix
lint-ios-fix: ## Lint and auto-fix Swift code with SwiftLint
@echo "--- :swift: Running SwiftLint (autocorrect)"
@$(SWIFTLINT) --fix "$$@"
################################################################################
# Testing Targets
################################################################################
.PHONY: test-web-e2e
test-web-e2e: install-web-e2e-deps ## Run web E2E tests with Playwright
@if [ ! -d "dist" ]; then \
$(MAKE) build; \
else \
echo "--- :white_check_mark: Using existing build. Use 'make build REFRESH_JS_BUILD=1' to rebuild."; \
fi
npm run test:e2e
.PHONY: test-web-e2e-ui
test-web-e2e-ui: install-web-e2e-deps ## Run web E2E tests with Playwright in UI mode
@if [ ! -d "dist" ]; then \
$(MAKE) build; \
else \
echo "--- :white_check_mark: Using existing build. Use 'make build REFRESH_JS_BUILD=1' to rebuild."; \
fi
npm run test:e2e:ui
.PHONY: test-web-unit
test-web-unit: install-web-deps ## Run JavaScript unit tests with Vitest
npm run test:unit
.PHONY: test-web-unit-watch
test-web-unit-watch: install-web-deps ## Run JavaScript unit tests with Vitest in watch mode
npm run test:unit:watch
.PHONY: test-ios-library-simulator
test-ios-library-simulator: build ## Run Swift package tests in the iOS Simulator (xcodebuild)
$(call XCODEBUILD_CMD, test, GutenbergKit-Package)
.PHONY: test-ios-library-host
test-ios-library-host: build ## Run Swift package tests on the host platform (swift test)
swift test
.PHONY: test-ios-app-e2e
test-ios-app-e2e: ## Run iOS demo app E2E tests against the production build
@if [ ! -d "dist" ]; then \
$(MAKE) build; \
else \
echo "--- :white_check_mark: Using existing build. Use 'make build REFRESH_JS_BUILD=1' to rebuild."; \
fi
@echo "--- :open_file_folder: Copying build into iOS bundle"
@$(MAKE) copy-ios-dist
@echo "--- :ios: Running iOS E2E Tests (production build)"
# xcodebuild refuses to overwrite an existing result bundle.
@rm -rf '$(IOS_E2E_RESULT_BUNDLE)'
@set -o pipefail && \
xcodebuild test \
-project ./ios/Demo-iOS/Gutenberg.xcodeproj \
-scheme GutenbergUITests \
-sdk iphonesimulator \
-destination '${SIMULATOR_DESTINATION}' \
-resultBundlePath '$(IOS_E2E_RESULT_BUNDLE)' \
| xcbeautify
.PHONY: test-ios-app-e2e-dev
test-ios-app-e2e-dev: ## Run iOS demo app E2E tests against the Vite dev server (must be running)
@if ! curl -sf http://localhost:5173 > /dev/null 2>&1; then \
echo "Error: Dev server is not running at http://localhost:5173"; \
echo "Start it first with: make serve-dev"; \
exit 1; \
fi
@echo "--- :ios: Running iOS E2E Tests (dev server)"
@set -o pipefail && \
TEST_RUNNER_GUTENBERG_EDITOR_URL=http://localhost:5173 \
xcodebuild test \
-project ./ios/Demo-iOS/Gutenberg.xcodeproj \
-scheme GutenbergUITests \
-sdk iphonesimulator \
-destination '${SIMULATOR_DESTINATION}' \
| xcbeautify
.PHONY: test-android-library-unit
test-android-library-unit: build ## Run Android library unit tests on the JVM
# `build` short-circuits `copy-android-dist` when `dist/` already exists
# (e.g. in CI, after extracting an upstream `dist.tar.gz`), so copy
# explicitly here to guarantee the tests run against the current dist
# rather than whatever was committed at HEAD.
@echo "--- :open_file_folder: Copying build into Android bundle"
@$(MAKE) copy-android-dist
@echo "--- :android: Running Android Library Unit Tests"
./android/gradlew -p ./android :gutenberg:test
# Ensure an Android device or emulator is available for instrumented tests.
# Checks for any connected device; if none found, boots the first available AVD.
define ENSURE_ANDROID_DEVICE
@if adb devices 2>/dev/null | tail -n +2 | grep -q 'device$$'; then \
echo "--- :white_check_mark: Android device already connected."; \
else \
AVD=$$("$$ANDROID_HOME/emulator/emulator" -list-avds 2>/dev/null | head -n 1); \
if [ -z "$$AVD" ]; then \
echo "Error: No Android device connected and no AVDs found."; \
echo "Connect a device, start an emulator, or create an AVD with Android Studio."; \
exit 1; \
fi; \
echo "--- :rocket: Booting Android emulator ($$AVD)..."; \
"$$ANDROID_HOME/emulator/emulator" -avd "$$AVD" -no-snapshot-load -no-audio -no-window &>/dev/null & \
EMULATOR_PID=$$!; \
echo "--- :hourglass: Waiting for emulator to boot..."; \
adb wait-for-device; \
BOOT_WAIT=0; \
while [ "$$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" != "1" ]; do \
BOOT_WAIT=$$((BOOT_WAIT + 1)); \
if [ $$BOOT_WAIT -gt 60 ]; then \
echo "Error: Emulator boot timed out after 120 seconds."; \
kill $$EMULATOR_PID 2>/dev/null; \
exit 1; \
fi; \
sleep 2; \
done; \
echo "--- :white_check_mark: Emulator booted."; \
fi
endef
.PHONY: test-android-app-e2e
test-android-app-e2e: ## Run Android demo app E2E tests against the production build
@if [ ! -d "dist" ]; then \
$(MAKE) build; \
else \
echo "--- :white_check_mark: Using existing build. Use 'make build REFRESH_JS_BUILD=1' to rebuild."; \
fi
@echo "--- :open_file_folder: Copying build into Android bundle"
@$(MAKE) copy-android-dist
$(ENSURE_ANDROID_DEVICE)
@echo "--- :android: Running Android E2E Tests (production build)"
# The system intermittently kills the app mid-test. The system and events
# buffers record why, but the per-test logcat omits them; enlarge the buffers
# so the whole test run survives until the dump.
@mkdir -p android/app/build/outputs/buildkite-logs
-@adb logcat -b all -G 16M
@./android/gradlew -p ./android :app:connectedDebugAndroidTest; \
EXIT=$$?; \
adb logcat -b all -d > android/app/build/outputs/buildkite-logs/device-logcat.txt; \
exit $$EXIT
.PHONY: test-android-app-e2e-dev
test-android-app-e2e-dev: ## Run Android demo app E2E tests against the Vite dev server (must be running)
@if ! curl -sf http://localhost:5173 > /dev/null 2>&1; then \
echo "Error: Dev server is not running at http://localhost:5173"; \
echo "Start it first with: make serve-dev"; \
exit 1; \
fi
$(ENSURE_ANDROID_DEVICE)
@echo "--- :android: Running Android E2E Tests (dev server)"
./android/gradlew -p ./android :app:connectedDebugAndroidTest
.PHONY: test-android-library-e2e
test-android-library-e2e: build ## Run Android library E2E tests on a device or emulator
# `build` short-circuits `copy-android-dist` when `dist/` already exists
# (e.g. in CI, after extracting an upstream `dist.tar.gz`), so copy
# explicitly here to guarantee the instrumented tests run against the
# current dist rather than whatever was committed at HEAD.
@echo "--- :open_file_folder: Copying build into Android bundle"
@$(MAKE) copy-android-dist
$(ENSURE_ANDROID_DEVICE)
@echo "--- :android: Running Android Library E2E Tests"
@mkdir -p android/Gutenberg/build/outputs/buildkite-logs
# As in test-android-app-e2e: keep the buffers that record why the system
# kills a process.
-@adb logcat -b all -G 16M
@adb logcat -b all -c
@./android/gradlew -p ./android :Gutenberg:connectedDebugAndroidTest; \
EXIT=$$?; \
adb logcat -b all -d > android/Gutenberg/build/outputs/buildkite-logs/device-logcat.txt; \
echo "--- :mag: Buildkite Test Engine collector output"; \
if grep -E 'Buildkite|BUILDKITE_ANALYTICS' android/Gutenberg/build/outputs/buildkite-logs/device-logcat.txt; then :; \
else \
echo "(no Buildkite collector output found in device logcat — listener may not have registered)"; \
fi; \
if grep -q 'BuildkiteLogger-ERROR\|Buildkite-InstrumentedTestCollector-ERROR' android/Gutenberg/build/outputs/buildkite-logs/device-logcat.txt; then \
echo "+++ :rotating_light: Buildkite Test Engine upload failed (see excerpt above)"; \
EXIT=1; \
fi; \
exit $$EXIT
################################################################################
# Release Target
################################################################################
.PHONY: release
release: ## Create and publish a new release
@if [ -z "$(VERSION_TYPE)" ]; then \
echo "Error: VERSION_TYPE is required."; \
echo ""; \
echo "Usage: make release VERSION_TYPE=[<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git] [DRY_RUN=true]"; \
echo ""; \
echo "Version Types:"; \
echo " <newversion> Custom version number (e.g., 1.2.3)"; \
echo " major Increment major version (1.0.0 -> 2.0.0)"; \
echo " minor Increment minor version (1.2.0 -> 1.3.0)"; \
echo " patch Increment patch version (1.2.3 -> 1.2.4)"; \
echo " premajor Increment major version and add prerelease (1.2.3 -> 2.0.0-alpha.0)"; \
echo " preminor Increment minor version and add prerelease (1.2.3 -> 1.3.0-alpha.0)"; \
echo " prepatch Increment patch version and add prerelease (1.2.3 -> 1.2.4-alpha.0)"; \
echo " prerelease Increment prerelease version (1.2.3-alpha.0 -> 1.2.3-alpha.1)"; \
echo " from-git Use version from git tag"; \
echo ""; \
echo "Examples:"; \
echo " make release VERSION_TYPE=patch"; \
echo " make release VERSION_TYPE=1.2.3"; \
echo " make release VERSION_TYPE=patch DRY_RUN=true"; \
exit 1; \
fi
@echo "--- :rocket: Starting GutenbergKit Release Process"
@if [ "$(DRY_RUN)" = "true" ]; then \
./bin/release.sh $(VERSION_TYPE) --dry-run; \
else \
./bin/release.sh $(VERSION_TYPE); \
fi