Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ Additional logs in workspace:
- `drupal-core/template.tf` - Drupal core development template (most actively developed)
- `drupal-contrib/template.tf` - Drupal contributed module development template
- `freeform/template.tf` - Multi-project freeform workspace template (keeps ddev-router)
- `image/scripts/.ddev/commands/host/launch` - Shared `ddev launch` override for all templates. Honors `DDEV_DEBUG`/`DDEV_VERBOSE` (prints `FULLURL <url>` and exits, matching stock ddev's contract used by tooling). For interactive use, branches on `ddev describe -j`'s `.raw.router_disabled`: freeform (router enabled) reads the per-project `coder-routes` Traefik config; drupal-core/drupal-contrib (router disabled, direct port bind) construct the named-app URL directly from the `ddev-web`/`mailpit` `coder_app` slugs — no Traefik file needed.
- `image/Dockerfile` - Base image build instructions (shared by all templates)
- `image/scripts/.ddev/global_config.yaml` - DDEV defaults copied into workspaces
- `scripts/coder-delete-workspace-dir.sh` - Sudo wrapper for workspace host dir cleanup (must be installed on server)
Expand Down
103 changes: 79 additions & 24 deletions image/scripts/.ddev/commands/host/launch
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,64 @@
## Example: "ddev launch" or "ddev launch /admin" or "ddev launch -m"
## Flags: [{"Name":"mailpit","Shorthand":"m","Usage":"ddev launch -m shows the Mailpit URL"}]

# Parse flags/path before anything else, so both the DDEV_DEBUG branch below
# and the interactive branches further down agree on the same target.
MAILPIT=false
PATH_SUFFIX=""

while :; do
case ${1:-} in
-m | --mailpit | --mailhog)
MAILPIT=true
;;
--) shift; break ;;
-?*) printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2 ;;
*) break ;;
esac
shift
done

if [ -n "${1:-}" ]; then
PATH_SUFFIX="/${1#/}"
fi

# Tooling (bats tests, `ddev launch | awk '/FULLURL/ {print $2}'`, DDEV's own
# TestLaunchCommand) sets DDEV_DEBUG/DDEV_VERBOSE to get a single parseable
# line instead of the interactive URL listing below. Match the stock ddev
# launch script's contract: FULLURL is DDEV_PRIMARY_URL with the same
# path/mailpit adjustment the interactive branches apply, since tooling runs
# inside the workspace where *.ddev.site resolves directly (unlike a human's
# browser, which needs the external Coder proxy URL built further down).
if [ "${DDEV_DEBUG:-}" = "true" ] || [ "${DDEV_VERBOSE:-}" = "true" ]; then
FULLURL="${DDEV_PRIMARY_URL}"
if [ "${MAILPIT}" = "true" ]; then
if [ "${FULLURL%://*}" = "https" ]; then
FULLURL="${FULLURL%:[0-9]*}:${DDEV_MAILPIT_HTTPS_PORT}"
else
FULLURL="${FULLURL%:[0-9]*}:${DDEV_MAILPIT_PORT}"
fi
else
FULLURL="${FULLURL%/}${PATH_SUFFIX}"
fi
echo "FULLURL ${FULLURL}"
exit 0
fi

# Emit an OSC 8 hyperlink when stdout is a terminal that supports it (VS Code's
# integrated terminal does), so the URL is clickable even though we can't
# actually launch a browser from inside the workspace container. Terminals
# that don't understand OSC 8 just show the plain URL text.
hyperlink() {
if [ -t 1 ]; then
printf '\033]8;;%s\033\\%s\033]8;;\033\\' "$1" "$1"
else
printf '%s' "$1"
fi
}

# Outside a Coder workspace fall back to a basic URL print (no browser available in DinD)
if [ -z "${CODER_WORKSPACE_NAME:-}" ] || ([ -z "${VSCODE_PROXY_URI:-}" ] && [ -z "${CODER_AGENT_URL:-}" ]); then
echo "Primary URL: ${DDEV_PRIMARY_URL:-unknown}"
echo "Primary URL: $(hyperlink "${DDEV_PRIMARY_URL:-unknown}")"
echo "(Not running in a Coder workspace; cannot open a browser.)"
exit 0
fi
Expand All @@ -25,23 +80,23 @@ fi
PROJECT="${DDEV_SITENAME}"
AGENT="${CODER_AGENT_NAME:-main}"

MAILPIT=false
PATH_SUFFIX=""

while :; do
case ${1:-} in
-m | --mailpit | --mailhog)
MAILPIT=true
;;
--) shift; break ;;
-?*) printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2 ;;
*) break ;;
esac
shift
done

if [ -n "${1:-}" ]; then
PATH_SUFFIX="/${1#/}"
# drupal-core/drupal-contrib omit ddev-router and bind the web container directly
# to a fixed host port, so there's no Traefik merged config for coder-routes to
# read. They register fixed `coder_app` slugs (ddev-web, mailpit) instead, whose
# subdomain URLs follow Coder's named-app pattern (no agent segment, since these
# templates define a single agent) — see docs/reference/coder-url-patterns.md.
ROUTER_DISABLED=$(ddev describe -j 2>/dev/null | jq -r '.raw.router_disabled // false')

if [ "$ROUTER_DISABLED" = "true" ]; then
if [ "${MAILPIT}" = "true" ]; then
echo "$(hyperlink "https://mailpit--${WORKSPACE}--${OWNER}.${DOMAIN}")"
exit 0
fi
echo ""
echo "Coder URL for project '${PROJECT}':"
echo " Web: $(hyperlink "https://ddev-web--${WORKSPACE}--${OWNER}.${DOMAIN}${PATH_SUFFIX}")"
echo ""
exit 0
fi

# Per-project routes file (written by ddev coder-routes after each ddev start).
Expand All @@ -60,12 +115,12 @@ if [ "${MAILPIT}" = "true" ]; then
mailpit_rule=$(yq e ".http.routers.\"${PROJECT}-coder-mailpit-${PROJECT_SLUG}\".rule // \"\"" "$CODER_ROUTES" 2>/dev/null)
if [ -n "$mailpit_rule" ] && [ "$mailpit_rule" != "null" ]; then
host=$(echo "$mailpit_rule" | sed -E 's/Host\(`(.+)`\)/\1/')
echo "https://${host}"
echo "$(hyperlink "https://${host}")"
exit 0
fi
fi
# fallback
echo "https://mailpit-${PROJECT_SLUG}--${WORKSPACE}--${OWNER}.${DOMAIN}"
echo "$(hyperlink "https://mailpit-${PROJECT_SLUG}--${WORKSPACE}--${OWNER}.${DOMAIN}")"
exit 0
fi

Expand Down Expand Up @@ -94,15 +149,15 @@ while IFS= read -r router; do
# Extract hostname from Host(`...`) — these use Coder subdomain proxy
host=$(echo "$rule" | sed -E 's/Host\(`(.+)`\)/\1/')
if [ "$router" = "$WEB_ROUTER" ]; then
WEB_LINE=" Web: https://${host}${PATH_SUFFIX}"
WEB_LINE=" Web: $(hyperlink "https://${host}${PATH_SUFFIX}")"
elif [ "$slug" = "mailpit" ]; then
MAILPIT_LINE=" Mailpit: https://${host}"
MAILPIT_LINE=" Mailpit: $(hyperlink "https://${host}")"
else
OTHER_LINES="${OTHER_LINES} ${slug}: https://${host}\n"
OTHER_LINES="${OTHER_LINES} ${slug}: $(hyperlink "https://${host}")\n"
fi
else
# PathPrefix rule — dynamic add-on, accessible via Coder port-forwarding URL
OTHER_LINES="${OTHER_LINES} ${slug}: https://${ext_port}--${AGENT}--${WORKSPACE}--${OWNER}.${DOMAIN}\n"
OTHER_LINES="${OTHER_LINES} ${slug}: $(hyperlink "https://${ext_port}--${AGENT}--${WORKSPACE}--${OWNER}.${DOMAIN}")\n"
fi
done < <(yq e '.http.routers | keys | .[]' "$CODER_ROUTES" 2>/dev/null)

Expand Down
Loading