diff --git a/AGENTS.md b/AGENTS.md index a4af752c04..52fa230c4e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ newspack-workspace is the Newspack monorepo. It contains all product plugins, th - `plugins//` - Product plugins (12 total). - `themes//` - Themes (newspack-theme, newspack-block-theme). - `packages//` - Shared libraries (scripts, components, colors, icons). -- `repos/plugins//`, `repos/themes//` - Standalone/local plugin and theme checkouts that live outside the monorepo (e.g. private or customer-specific plugins, `newspack-manager`, licensed WooCommerce extensions). The `repos/plugins` and `repos/themes` directories are tracked (`.gitkeep`); anything you drop inside them is gitignored. Mounted at `/newspack-repos` and symlinked into the active site (`wp-content/plugins/`, `wp-content/themes/`) by `bin/link-repos.sh`. **Any directory works with no registration** - `n` commands (`n build`, `n composer`, `n watch`, cwd-detection) discover `repos/` checkouts by path, so there's no need to edit `bin/repos.sh`. If a name also exists in the monorepo `plugins/`/`themes/`, the **tracked copy wins** and the `repos/` duplicate is skipped. Workflow: drop a real checkout in (clone/unzip directly, or `git worktree add`), build it, then `n restart`/`n start` to pick it up. A symlink *inside* `repos/` pointing outside the workspace will dangle in the container - use a real directory. +- `repos/plugins//`, `repos/themes//` - Standalone/local plugin and theme checkouts that live outside the monorepo (e.g. private or customer-specific plugins, `newspack-manager`, licensed WooCommerce extensions). The `repos/plugins` and `repos/themes` directories are tracked (`.gitkeep`); anything you drop inside them is gitignored. Mounted at `/newspack-repos` and symlinked into the active site (`wp-content/plugins/`, `wp-content/themes/`) by `bin/link-repos.sh`. **Any directory works with no registration** - `n` commands (`n build`, `n composer`, `n watch`, cwd-detection) discover `repos/` checkouts by path, so there's no need to edit `bin/repos.sh`. If a name also exists in the monorepo `plugins/`/`themes/`, the **tracked copy wins** and the `repos/` duplicate is skipped. Workflow: drop a real checkout in (clone/unzip directly, or `git worktree add`), build it, then `n restart`/`n start` to pick it up. A symlink *inside* `repos/` pointing outside the workspace will dangle in the container - use a real directory. For the two private, non-monorepo plugins every install needs (`newspack-manager`, `newspack-manager-admin`), `n setup-repos` clones and builds them into `repos/plugins/` in one shot - see [First-Time Setup](#first-time-setup). Each directory is a standalone WordPress plugin/theme that can be zipped and installed independently. @@ -125,9 +125,20 @@ cp default.env .env # Create local config n start # Launch containers n install # Install WordPress n ci-build all # Build all projects +n setup-repos # Clone + build the private managed plugins (optional) n setup --yes # Bootstrap site with content and plugins ``` +`n setup-repos` pulls in the two plugins that can't live in this monorepo because +they're in separate private repos: `newspack-manager` and `newspack-manager-admin`. +It clones them into `repos/plugins/` (auth via the GitHub CLI, so `gh auth login` +first), skipping any that are already present, then builds each through the same +standalone-repo path as `n build ` and symlinks them into the running site +via `bin/link-repos.sh` - so they show up in the plugins list ready to activate, +no restart needed. Pass `--env ` to build and link into an isolated +environment instead of the main site. Omit this step if you don't need the +Manager plugins locally. + ### Building Projects ```bash n build # Build current project (from within repo folder) diff --git a/bin/env.sh b/bin/env.sh index 6b71f1e6fb..4a4fd3ff79 100755 --- a/bin/env.sh +++ b/bin/env.sh @@ -200,6 +200,7 @@ services: - .:/newspack-monorepo - ./plugins:/newspack-plugins - ./themes:/newspack-themes + - ./repos:/newspack-repos ${worktree_volumes} - ./envs/${env_name}/html:/var/www/html - ./manager-html:/var/www/manager-html - ./additional-sites-html:/var/www/additional-sites-html diff --git a/bin/repos.sh b/bin/repos.sh index 78892d5dd1..5b06c25dd9 100755 --- a/bin/repos.sh +++ b/bin/repos.sh @@ -23,6 +23,14 @@ newspack_themes=( "newspack-block-theme" ) +# Plugins that live in their own private repos outside this monorepo, so a fresh +# checkout has no copy of them. `n setup-repos` clones these into repos/plugins/ +# (auth via gh) where the standard repos/ convention picks them up. +managed_plugins=( + "newspack-manager" + "newspack-manager-admin" +) + woocommerce_plugins=( "woocommerce" "woocommerce-gateway-stripe" diff --git a/bin/setup-repos.sh b/bin/setup-repos.sh new file mode 100755 index 0000000000..a7b5f810c2 --- /dev/null +++ b/bin/setup-repos.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# +# Clone the non-monorepo "managed" plugins (newspack-manager, +# newspack-manager-admin) into repos/plugins/ for local development. +# +# These plugins live in private Automattic repos and can't be tracked in this +# monorepo, so a fresh checkout has no copy of them. This pulls them in one +# shot via the GitHub CLI (which carries your auth for the private repos), +# idempotently: an existing checkout is left untouched. +# +# Cloning only -- building and symlinking are handled by the caller +# (`n setup-repos`) through the standard build-repos.sh / link-repos.sh paths, +# the same ones `n build ` and container startup use. +# +# Usage: n setup-repos + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +source "$SCRIPT_DIR/repos.sh" + +if ! command -v gh &>/dev/null; then + echo "Error: the GitHub CLI (gh) is required to clone the private managed repos." >&2 + echo "Install it from https://cli.github.com/, then run 'gh auth login'." >&2 + exit 1 +fi + +DEST="$ROOT_DIR/repos/plugins" +mkdir -p "$DEST" + +for name in "${managed_plugins[@]}"; do + target="$DEST/$name" + if [ -d "$target" ]; then + echo "✓ $name already present in repos/plugins/, skipping clone." + continue + fi + echo "Cloning Automattic/$name into repos/plugins/$name..." + gh repo clone "Automattic/$name" "$target" +done diff --git a/n b/n index 3cfa3d9b0c..22a8894825 100755 --- a/n +++ b/n @@ -454,6 +454,34 @@ case $1 in setup-newspack-network) docker exec $DOCKER_IT $USER_COMMAND $TARGET_CONTAINER sh -c "/var/scripts/setup-newspack-network.sh" ;; + setup-repos) + shift + repos_container="$TARGET_CONTAINER" + while [[ $# -gt 0 ]]; do + if [[ "$1" == "--env" ]]; then + if [[ $# -lt 2 || "$2" == --* ]]; then + echo "Error: --env requires an environment name." >&2 + echo "Usage: n setup-repos [--env ENV_NAME]" >&2 + exit 1 + fi + repos_container=$(echo "newspack_env_${2}" | tr '-' '_') + shift 2 + else + echo "Unknown argument: $1" >&2 + echo "Usage: n setup-repos [--env ENV_NAME]" >&2 + exit 1 + fi + done + # Clone happens on the host (gh carries the auth for the private repos) + # into the shared repos/plugins/ dir; build + symlink happen in the + # container via the standard repos/ paths. Abort if the clone failed so + # we don't try to build a checkout that isn't there. + "$NABSPATH/bin/setup-repos.sh" || exit $? + for managed in "${managed_plugins[@]}"; do + docker exec $DOCKER_IT $USER_COMMAND "$repos_container" sh -c "/var/scripts/build-repos.sh $managed" + done + docker exec $DOCKER_IT $USER_COMMAND "$repos_container" sh -c "/var/scripts/link-repos.sh" + ;; worktree) "$NABSPATH/bin/worktree.sh" "${@:2}" ;; @@ -508,6 +536,8 @@ case $1 in echo " setup-newspack-network Set up Newspack Network Docker environment." echo "" echo "Repository Management:" + echo " setup-repos [--env name] Clone the private managed plugins (newspack-manager," + echo " newspack-manager-admin) into repos/plugins/ and build them." echo " pull Pull the latest changes for all repositories." echo " branch [name] Switch all repositories to the specified branch." echo " trunk Switch all repositories to the trunk branch."