mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-08-31 01:14:08 +08:00
fix(devcontainer): correct the bind and port reset (#69753)
Signed-off-by: Mrugesh Mohapatra <1884376+raisedadead@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
1fb1ca975f
commit
c306144dd0
@@ -1,64 +0,0 @@
|
||||
# Develop freeCodeCamp in a container
|
||||
|
||||
The container builds itself, installs every dependency, starts MongoDB, and seeds a test user. Wait until the terminal shows `Done. Press any key to close the terminal.`
|
||||
|
||||
## Start the application
|
||||
|
||||
Choose one option:
|
||||
|
||||
- Open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`), type `Run Task`, then select **Start freeCodeCamp**.
|
||||
- Open a terminal and run:
|
||||
|
||||
```bash
|
||||
pnpm run develop
|
||||
```
|
||||
|
||||
The first build takes several minutes. VS Code shows a notification when port `8000` is ready. Open that notification to view the client.
|
||||
|
||||
To build one part of the curriculum instead of all of it, set a filter:
|
||||
|
||||
```bash
|
||||
FCC_SUPERBLOCK='responsive-web-design' pnpm run develop
|
||||
```
|
||||
|
||||
## Services
|
||||
|
||||
| Port | Service | Notes |
|
||||
| ------ | ------- | --------------------------------------- |
|
||||
| `8000` | Client | The learning platform. |
|
||||
| `3000` | API | API docs are at `/documentation`. |
|
||||
| `8025` | Mailpit | Every email the API sends arrives here. |
|
||||
|
||||
### Codespaces: port 3000 must be public
|
||||
|
||||
The client calls the API from your browser, across two different forwarded
|
||||
origins. A private port answers that call with a GitHub sign-in redirect, and
|
||||
the browser reports it as a CORS error.
|
||||
|
||||
`post-create.sh` attempts this, but the token a codespace provides does not
|
||||
carry the `codespace` scope, so the attempt usually fails. Open the **Ports**
|
||||
panel, right click port `3000`, then choose **Port Visibility > Public**. Run
|
||||
`gh auth login -s codespace` once if you want the script to do it for you.
|
||||
|
||||
A public port is reachable by anybody who has the URL, and `sample.env` sets
|
||||
`FCC_ENABLE_DEV_LOGIN_MODE=true`, which serves a sign-in route that needs no
|
||||
password. Stop the codespace when you finish working.
|
||||
|
||||
## Optional setup
|
||||
|
||||
For end-to-end tests:
|
||||
|
||||
```bash
|
||||
npx playwright install chromium
|
||||
```
|
||||
|
||||
For curriculum tests:
|
||||
|
||||
```bash
|
||||
pnpm -F=curriculum install-puppeteer
|
||||
```
|
||||
|
||||
## More information
|
||||
|
||||
For the full contribution guide, see
|
||||
https://contribute.freecodecamp.org/how-to-setup-freecodecamp-locally
|
||||
@@ -24,11 +24,14 @@
|
||||
// onCreateCommand: a prebuild snapshots the container after onCreateCommand
|
||||
// and would freeze the wrong hostname.
|
||||
"postCreateCommand": ".devcontainer/post-create.sh",
|
||||
// Codespaces resets port visibility on stop, and postCreateCommand does
|
||||
// not run again on a restart.
|
||||
"postStartCommand": ".devcontainer/post-start.sh",
|
||||
"postAttachCommand": ".devcontainer/welcome.sh",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
|
||||
"settings": {
|
||||
"task.allowAutomaticTasks": "on",
|
||||
"tasks": {
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
@@ -39,13 +42,6 @@
|
||||
"isBackground": true,
|
||||
"problemMatcher": [],
|
||||
"presentation": { "reveal": "always", "panel": "dedicated" }
|
||||
},
|
||||
{
|
||||
"label": "Open README",
|
||||
"type": "shell",
|
||||
"command": "code .devcontainer/README.md",
|
||||
"presentation": { "reveal": "silent", "close": true },
|
||||
"runOptions": { "runOn": "folderOpen" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,6 +3,13 @@ name: freecodecamp-devcontainer
|
||||
services:
|
||||
devcontainer:
|
||||
image: ghcr.io/freecodecamp/devcontainer:latest
|
||||
# gatsby develop defaults to host `localhost`. Where the network namespace
|
||||
# has IPv6, glibc RFC 6724 precedence resolves that to ::1 first, so the
|
||||
# dev server binds IPv6 loopback only and port forwarding, which connects
|
||||
# over IPv4, is refused. 0.0.0.0 needs no AF_INET6 socket, so it also holds
|
||||
# where IPv6 is switched off.
|
||||
environment:
|
||||
GATSBY_HOST: 0.0.0.0
|
||||
volumes:
|
||||
- ..:/workspaces/freeCodeCamp:cached
|
||||
# Shares the db network namespace so MONGOHQ_URL and MAILPIT_HOST in
|
||||
|
||||
@@ -3,26 +3,6 @@ set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
publish_api_port() {
|
||||
if gh codespace ports visibility 3000:public -c "$CODESPACE_NAME" >/dev/null 2>&1; then
|
||||
printf 'Port 3000 is public. The client can reach the API.\n'
|
||||
return
|
||||
fi
|
||||
cat <<'MSG'
|
||||
|
||||
Port 3000 is private, so the client cannot reach the API yet.
|
||||
The token a codespace provides does not carry the "codespace" scope, so this
|
||||
step usually needs you. Open the Ports panel, right click port 3000, then
|
||||
choose Port Visibility, then Public.
|
||||
|
||||
To let this run for you next time: gh auth login -s codespace
|
||||
|
||||
A public port is reachable by anybody who has the URL, and the development
|
||||
sign-in route needs no password. Stop the codespace when you finish working.
|
||||
|
||||
MSG
|
||||
}
|
||||
|
||||
wait_for_primary() {
|
||||
for _ in $(seq 1 30); do
|
||||
if mongosh --quiet --eval 'if (!db.hello().isWritablePrimary) quit(1)' >/dev/null 2>&1; then
|
||||
@@ -42,10 +22,6 @@ if ! wait_for_primary; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${CODESPACE_NAME:-}" ]]; then
|
||||
publish_api_port
|
||||
fi
|
||||
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
. ./.env
|
||||
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Runs on every start, including a resume. Codespaces resets port visibility
|
||||
# when a codespace stops, and postCreateCommand does not run again.
|
||||
[[ -n "${CODESPACE_NAME:-}" ]] || exit 0
|
||||
|
||||
for attempt in 1 2; do
|
||||
status=0
|
||||
err=$(timeout 20 gh codespace ports visibility 3000:public -c "$CODESPACE_NAME" 2>&1) || status=$?
|
||||
|
||||
if [[ $status -eq 0 ]]; then
|
||||
printf 'Port 3000 is public, so the client can reach the API.\n'
|
||||
printf 'Anybody with the URL can reach it, and the development sign-in\n'
|
||||
printf 'route needs no password. Stop the codespace when you finish.\n'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $status -eq 124 ]]; then
|
||||
err="gh timed out after 20 seconds"
|
||||
fi
|
||||
|
||||
if [[ $status -eq 127 ]]; then
|
||||
err="gh is not installed"
|
||||
break
|
||||
fi
|
||||
|
||||
if [[ $attempt -lt 2 ]]; then
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
|
||||
printf 'gh could not set the port: %s\n' "$err" >&2
|
||||
cat <<'MSG'
|
||||
|
||||
Port 3000 is private, so the client cannot reach the API yet.
|
||||
Open the Ports panel, right click port 3000, then choose Port Visibility,
|
||||
then Public.
|
||||
|
||||
A public port is reachable by anybody who has the URL, and the development
|
||||
sign-in route needs no password. Stop the codespace when you finish working.
|
||||
|
||||
MSG
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cat <<'MSG'
|
||||
|
||||
freeCodeCamp is ready. Dependencies are installed, MongoDB is running,
|
||||
and a test user is seeded.
|
||||
|
||||
Open a new terminal and start the development script:
|
||||
|
||||
pnpm run develop
|
||||
|
||||
Read the setup and troubleshooting guide before you begin:
|
||||
|
||||
https://contribute.freecodecamp.org/how-to-setup-freecodecamp-locally/
|
||||
|
||||
MSG
|
||||
@@ -9,6 +9,10 @@ on:
|
||||
- '.github/workflows/devcontainer-ci.yml'
|
||||
- 'sample.env'
|
||||
- 'package.json'
|
||||
- 'turbo.json'
|
||||
- 'pnpm-lock.yaml'
|
||||
- 'client/package.json'
|
||||
- 'client/turbo.json'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
@@ -76,6 +80,28 @@ jobs:
|
||||
devcontainer exec --workspace-folder . grep -q '^MAILPIT_HOST=localhost$' .env
|
||||
devcontainer exec --workspace-folder . grep -q '^HOME_LOCATION=http://localhost:8000$' .env
|
||||
|
||||
- name: Validate the client answers on IPv4 loopback
|
||||
run: |
|
||||
devcontainer exec --workspace-folder . bash -c '
|
||||
FCC_SUPERBLOCK=responsive-web-design pnpm run develop > /tmp/develop.log 2>&1 &
|
||||
pid=$!
|
||||
deadline=$((SECONDS + 2400))
|
||||
while [ "$SECONDS" -lt "$deadline" ]; do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
echo "pnpm run develop exited before the client answered"
|
||||
cat /tmp/develop.log
|
||||
exit 1
|
||||
fi
|
||||
if curl -sf -o /dev/null --max-time 10 http://127.0.0.1:8000/; then
|
||||
echo "The client answers on 127.0.0.1:8000"
|
||||
exit 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
echo "The client never answered on 127.0.0.1:8000"
|
||||
cat /tmp/develop.log
|
||||
exit 1'
|
||||
|
||||
- name: Validate the Codespaces URL rewrite
|
||||
run: |
|
||||
devcontainer exec --workspace-folder . env \
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
"outputs": ["public/**"]
|
||||
},
|
||||
"develop": {
|
||||
"env": ["FCC_*"]
|
||||
"env": ["FCC_*", "GATSBY_HOST"]
|
||||
},
|
||||
"setup": {
|
||||
"env": [
|
||||
|
||||
Reference in New Issue
Block a user