diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 2b28fcdc3..1464179d7 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -13,10 +13,10 @@ steps: key: build-react command: | # Fail fast if any step (including the backgrounded - # `prep-translations`, surfaced via `wait`) returns non-zero, + # `fetch-translations`, surfaced via `wait`) returns non-zero, # rather than continuing into `make build` with partial inputs. set -euo pipefail - # `prep-translations` is pure network I/O and no longer depends + # `fetch-translations` is pure network I/O and no longer depends # on `node_modules` (uses Node's built-in `fetch`), so it can run # in parallel with `npm ci`. Vite reads `src/translations/` when # it emits locale bundles, so we wait for the fetch to complete @@ -27,16 +27,16 @@ steps: # interleave with `npm ci`'s and confuse Buildkite log folding. # The replay happens unconditionally so a failed fetch surfaces # its log before `set -e` aborts the script. - make prep-translations STRICT_L10N=1 > prep-translations.log 2>&1 & - PREP_PID=$$! - make npm-dependencies - PREP_STATUS=0 - wait $$PREP_PID || PREP_STATUS=$$? - echo "--- :earth_americas: prep-translations (ran in parallel with npm ci)" - cat prep-translations.log - rm -f prep-translations.log - if [ "$$PREP_STATUS" -ne 0 ]; then - exit "$$PREP_STATUS" + make fetch-translations STRICT_L10N=1 > fetch-translations.log 2>&1 & + FETCH_PID=$$! + make install-web-deps + FETCH_STATUS=0 + wait $$FETCH_PID || FETCH_STATUS=$$? + echo "--- :earth_americas: fetch-translations (ran in parallel with npm ci)" + cat fetch-translations.log + rm -f fetch-translations.log + if [ "$$FETCH_STATUS" -ne 0 ]; then + exit "$$FETCH_STATUS" fi make build REFRESH_JS_BUILD=1 tar -czf dist.tar.gz dist/ @@ -55,7 +55,7 @@ steps: - label: ':eslint: Lint React App' key: lint-js - command: make lint-js + command: make lint-web plugins: *plugins - label: ':npm: Check @wordpress package versions' @@ -65,7 +65,7 @@ steps: - label: ':javascript: Test JavaScript' key: test-js - command: make test-js + command: make test-web-unit plugins: *plugins - label: ':performing_arts: Test Web E2E' @@ -77,7 +77,7 @@ steps: echo "--- :wordpress: Starting wp-env" make wp-env-start echo "--- :performing_arts: Running E2E tests" - make test-e2e + make test-web-e2e plugins: *plugins - label: ':android: Publish Android Library' @@ -110,7 +110,7 @@ steps: command: | buildkite-agent artifact download dist.tar.gz . tar -xzf dist.tar.gz - make test-android + make test-android-library-unit agents: queue: android plugins: *plugins @@ -121,7 +121,7 @@ steps: command: | buildkite-agent artifact download dist.tar.gz . tar -xzf dist.tar.gz - make test-swift-package + make test-ios-library-simulator plugins: *plugins - label: ':swift: Library Tests' @@ -130,7 +130,7 @@ steps: command: | buildkite-agent artifact download dist.tar.gz . tar -xzf dist.tar.gz - make test-swift-library + make test-ios-library-host plugins: *plugins - label: ':xcode: Build XCFramework' @@ -143,7 +143,7 @@ steps: tar -xzf dist.tar.gz install_gems bundle exec fastlane set_up_signing_release - make build-resources-xcframework + make build-ios-resources-xcframework bundle exec fastlane xcframework_sign ./package_xcframework.sh artifact_paths: @@ -199,7 +199,7 @@ steps: command: | buildkite-agent artifact download dist.tar.gz . tar -xzf dist.tar.gz - make test-ios-e2e + make test-ios-app-e2e plugins: *plugins - label: ':android: Test Android E2E' @@ -212,7 +212,7 @@ steps: --system-image "system-images;android-34;google_apis;arm64-v8a" \ --device "pixel_5" echo "--- :android: Running Android instrumented tests" - make test-android-e2e + make test-android-app-e2e agents: queue: mac-metal plugins: *plugins diff --git a/AGENTS.md b/AGENTS.md index a382f3d55..fa86dd388 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,6 +23,8 @@ To see all available make commands with descriptions, run: make help ``` +New targets follow the naming grammar documented in the header comment at the top of the `Makefile`. + By default, dependencies, translations, and JS build are skipped if output directories already exist. Environment variables be used to force refresh of these steps when needed. - `REFRESH_DEPS=1` - Force refresh of dependencies (e.g. re-install npm packages) @@ -71,10 +73,10 @@ Note: Console logs should be used sparingly. For verbose or development-specific ```bash # Auto-fix linting errors & verify linting passes -make lint-js-fix +make lint-web-fix # When Swift files changed -make lint-swift-fix +make lint-ios-fix ``` These commands ensure code quality and prevent lint errors from blocking commits. @@ -85,8 +87,8 @@ Swift code is linted with SwiftLint, run via the SwiftPM plugin in the `BuildToo package so the linter stays out of the dependency graph of anyone consuming GutenbergKit via SwiftPM. -- `make lint-swift` — report violations -- `make lint-swift-fix` — auto-correct the violations SwiftLint can fix +- `make lint-ios` — report violations +- `make lint-ios-fix` — auto-correct the violations SwiftLint can fix The SwiftLint version is pinned in a single place: the `swiftlint_version` key in `.swiftlint.yml`. `BuildTools/Package.swift` parses that key at manifest-evaluation @@ -102,14 +104,14 @@ stay consistent for the shared team. To lint specific files rather than the whole project, set `SWIFT_LINT_PATHS`: ```bash -make lint-swift SWIFT_LINT_PATHS=ios/Sources/GutenbergKit/Sources/EditorService.swift +make lint-ios SWIFT_LINT_PATHS=ios/Sources/GutenbergKit/Sources/EditorService.swift ``` Separate multiple files with **newlines**, not spaces, so that paths containing spaces stay intact. This makes it easy to lint just the changed files: ```bash -make lint-swift SWIFT_LINT_PATHS="$(git diff --name-only -- '*.swift')" +make lint-ios SWIFT_LINT_PATHS="$(git diff --name-only -- '*.swift')" ``` Each value must be a path to an existing **file**. Passing a directory (or a diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 214aaaf9b..3c058fe60 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,8 +19,8 @@ Whether you're looking to write code, improve documentation, or help triage issu ## Guidelines -- Run `make format` and `make lint-js` before submitting changes -- Ensure tests pass with `make test-js`, `make test-swift-package`, and `make test-android` +- Run `make format` and `make lint-web` before submitting changes +- Ensure tests pass with `make test-web-unit`, `make test-ios-library-simulator`, and `make test-android-library-unit` - Follow the existing code style and patterns ## Releases diff --git a/Makefile b/Makefile index 79b5475b9..5b4ad4682 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,28 @@ +# Target naming grammar +# +# [-][-] +# +# 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 @@ -28,27 +53,27 @@ endef # Utility Targets ################################################################################ -.PHONY: npm-dependencies -npm-dependencies: ## Install npm dependencies +.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 -# - npm-dependencies was invoked directly (not from a recursive `$(MAKE)`) +# - install-web-deps was invoked directly (not from a recursive `$(MAKE)`) # # `build`'s rebuild branch invokes this as `$(MAKE) _RECURSIVE_INVOKE=1 -# npm-dependencies`, which sets MAKECMDGOALS=npm-dependencies in the +# 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 "^npm-dependencies$$"; }; then \ + @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: prep-translations -prep-translations: ## Fetch and cache locale string files +.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 @@ -65,12 +90,12 @@ prep-translations: ## Fetch and cache locale string files # Otherwise, skip unless... # - src/translations doesn't contain any fetched bundles (only `.gitkeep` is committed) # - REFRESH_L10N is set to true or 1 -# - prep-translations was invoked directly - @if [ -d "dist" ] && [ "$(REFRESH_L10N)" != "true" ] && [ "$(REFRESH_L10N)" != "1" ] && ! echo "$(MAKECMDGOALS)" | grep -q "^prep-translations$$"; then \ +# - 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 "^prep-translations$$"; then \ - echo "--- :npm: Preparing Translations"; \ - if ! npm run prep-translations -- --force; then \ + 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; \ @@ -82,8 +107,8 @@ prep-translations: ## Fetch and cache locale string files echo "--- :white_check_mark: Skipping translations fetch (bundles already present in src/translations). Use REFRESH_L10N=1 to force refresh."; \ fi -.PHONY: e2e-dependencies -e2e-dependencies: npm-dependencies ## Install E2E test dependencies +.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."; \ @@ -114,61 +139,61 @@ clean: ## Remove build artifacts and translation string files ################################################################################ .PHONY: build -build: prep-translations ## Build the project for all platforms (iOS, Android, web) +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 # -# `npm-dependencies` is invoked from inside the rebuild branch rather +# `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`, `test-swift-library`, etc.) don't +# 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-e2e` via -# `e2e-dependencies`, `lint-js`, `test-js`, etc.) declare -# `npm-dependencies` as their own prereq. - @if [ ! -d "dist" ] || [ "$(REFRESH_JS_BUILD)" = "true" ] || [ "$(REFRESH_JS_BUILD)" = "1" ] || echo "$(MAKECMDGOALS)" | grep -q "^build$$"; then \ - $(MAKE) _RECURSIVE_INVOKE=1 npm-dependencies && \ +# 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-dist-ios && \ - $(MAKE) copy-dist-android; \ + $(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-dist-ios -copy-dist-ios: +.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-dist-android -copy-dist-android: +.PHONY: copy-android-dist +copy-android-dist: @rm -rf ./android/Gutenberg/src/main/assets/ @cp -r ./dist/. ./android/Gutenberg/src/main/assets -.PHONY: build-swift-package -build-swift-package: build ## Build the Swift package for iOS +.PHONY: build-ios-library +build-ios-library: build ## Build the Swift package for iOS $(call XCODEBUILD_CMD, build, GutenbergKit) -.PHONY: build-resources-xcframework -build-resources-xcframework: build ## Build GutenbergKitResources XCFramework -# `build` short-circuits `copy-dist-ios` when `dist/` already exists (e.g. in +.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-dist-ios + @$(MAKE) copy-ios-dist @echo "--- :swift: Building GutenbergKitResources XCFramework" ./build_xcframework.sh -.PHONY: local-android-library -local-android-library: build ## Build the Android library to local Maven +.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 @@ -176,28 +201,28 @@ local-android-library: build ## Build the Android library to local Maven # Development Targets ################################################################################ -.PHONY: dev-server -dev-server: npm-dependencies ## Start the development server +.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: dev-server-force -dev-server-force: npm-dependencies ## Start the development server, ignore the cache and re-bundle +.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 -.PHONY: dev-tools -dev-tools: npm-dependencies ## Start the React Developer Tools +.PHONY: start-devtools +start-devtools: install-web-deps ## Start the React Developer Tools npm run dev:tools -.PHONY: preview -preview: npm-dependencies ## Preview the production build locally - npm run preview - ################################################################################ # Local WordPress Environment Targets (wp-env) ################################################################################ .PHONY: wp-env-start -wp-env-start: npm-dependencies ## Start the local WordPress environment +wp-env-start: install-web-deps ## Start the local WordPress environment @bash bin/wp-env-guard.sh; \ status=$$?; \ if [ $$status -eq 0 ]; then \ @@ -212,15 +237,15 @@ 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 +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-android-urls -wp-env-android-urls: ## Report whether WordPress emits emulator-reachable URLs, 10.0.2.2 instead of localhost (set via MODE=on|off) +.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 ################################################################################ @@ -228,22 +253,22 @@ wp-env-android-urls: ## Report whether WordPress emits emulator-reachable URLs, ################################################################################ .PHONY: format -format: npm-dependencies ## Format code +format: install-web-deps ## Format all supported files in place with Prettier npm run format -.PHONY: lint-js -lint-js: npm-dependencies ## Lint JavaScript code +.PHONY: lint-web +lint-web: install-web-deps ## Lint JavaScript code with ESLint npm run lint:js # Reads `package-lock.json`, not the installed tree, so it needs no -# `npm-dependencies` prerequisite -- which would otherwise report on a stale +# `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-fix-js -lint-js-fix: npm-dependencies ## Lint and auto-fix JavaScript code +.PHONY: lint-web-fix +lint-web-fix: install-web-deps ## Lint and auto-fix JavaScript code with ESLint npm run lint:js:fix .PHONY: lint-android @@ -256,14 +281,14 @@ lint-android: ## Lint Android code with Detekt # 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-swift SWIFT_LINT_PATHS=ios/Sources/GutenbergKit/Sources/EditorService.swift`. +# `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-swift SWIFT_LINT_PATHS="$(git diff --name-only -- '*.swift')" +# 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 @@ -285,13 +310,13 @@ SWIFTLINT = IFS="$$(printf '\nx')"; IFS="$${IFS%x}"; \ --allow-writing-to-directory "$(CURDIR)" --allow-writing-to-package-directory \ swiftlint --working-directory "$(CURDIR)" --quiet -.PHONY: lint-swift -lint-swift: ## Lint Swift code +.PHONY: lint-ios +lint-ios: ## Lint Swift code with SwiftLint @echo "--- :swift: Running SwiftLint" @$(SWIFTLINT) "$$@" -.PHONY: lint-swift-fix -lint-swift-fix: ## Lint and auto-fix Swift code +.PHONY: lint-ios-fix +lint-ios-fix: ## Lint and auto-fix Swift code with SwiftLint @echo "--- :swift: Running SwiftLint (autocorrect)" @$(SWIFTLINT) --fix "$$@" @@ -299,8 +324,8 @@ lint-swift-fix: ## Lint and auto-fix Swift code # Testing Targets ################################################################################ -.PHONY: test-e2e -test-e2e: e2e-dependencies ## Run end-to-end tests +.PHONY: test-web-e2e +test-web-e2e: install-web-e2e-deps ## Run web E2E tests with Playwright @if [ ! -d "dist" ]; then \ $(MAKE) build; \ else \ @@ -308,8 +333,8 @@ test-e2e: e2e-dependencies ## Run end-to-end tests fi npm run test:e2e -.PHONY: test-e2e-ui -test-e2e-ui: e2e-dependencies ## Run end-to-end tests in UI mode +.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 \ @@ -317,31 +342,31 @@ test-e2e-ui: e2e-dependencies ## Run end-to-end tests in UI mode fi npm run test:e2e:ui -.PHONY: test-js -test-js: npm-dependencies ## Run JavaScript tests +.PHONY: test-web-unit +test-web-unit: install-web-deps ## Run JavaScript unit tests with Vitest npm run test:unit -.PHONY: test-js-watch -test-js-watch: npm-dependencies ## Run JavaScript tests in watch mode +.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-swift-package -test-swift-package: build ## Run Swift package tests in the iOS Simulator +.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-swift-library -test-swift-library: build ## Run Swift package tests against the host platform via `swift test` +.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-e2e -test-ios-e2e: ## Run iOS E2E tests against the production build +.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-dist-ios + @$(MAKE) copy-ios-dist @echo "--- :ios: Running iOS E2E Tests (production build)" @set -o pipefail && \ xcodebuild test \ @@ -351,11 +376,11 @@ test-ios-e2e: ## Run iOS E2E tests against the production build -destination '${SIMULATOR_DESTINATION}' \ | xcbeautify -.PHONY: test-ios-e2e-dev -test-ios-e2e-dev: ## Run iOS E2E tests against the Vite dev server (must be running) +.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 dev-server"; \ + echo "Start it first with: make serve-dev"; \ exit 1; \ fi @echo "--- :ios: Running iOS E2E Tests (dev server)" @@ -368,16 +393,15 @@ test-ios-e2e-dev: ## Run iOS E2E tests against the Vite dev server (must be runn -destination '${SIMULATOR_DESTINATION}' \ | xcbeautify -.PHONY: test-android -test-android: build ## Run Android tests -# `build` short-circuits `copy-dist-android` when `dist/` already exists +.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" - @rm -rf ./android/Gutenberg/src/main/assets/ - @cp -r ./dist/. ./android/Gutenberg/src/main/assets - @echo "--- :android: Running Android Tests" + @$(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. @@ -411,25 +435,24 @@ define ENSURE_ANDROID_DEVICE fi endef -.PHONY: test-android-e2e -test-android-e2e: ## Run Android E2E tests against the production build +.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" - @rm -rf ./android/Gutenberg/src/main/assets/ - @cp -r ./dist/. ./android/Gutenberg/src/main/assets + @$(MAKE) copy-android-dist $(ENSURE_ANDROID_DEVICE) @echo "--- :android: Running Android E2E Tests (production build)" ./android/gradlew -p ./android :app:connectedDebugAndroidTest -.PHONY: test-android-e2e-dev -test-android-e2e-dev: ## Run Android E2E tests against the Vite dev server (must be running) +.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 dev-server"; \ + echo "Start it first with: make serve-dev"; \ exit 1; \ fi $(ENSURE_ANDROID_DEVICE) @@ -437,16 +460,15 @@ test-android-e2e-dev: ## Run Android E2E tests against the Vite dev server (must ./android/gradlew -p ./android :app:connectedDebugAndroidTest .PHONY: test-android-library-e2e -test-android-library-e2e: build ## Run instrumented tests for the Gutenberg Android library module -# `build` short-circuits `copy-dist-android` when `dist/` already exists +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" - @rm -rf ./android/Gutenberg/src/main/assets/ - @cp -r ./dist/. ./android/Gutenberg/src/main/assets + @$(MAKE) copy-android-dist $(ENSURE_ANDROID_DEVICE) - @echo "--- :android: Running Android Library Instrumented Tests" + @echo "--- :android: Running Android Library E2E Tests" @mkdir -p android/Gutenberg/build/outputs/buildkite-logs @adb logcat -c @./android/gradlew -p ./android :Gutenberg:connectedDebugAndroidTest; \ diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 40d2f403c..e85632ffb 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -3,7 +3,7 @@ GutenbergKit - Note: Editors are using the dev server started with `make dev-server`. + Note: Editors are using the dev server started with `make serve-dev`. Note: Editors are using the compiled web app built with `make build`. Standalone editor Editor without a WordPress site. No theme styles, media uploads, or plugins. diff --git a/android/buildSrc/src/main/kotlin/GenerateSupportedLocales.kt b/android/buildSrc/src/main/kotlin/GenerateSupportedLocales.kt index d9e75fddf..a75353735 100644 --- a/android/buildSrc/src/main/kotlin/GenerateSupportedLocales.kt +++ b/android/buildSrc/src/main/kotlin/GenerateSupportedLocales.kt @@ -54,13 +54,13 @@ abstract class GenerateSupportedLocales : DefaultTask() { }.sorted() if (locales.isEmpty()) { - // An empty manifest typically means `make prep-translations` was + // An empty manifest typically means `make fetch-translations` was // skipped or failed silently — `src/translations/` only had // `.gitkeep` when Vite scanned it. Without this guard the library // ships with a runtime-empty `SupportedLocales`, which resolves // every locale to English. throw GradleException( - "supported-locales.json is empty. Run `make prep-translations REFRESH_L10N=1` " + + "supported-locales.json is empty. Run `make fetch-translations REFRESH_L10N=1` " + "from the repo root, then `make build`, before assembling the :Gutenberg library." ) } diff --git a/bin/README.md b/bin/README.md index 7044873da..a0ecfcbf0 100644 --- a/bin/README.md +++ b/bin/README.md @@ -79,14 +79,14 @@ make release VERSION_TYPE=patch DRY_RUN=true - `make` - for building the project - Git - for version control operations -### `prep-translations.js` +### `fetch-translations.js` -Prepares translations for the GutenbergKit project. This script is typically run as part of the build process. +Fetches and caches locale string files for the GutenbergKit project. This script is typically run as part of the build process. #### Usage ```bash -make prep-translations +make fetch-translations ``` ### `check-wordpress-package-duplicates.js` diff --git a/bin/claude-hooks/swiftlint.sh b/bin/claude-hooks/swiftlint.sh index 83b395be6..e64f5ee7b 100755 --- a/bin/claude-hooks/swiftlint.sh +++ b/bin/claude-hooks/swiftlint.sh @@ -3,7 +3,7 @@ # Claude Code PostToolUse hook: lint Swift code with SwiftLint after an edit. # # Reads the hook payload (JSON) on stdin. When the edited file is Swift, runs -# `make lint-swift` so the hook uses the exact same SwiftLint binary and +# `make lint-ios` so the hook uses the exact same SwiftLint binary and # configuration as the project lint command. On violations, prints them to # stderr and exits 2 so Claude Code feeds them back to the model for # self-correction. @@ -27,7 +27,7 @@ cd "${CLAUDE_PROJECT_DIR:-.}" || exit 0 # edit when this runs somewhere Xcode isn't available. command -v xcrun >/dev/null 2>&1 || exit 0 -out=$(make lint-swift 2>&1) +out=$(make lint-ios 2>&1) status=$? # SwiftLint exits non-zero for `error`-severity violations, but only prints to diff --git a/bin/prep-translations.js b/bin/fetch-translations.js similarity index 100% rename from bin/prep-translations.js rename to bin/fetch-translations.js diff --git a/bin/wp-env-android.sh b/bin/wp-env-android.sh index ad2325e1a..7589f1569 100755 --- a/bin/wp-env-android.sh +++ b/bin/wp-env-android.sh @@ -71,17 +71,21 @@ else CURRENT="off" fi -echo "Android emulator URLs: $CURRENT" +echo "Android emulator URL remap — rewrites localhost to 10.0.2.2 in WordPress's" +echo "URL output so media, block assets, and REST links resolve in the emulator." +echo +echo "Status: $CURRENT" if [ "$CURRENT" = "on" ]; then - echo "WordPress emits 10.0.2.2 instead of localhost for media, block assets," - echo "and REST links." + echo "WordPress emits 10.0.2.2. Reachable from the Android emulator, but not" + echo "from a browser or the iOS Simulator." else - echo "WordPress emits localhost URLs, reachable from a browser and the iOS" - echo "Simulator." + echo "WordPress emits localhost. Reachable from a browser and the iOS Simulator," + echo "but not from the Android emulator." fi if [ -n "$MODE" ]; then + echo echo "Rebuild the Android app to pick up the change." else if [ "$CURRENT" = "on" ]; then @@ -91,5 +95,5 @@ else fi echo - echo "To change it: make wp-env-android-urls MODE=$OTHER" + echo "To change it: make wp-env-config-android-urls MODE=$OTHER" fi diff --git a/docs/code/development-tools.md b/docs/code/development-tools.md index 1be716043..3ac363102 100644 --- a/docs/code/development-tools.md +++ b/docs/code/development-tools.md @@ -23,7 +23,7 @@ The [React Developer Tools](https://react.dev/learn/react-developer-tools) allow 1. Start the standalone DevTools server: ```bash - make dev-tools + make start-devtools ``` This opens a standalone window that will display your React component tree. @@ -31,7 +31,7 @@ The [React Developer Tools](https://react.dev/learn/react-developer-tools) allow 2. Start the development server: ```bash - make dev-server + make serve-dev ``` 3. For Android emulators only, set up port forwarding: diff --git a/docs/code/getting-started.md b/docs/code/getting-started.md index b93eb7646..cf971280f 100644 --- a/docs/code/getting-started.md +++ b/docs/code/getting-started.md @@ -19,7 +19,7 @@ To see all available development commands, run `make help` (or simply `make`) in Install the GutenbergKit dependencies and start the development server by running the following command in your terminal: ```bash -make dev-server +make serve-dev ``` Once finished, the web app can now be accessed in your browser by visiting the URL logged in your terminal. However, it is **recommended to use a native host app for testing** changes made to the editor for a more realistic experience. A demo app is included in the GutenbergKit project, along with instructions on how to use it below. @@ -32,7 +32,7 @@ This demo app is useful for quickly testing changes made to the editor. The iOS demo app loads the development server by default. -1. Start the development server by running `make dev-server`. +1. Start the development server by running `make serve-dev`. 1. Launch Xcode and open the `ios/Demo-iOS/Gutenberg.xcodeproj` project. 1. Select the `Gutenberg` target. 1. Run the app. @@ -50,7 +50,7 @@ Alternatively, you can load a production build of the web app bundled with the G The Android demo app loads the production build of the web app bundled with the GutenbergKit package by default—i.e., the output of the project's `make build` command. It can be configured to load the development server by setting a `GUTENBERG_EDITOR_URL` environment variable in the `android/local.properties` file. -1. Start the development server by running `make dev-server`. +1. Start the development server by running `make serve-dev`. 1. Launch Android Studio and open the `android` project. 1. Modify the `android/local.properties` file to include an environment variable named `GUTENBERG_EDITOR_URL` with the development server URL. 1. Run the app on an emulator. diff --git a/docs/code/local-wordpress.md b/docs/code/local-wordpress.md index 6b9665c83..be26736c5 100644 --- a/docs/code/local-wordpress.md +++ b/docs/code/local-wordpress.md @@ -26,15 +26,15 @@ Once started, the **"Local WordPress"** option in both the iOS and Android demo ## Available Commands -| Command | Description | -| --------------------------------------- | ------------------------------------------------------------- | -| `make wp-env-start` | Start the environment and provision credentials | -| `make wp-env-stop` | Stop the environment | -| `make wp-env-clean` | Remove downloaded WordPress, plugin, and theme files | -| `make wp-env-android-urls` | Report whether WordPress emits emulator-reachable URLs | -| `make wp-env-android-urls MODE=on\|off` | Emit `10.0.2.2` URLs for the Android emulator, or `localhost` | +| Command | Description | +| ---------------------------------------------- | ------------------------------------------------------------- | +| `make wp-env-start` | Start the environment and provision credentials | +| `make wp-env-stop` | Stop the environment | +| `make wp-env-clean` | Remove downloaded files and cached credentials | +| `make wp-env-config-android-urls` | Report whether WordPress emits emulator-reachable URLs | +| `make wp-env-config-android-urls MODE=on\|off` | Emit `10.0.2.2` URLs for the Android emulator, or `localhost` | -The site is rebuilt from scratch on every start, so stopping the environment discards any content you created. Use `make wp-env-clean` when you also want to remove the downloaded WordPress, plugin, and theme files. +The site is rebuilt from scratch on every start, so stopping the environment discards any content you created. Use `make wp-env-clean` when you also want to remove the downloaded WordPress, plugin, and theme files, along with `.wp-env.credentials.json`. ## How It Works @@ -87,7 +87,7 @@ The credentials remap above covers the site URL the app connects to. It does not To remap them, enable the URL override: ```bash -make wp-env-android-urls MODE=on +make wp-env-config-android-urls MODE=on ``` This installs a mu-plugin (`gutenbergkit-android-urls.php`) that rewrites `localhost` and `127.0.0.1` to `10.0.2.2` in WordPress's URL output. The mu-plugins directory is mounted into the running server, so the change applies immediately — no restart, and existing credentials keep working. @@ -97,7 +97,7 @@ Rebuild the Android app afterwards. This is needed for the URL change itself, no To revert (for browser access or iOS testing): ```bash -make wp-env-android-urls MODE=off +make wp-env-config-android-urls MODE=off ``` Run it with no `MODE` to report the current setting. @@ -105,7 +105,7 @@ Run it with no `MODE` to report the current setting. Two things to be aware of while the override is active: - The WordPress admin dashboard (`http://localhost:8888/wp-admin/`) redirects to `10.0.2.2`, which doesn't resolve in a desktop browser. -- The `/wp/v2/settings` endpoint still reports `url` as `localhost`, because that field reads the stored option directly rather than passing through the `site_url` and `home_url` filters. It is not a reliable way to check whether the override is on — use `make wp-env-android-urls` instead. +- The `/wp/v2/settings` endpoint still reports `url` as `localhost`, because that field reads the stored option directly rather than passing through the `site_url` and `home_url` filters. It is not a reliable way to check whether the override is on — use `make wp-env-config-android-urls` instead. ### Physical Devices diff --git a/docs/code/physical-device-setup.md b/docs/code/physical-device-setup.md index 5a081dd06..98430d3bf 100644 --- a/docs/code/physical-device-setup.md +++ b/docs/code/physical-device-setup.md @@ -13,7 +13,7 @@ When running the demo app on a physical device, the device needs to access the d ## Prerequisites - Your physical device and development machine must be on the same network -- The development server must be running (`make dev-server`) +- The development server must be running (`make serve-dev`) - You need to know your development machine's IP address ### Finding Your Development Machine's IP Address @@ -40,7 +40,7 @@ Look for your local network IP address (typically in the format `192.168.x.x` or ## iOS Configuration -1. Start the development server by running `make dev-server`. +1. Start the development server by running `make serve-dev`. 2. Launch Xcode and open the `ios/Demo-iOS/Gutenberg.xcodeproj` project. 3. Select the `Gutenberg` target. 4. Navigate to _Product_ → _Scheme_ → _Edit Scheme_. @@ -57,7 +57,7 @@ Look for your local network IP address (typically in the format `192.168.x.x` or ### 1. Configure the Editor URL -1. Start the development server by running `make dev-server`. +1. Start the development server by running `make serve-dev`. 2. Launch Android Studio and open the `android` project. 3. Modify the `android/local.properties` file to include an environment variable named `GUTENBERG_EDITOR_URL` with your development machine's IP address and port. - Example: `GUTENBERG_EDITOR_URL=http://192.168.1.100:5173/` diff --git a/docs/code/testing.md b/docs/code/testing.md index f41abe203..ecfd2a1fa 100644 --- a/docs/code/testing.md +++ b/docs/code/testing.md @@ -13,19 +13,19 @@ Important, high-level test cases are [documented](../test-cases.md) for manual t Test files follow the `*.test.{js,jsx}` naming convention. ```bash -make test-js +make test-web-unit ``` ### Swift (Swift Testing) ```bash -make test-swift-package +make test-ios-library-simulator ``` ### Android (JUnit) ```bash -make test-android +make test-android-library-unit ``` ## E2E Tests @@ -41,13 +41,13 @@ Locally, Playwright starts the Vite dev server (`npm run dev` on `:5173`) and re Run tests: ```bash -make test-e2e +make test-web-e2e ``` Run in interactive UI mode: ```bash -make test-e2e-ui +make test-web-e2e-ui ``` ### iOS E2E Tests (XCUITest) @@ -66,20 +66,20 @@ Uses the Vite dev server for faster iteration — no production build required. ```bash # Terminal 1 -make dev-server +make serve-dev # Terminal 2 -make test-ios-e2e-dev +make test-ios-app-e2e-dev ``` This sets `TEST_RUNNER_GUTENBERG_EDITOR_URL`, which `xcodebuild` forwards to the test runner process (with the `TEST_RUNNER_` prefix stripped). The test setup then passes `GUTENBERG_EDITOR_URL` to the app under test via `launchEnvironment`, so the WebView loads from `http://localhost:5173` instead of the bundled assets. #### Production build (CI) -Uses the production JS bundle built by Vite. This is what CI runs and is the default `make test-ios-e2e` target: +Uses the production JS bundle built by Vite. This is what CI runs and is the default `make test-ios-app-e2e` target: ```bash -make test-ios-e2e +make test-ios-app-e2e ``` The target depends on `build` and will handle it automatically. @@ -88,8 +88,8 @@ The target depends on `build` and will handle it automatically. The mode is controlled by the `GUTENBERG_EDITOR_URL` environment variable. When set, `EditorViewController` loads from that URL; otherwise it loads from the bundled `index.html`. -- `make test-ios-e2e-dev` — sets `TEST_RUNNER_GUTENBERG_EDITOR_URL=http://localhost:5173` and checks that the dev server is running before starting. -- `make test-ios-e2e` — does not set the variable; runs a production build first. +- `make test-ios-app-e2e-dev` — sets `TEST_RUNNER_GUTENBERG_EDITOR_URL=http://localhost:5173` and checks that the dev server is running before starting. +- `make test-ios-app-e2e` — does not set the variable; runs a production build first. You can also pass the variable directly if you need a custom URL: @@ -117,8 +117,8 @@ Lint JavaScript code using ESLint: ```bash # Auto-fix linting errors -make lint-js-fix +make lint-web-fix # Verify linting passes -make lint-js +make lint-web ``` diff --git a/docs/code/troubleshooting.md b/docs/code/troubleshooting.md index 3ff4f70dc..c7fae8582 100644 --- a/docs/code/troubleshooting.md +++ b/docs/code/troubleshooting.md @@ -24,8 +24,8 @@ The file does not exist at "[path]" which is in the optimize deps directory. The **Solution:** Clear Vite's cache by either: -- Stopping the development server and restarting it via the `make dev-server-force` command to force Vite to re-bundle dependencies. -- Deleting the `node_modules/.vite` directory (or `node_modules` entirely) and restarting the development server via `make dev-server`. +- Stopping the development server and restarting it via the `make serve-dev-force` command to force Vite to re-bundle dependencies. +- Deleting the `node_modules/.vite` directory (or `node_modules` entirely) and restarting the development server via `make serve-dev`. You may also need to clear your browser cache to ensure no stale files are used. diff --git a/ios/Demo-iOS/Sources/Views/EditorList.swift b/ios/Demo-iOS/Sources/Views/EditorList.swift index d637858be..3aa95152c 100644 --- a/ios/Demo-iOS/Sources/Views/EditorList.swift +++ b/ios/Demo-iOS/Sources/Views/EditorList.swift @@ -20,7 +20,7 @@ struct EditorList: View { } } header: { if ProcessInfo.processInfo.environment["GUTENBERG_EDITOR_URL"] != nil { - Text("Note: Editors are using the dev server started with `make dev-server`.") + Text("Note: Editors are using the dev server started with `make serve-dev`.") .textCase(nil) .font(.footnote) .foregroundStyle(.secondary) diff --git a/package.json b/package.json index 2ffca911e..d48471969 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ "dev:tools": "react-devtools", "build": "vite --emptyOutDir build", "check:wp-packages": "node bin/check-wordpress-package-duplicates.js", + "fetch-translations": "node bin/fetch-translations.js", "format": "prettier --write .", "generate-version": "node bin/generate-version.js", "lint:js": "eslint . --report-unused-disable-directives --max-warnings 0", "lint:js:fix": "eslint . --report-unused-disable-directives --max-warnings 0 --fix", "postinstall": "patch-package --error-on-warn && npm run generate-version", - "prep-translations": "node bin/prep-translations.js", "preview": "vite preview --host", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui",