Polishing the detail page is complete, bug #65 #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI/CD | |
| on: | |
| pull_request: | |
| branches: [main] | |
| push: | |
| branches: [main] | |
| # Cancel outdated pull request runs to save runner time and energy. Runs on | |
| # main are never cancelled, so a deploy is not stopped halfway; a newer | |
| # merge waits for the running one instead. | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| # Apache serves this folder at /project2 (see docs/ci-cd.md). | |
| WEB_DIR: /var/www/html/project2 | |
| # The backend runs from here, outside the runner's work folder, which is | |
| # wiped by the next checkout. | |
| APP_DIR: /srv/ufound-it | |
| SERVICE: ufound-it-backend | |
| jobs: | |
| # The job keeps its name since branch protection requires a check named | |
| # "checks". Pull requests only run this job. | |
| checks: | |
| runs-on: self-hosted | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| # npm ci installs exactly what package-lock.json says, so CI matches | |
| # what we run locally. | |
| - run: npm ci | |
| - run: npm run lint | |
| - run: npm run format:check | |
| - run: npm test | |
| - run: npm run build | |
| # A separate job so it can belong to the "production" environment, which | |
| # makes GitHub list each deploy, which commit is live, and the site URL. | |
| # A new job starts from a fresh checkout, so it installs and builds again. | |
| deploy: | |
| needs: checks | |
| if: github.event_name == 'push' | |
| runs-on: self-hosted | |
| environment: | |
| name: production | |
| url: http://it2810-25.idi.ntnu.no/project2/ | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - run: npm ci | |
| - run: npm run build | |
| - name: Deploy frontend | |
| run: | | |
| find "$WEB_DIR" -mindepth 1 -delete | |
| cp -r frontend/dist/. "$WEB_DIR"/ | |
| - name: Deploy backend | |
| run: | | |
| # npm ci needs the workspace layout, so both package.json files are | |
| # copied even though only the backend runs here. backend/.env is | |
| # created once by hand on the VM and is left alone. | |
| mkdir -p "$APP_DIR/backend" "$APP_DIR/frontend" | |
| cp package.json package-lock.json "$APP_DIR"/ | |
| cp backend/package.json "$APP_DIR/backend/" | |
| cp frontend/package.json "$APP_DIR/frontend/" | |
| rm -rf "$APP_DIR/backend/dist" | |
| cp -r backend/dist "$APP_DIR/backend/" | |
| (cd "$APP_DIR" && npm ci --omit=dev --workspace backend) | |
| # Node is only installed in the runner's tool cache, so the service | |
| # gets its own copy of the same version CI tested with. Renaming | |
| # over the old binary works while the service is still running it. | |
| cp "$(command -v node)" "$APP_DIR/node.new" | |
| mv -f "$APP_DIR/node.new" "$APP_DIR/node" | |
| sudo -n systemctl restart "$SERVICE" | |
| - name: Check the deployed site | |
| run: | | |
| graphql() { | |
| curl -fsS http://localhost/project2/graphql \ | |
| -H 'content-type: application/json' \ | |
| --data "{\"query\":\"$1\"}" | |
| } | |
| # The backend needs a moment to start, so retry before failing. | |
| for attempt in 1 2 3 4 5 6 7 8 9 10; do | |
| if graphql '{ health }' | grep -q '"ok"'; then | |
| break | |
| fi | |
| if [ "$attempt" = 10 ]; then | |
| echo "The backend did not answer through Apache." >&2 | |
| sudo -n systemctl status "$SERVICE" --no-pager || true | |
| exit 1 | |
| fi | |
| sleep 2 | |
| done | |
| # health does not touch the database, so a wrong password in .env | |
| # or a stopped MySQL only shows up in a real query. | |
| result=$(graphql '{ sightings(first: 1) { totalCount } }') | |
| if ! echo "$result" | grep -q '"totalCount"'; then | |
| echo "The backend is up but cannot read sightings: $result" >&2 | |
| exit 1 | |
| fi | |
| curl -fsS -o /dev/null http://localhost/project2/ | |
| echo "Deployed and responding." |