Skip to content

Scheduled Merge: dev to prod - #1602

Open
github-actions[bot] wants to merge 51 commits into
prodfrom
dev
Open

Scheduled Merge: dev to prod#1602
github-actions[bot] wants to merge 51 commits into
prodfrom
dev

Conversation

@github-actions

Copy link
Copy Markdown

Automated PR created by GitHub Actions on a semi-weekly schedule.

Owen Luts and others added 30 commits February 19, 2026 14:51
- vite.config.mjs: use classic JSX runtime so .js components qualify as
  Fast Refresh boundaries (plugin-react's automatic runtime only treats
  .jsx/.tsx as boundaries, so every edit was forcing a full page reload)
- README: document the docker dev workflow, the VITE_ vs REACT_APP_ env
  var pitfall, and the DB_HOST/DB_PORT values needed for the docker network
- restore .github/workflows/node.js.yml (deleted with no replacement),
  fixing two latent bugs: a matrix var name typo that broke node-version
  selection, and cd steps not persisting across separate run: blocks so
  builds silently ran in the repo root instead of client/server
Owen Luts and others added 21 commits August 17, 2026 15:04
…ckerterraform' into 1121-story-update-cd-to-fully-dockerterraform
deploy.yml and staging-deploy.yml export ENV_URL/STAGING_ENV_URL
secrets before building the client, but a wrong-prefixed value
(leftover REACT_APP_ from before the Vite migration) would silently
leave VITE_SERVER_URL undefined and ship a client with no API URL.
Now the build exits with a clear error instead.
Both Dockerfiles COPY . ./ after installing deps. client/.dockerignore
didn't exclude .env, and server/.dockerignore didn't exist at all, so
building locally (the now-documented dev workflow) baked DB passwords,
OAuth secrets, and session keys into an image layer that outlives the
container. Verified with real .env files present in the build context
that neither image now contains .env or .git.
Nothing previously validated that client/Dockerfile, server/Dockerfile,
or .devcontainer/docker-compose.yml still build on PRs that touch them.
Runs docker compose build on the devcontainer stack; confirmed locally
this needs no .env/secrets to succeed. Build-only by design — it won't
catch runtime/env issues (e.g. the DB_HOST or VITE_SERVER_URL bugs
found earlier this branch), only Dockerfile/dependency breakage.
- client/package-lock.json was missing the linux-x64-gnu optional
  rollup binary (npm/cli#4828 - lockfile only had darwin entries from
  being generated on macOS). This is what made the just-restored
  node.js.yml CI check fail immediately: `vite build` couldn't find
  @rollup/rollup-linux-x64-gnu on the Linux runner. Regenerated inside
  a node:20 (debian) container to match CI and confirmed `vite build`
  now succeeds there.
- server/package-lock.json was stale relative to server/package.json,
  which already declares octokit and simple-git as dependencies the
  lockfile never picked up. `npm ci` would fail on this outright.
  Verified `npm i` + eslint both work cleanly against the regenerated
  lockfile.
Addresses github-code-quality bot findings: MainFooter no longer needs
the class-component/redux imports (Component, connect, bindActionCreators,
appActions, mainActions) or the unused editPage color helpers.
VersionService, lab15's Exercise/RepairService, and 4 spots in
ImagineService were still reading process.env.REACT_APP_SERVER_URL,
which Vite never defines in the browser bundle. Switched them to
import.meta.env.VITE_SERVER_URL like the rest of the services.
CodeQL flagged the workflow for not declaring an explicit permissions
block, leaving it on the default GITHUB_TOKEN scope. It only checks
out code and builds images locally, so read-only contents access is
all it needs.
…ockerterraform

Fully Update Development to Dev Containers
The 1121 Vite/Docker migration merge dropped the prod-client pm2 app
from ecosystem.config.js and renamed client's npm "start" script away,
breaking the SSH deploy script's pm2 restart on staging (ball.rit.edu).

Restores prod-client, pointed at a new "start" script that runs Vite's
dev server on port 3000 (matching the old CRA dev-server behavior this
pm2 app relied on). Skips reintroducing configPath.js's Windows/npm
path workaround, since staging and prod both run Ubuntu.
octokit v5 is ESM-only, but VersionService.js is a CommonJS module and
was require()-ing it at the top level. app.js requires VersionService
before starting the server, so this crashed the entire backend on
boot (see prod-backend-error.log on staging).

Loads Octokit via a lazy dynamic import() instead, the supported way
to consume an ESM-only package from CommonJS.
Crashed prod-backend on boot: pg-connection-string's URL parser threw
on the literal "undefined" port, since DB_PORT was newly read directly
from env with no fallback (previously computed in code) and staging's
environment was never updated to set it.

Separately, the password var had been changed to read
POSTGRES_PASSWORD, which the README (from this same migration) documents
as the *Docker postgres image's own* init variable, distinct from the
app-facing DB_PASS the connection string is supposed to use — reverted
that back to DB_PASS.

Adds a 5432 fallback for DB_PORT, matching the old hardcoded default
for non-dev environments, so this doesn't require every deploy target
to define it going forward.
app.js required '../server/services/VersionService', a path that only
resolved by coincidence on bare-metal deploys (server/ sits one level
under the repo root, so going up and back into a sibling server/
happens to land back in the same place). Inside the devcontainer,
/app *is* the server directory directly, so there's no outer server/
to go back into and the require failed with MODULE_NOT_FOUND.

Uses the plain relative path within the same directory instead.
server/eslint.config.mjs imports "@eslint/js" directly, but the
lockfile only placed it nested under eslint's own node_modules
(node_modules/eslint/node_modules/@eslint/js), never hoisted to the
top level. Node's ESM resolution for a bare specifier from a sibling
config file only checks the top level, so any fresh `npm install`/
`npm ci` in server/ left `eslint --fix` unable to resolve it,
including through the lint-staged pre-commit hook.

Adds @eslint/js as an explicit devDependency, which is what ESLint's
own flat-config docs recommend for exactly this reason.
vite.config.mjs runs the classic JSX runtime (JSX compiles to
React.createElement calls), which requires React in scope wherever
JSX is used. 37 files across labs 12-15, the Imagine26 context, and
both the desktop and mobile footers either imported nothing from
react, only named hooks, or used the broken `import { React, ... }
from "react"` pattern (react has no named export called React, so it
silently resolved to undefined).

With no error boundary anywhere in the app, an uncaught render error
in any of these unmounts the entire React tree - mobileFooter.js and
versionComponent.js in particular render on every page, so this was a
site-wide crash for any user hitting them, not just a broken lab.

Every affected file now has a proper `import React` (default import),
alongside whatever named hooks/exports it already used.
@emotion/react and @emotion/styled are only reachable through a
lazily-loaded route (the DragIndicator icon pulled in by lab13's
ConfidenceRanking/DraggableCard). Vite only scans statically-reachable
imports at server startup, so it discovered these mid-session and
re-optimized them separately from the copy the browser already cached
from the initial scan, producing two module instances ("You are
loading @emotion/react when it is already loaded").

Adding them to optimizeDeps.include forces both into the initial
pre-bundle. Verified via the regenerated .vite/deps/_metadata.json,
which now includes both packages from the upfront scan.
The server returns an error sentinel string (e.g. "Error: Reading Not
Found"/"Error: Reading Not Retrieved") instead of a reading object
when labID doesn't resolve to a lab with content. Reading.js assumed
data[0] was always a real object and crashed trying to read .piechart
off of the resulting undefined (strings don't have a .reading
property, so data[0].reading was undefined, and .piechart on that
threw).

Now checks data[0]?.reading up front and bails out with a logged
error instead of crashing when the server didn't return real content.
…uiz routes

<Reading> was missing labID and isImagine (its sibling <About> routes
still had labID={lab}), so LabService.getLabReading was always called
with labID=undefined - the server then queried "WHERE id = 'undefined'",
which Postgres rejects, producing the "Error: Reading Not Retrieved"
sentinel that the previous commit stopped from crashing but didn't
explain.

Separately, renderLabs() was missing all 16 ExerciseLabN routes plus
Reinforcement and Quiz entirely (confirmed via eslint flagging all of
those imports and the quiz state vars as unused) - every lab's actual
exercise, reinforcement, and quiz page fell through to the <Error
default /> fallback instead of rendering. Restored all of them
matching the props from the last known-working version of this
branch. Verified live: /Lab1/Exercise, /Lab1/Reinforcement,
/Lab1/Quiz, and /Lab15/Exercise all render real content now.

Also dropped the now-unused ScrollWrapper import, which was blocking
the pre-commit lint gate.
The sweep that found the previous 37 files had two blind spots: it
required a JSX tag's attributes to start on the same line as the tag
(missed Lab15Context.js's multi-line <ExerciseStateContext.Provider>),
and it only checked .js files (missed TicTacToeButton.jsx). A
corrected, broader sweep across .js and .jsx found these plus
UserPfp.js and RenderTextWithHighlight.js, which had no react import
at all. Re-ran the sweep afterward across the whole tree - clean.

Lab15Context.js was the actual reported crash (ExerciseStateProvider
on /Lab15/Exercise); verified fixed live in the browser.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant