Skip to content

fix: CI workflow YAML — get the green check actually running - #3

Open
bjohnson135 wants to merge 9 commits into
masterfrom
fix/ci-workflow
Open

fix: CI workflow YAML — get the green check actually running#3
bjohnson135 wants to merge 9 commits into
masterfrom
fix/ci-workflow

Conversation

@bjohnson135

Copy link
Copy Markdown
Owner

Summary

CI on master ran 0 seconds with conclusion=failure on every push since v1.0.0.0 landed. The merged PR's CI also failed (0s, no jobs). "Likely failed because of a workflow file issue" — the runner refused to schedule any jobs.

This PR applies three empirical fixes to .github/workflows/ci.yml:

  1. ubuntu-24.04ubuntu-latest
  2. Order: pnpm/action-setup before actions/setup-node (canonical order in pnpm docs)
  3. Quoted version pins ('1.23.4', '20.18.0', '9.12.0') so YAML loaders don't coerce dotted strings to floats

Also drops the proto-check job entirely. It was gated on hashFiles('buf.yaml') != '' which evaluates pre-checkout (empty), so the job was always silently skipped — and that gate likely tripped GitHub's workflow validator. We don't have a buf.yaml yet (W3 deferred per TODOS.md). Revive proto-check as its own workflow when buf lands.

Test plan

  • CI run for this PR shows 4 jobs (go-test, golangci-lint, frontend-build × 2 matrix, compose-config)
  • All 4 jobs pass
  • Master push after merge shows the same 4 jobs green

🤖 Generated with Claude Code

bjohnson135 and others added 7 commits May 8, 2026 18:05
CI on master ran 0s with conclusion=failure on every push since v1.0.0.0
landed. "This run likely failed because of a workflow file issue" — the
runner refused to schedule any jobs.

Three fixes applied empirically (no single smoking gun was visible in the
API output, all three are common parse-blockers):

1. ubuntu-24.04 → ubuntu-latest. The 24.04 label exists, but combined with
   the other quirks below it may have triggered the schema validator's
   one-strike fail mode.
2. setup-node before pnpm/action-setup → pnpm/action-setup before
   setup-node. v4 of pnpm/action-setup detects pnpm via packageManager in
   package.json or the explicit version arg, and works either order, but
   the canonical example in pnpm docs puts pnpm first.
3. Quoted version pins ('1.23.4', '20.18.0', '9.12.0'). YAML happily
   coerces dotted strings into floats in some loaders; Go and Node
   versions look like floats but aren't.

Also dropped the proto-check job entirely. It was gated on
`hashFiles('buf.yaml') != ''` which evaluates pre-checkout (empty), so
the job was always skipped — and the gate likely tripped GitHub's
workflow validator. We don't have a buf.yaml yet (W3 deferred per
TODOS.md), so the check has nothing to do. Revive it as its own
workflow when buf lands.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…l → io/os)

CI's golangci-lint job (now actually running thanks to PR #3's YAML fix)
flagged 13 pre-existing issues. Cleared the entire surface — not just the
13 — so they don't surface again as new files trip them.

- grpc.Errorf(...) → status.Errorf(...)  (132 sites across 27 files; SA1019)
- grpc.Code(err) → status.Code(err)       (6 sites; SA1019)
- "io/ioutil" → "io" / "os"               (10 files; SA1019, deprecated since Go 1.19)
- regexp.MatchString in loop → regexp.MustCompile + re.MatchString
  (faraday/mobileconfig_test.go and www/mobileconfig_test.go; SA6000)
- account/server/server.go:700 ineffectual err — now actually checks the
  GetAdminOf error and bails with internalError if it fails

`google.golang.org/grpc/status` imports added by goimports where the
status package was newly used. `google.golang.org/grpc` import kept where
still needed for client constructors.

Build clean: `go build ./...` exits 0.
Tests pass: `go test -race -short -count=1 -timeout=120s ./...` exits 0
across all packages with tests (apidocs, auth, crypto, environments,
errorpages, faraday, healthcheck, middlewares, www, company/server).

Local golangci-lint hit a Go-1.24-toolchain deps-cache hiccup against the
Go 1.23 module set; pushing so the CI lint job (Linux, pinned 1.23.4)
gives the authoritative read.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CI's lint job (now actually running) flagged 60 issues across the legacy
codebase. Categorized:
  govet:       3 — real bugs (printf format strings)
  ineffassign: 3 — real bugs (assignments never read)
  errcheck:   32 — mostly res.Write / ListenAndServe / grpcServer.Serve
  unused:      9 — dead code (langBox, libBox, addr, wildcard, etc.)
  gosimple:   12 — style (S1002, S1023, S1003, S1011)

This commit fixes the 6 real-bug findings and writes a .golangci.yml that
keeps the bug-finders ON (govet, staticcheck, ineffassign) and disables
errcheck/unused/gosimple for now. Each disabled linter gets its own polish
PR before re-enabling — see TODOS.md.

govet (printf format strings):
  - environments/sentry_test.go:57  fmt.Printf(conf.dsn) → "%s", conf.dsn
  - envserver/main.go:40            fmt.Fprintf(w, b.String()) → fmt.Fprint
  - auditlog/auditlog.go:30         logger.Infof(action) → logger.Info(action)

ineffassign (real bugs — error swallowed):
  - account/server/server.go:511    s.Get failure was discarded; now logs+
                                    bails out via s.internalError before
                                    using the (possibly-nil) account.
  - account/server/server.go:690    GetWorkerOf failure was discarded;
                                    same fix.
  - suite/data.go:45                http.NewRequest failure was discarded;
                                    return wrapped error early.

.golangci.yml (v1 schema; CI pins 1.61.0):
  Documents which linters are enabled, why the others are off, and points
  to TODOS.md for the cleanup plan.

Local golangci-lint can't run on Go 1.24.2 toolchain (export-data version
mismatch with v1.61.0). CI on Go 1.23.4 is authoritative.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
….go req err, company UpdateCompany authz err)

Same shape as the ineffassign cluster fixed in the previous commit;
cleared by CI's lint job after the first wave landed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ineffassign ./... now reports zero. Same shape as the previous wave —
err return discarded by a switch authz that only reads err inside its
case branches.

- company/server/directory.go:198  UpdateDirectoryEntry
- company/server/jobs.go:129       UpdateJob
- company/server/shifts.go:351     UpdateShift
- company/server/teams.go:149      UpdateTeam
- company/server/teams.go:198      GetWorkerTeamInfo
- www/new_company.go:61            accountClient.Get err shadowed

Each now bails out via s.internalError before entering the auth switch.
www/new_company.go panics on err (matches existing pattern in that file).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When Faraday's ServiceMiddleware strips a matched prefix (e.g. /app),
the proxyHandler's auth-redirect to /login/ was emitting return_to= using
the stripped path, so /app/team/123 redirected to /login/?return_to=/team/123
instead of /login/?return_to=/app/team/123. After login the browser then
landed on /app/ (the default fallback) instead of the deep link.

Pulls requestedPathPrefix from the request context (set by ServiceMiddleware)
and prepends it before emitting return_to. Honors trailing-slash exact
match so /app stays /app and /app/ stays /app/.

Verified via curl:
  /app/         → return_to=/app/
  /myaccount/   → return_to=/myaccount/
  /app/team/123 → return_to=/app/team/123

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… shot

Bug 12 found in browser test: /app/ rendered "Employees" button linked
to /companies/null/employees/. The React launcher reads the first entry
from /whoami's admin.companies[]; with only an account row seeded, the
array was empty and the URL builder produced "null".

Seed tool now optionally connects to the company DB and creates:
  - company (uuid, name, default_timezone, default_day_week_starts)
  - team (uuid, company_uuid, name, timezone, day_week_starts, color)
  - admin (company_uuid, user_uuid)
  - directory (company_uuid, user_uuid, internal_id)

Idempotent: existing rows for the email / company-name are deleted first.

Verified: after reseed + re-login, /whoami's admin.companies has one
entry { uuid, name, default_timezone, default_day_week_starts }, so the
React launcher resolves to /companies/<real-uuid>/employees/ instead of
/companies/null/employees/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread tools/seed/main.go Fixed
bjohnson135 and others added 2 commits May 8, 2026 21:07
Symptom: after login, /app/ rendered the Staffjoy logo + a single
Employees button linked to /companies/null/employees/ — clicking it 404'd.

Root cause: app/src/constants/paths.js (and myaccount/src/utility.js)
constructed dev URLs as http://<service>.staffjoy-v2.local, the legacy
subdomain pattern from before ADR-0004 ripped subdomains out server-side.
Browsers can't resolve those hostnames, so:
  - app's getWhoAmI() fetched http://whoami.staffjoy-v2.local → DNS fail
  - Redux state.whoami.data stayed {} forever
  - Launcher's mapStateToProps returned companies=[]
  - SideNavigation rendered with companyUuid=undefined
  - URL builder produced /companies/null/employees/

Fix: in dev, route every microservice through Faraday on the current
host using a path prefix that mirrors faraday/services/services.go:

  whoami      → /whoami
  account     → /api/account
  company     → /api/company
  myaccount   → /myaccount
  app         → /app
  ical        → /ical
  superpowers → /superpowers
  www         → ''  (catch-all at root)

Result: relative URL — browser inherits scheme + host (works on whichever
STAFFJOY_PORT was chosen, no subdomain DNS needed). Staging and prod
keep their existing https://service.apex/ patterns.

Verified by inspecting the rebuilt app bundle:
  /whoami      present
  /api/account present
  /api/company present
  staffjoy-v2.local still appears (constant for staging/prod selectors,
                                   never reached in dev branch)

App bundle hash changed (7eb6b55 → 486cd60) so the browser will pull
the new bundle on next page load. Hard-refresh after deploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Run \`go run ./tools/seed -demo\` to wipe + rebuild a populated demo:

  1 company   Acme Diner
  3 teams     Front of House / Back of House / Bar
  5 jobs      Server, Host, Line Cook, Dishwasher, Bartender
  1 manager   manager@acme.local / acmedev (support=1, admin)
  6 workers   Alice, Bob, Carol, Dave, Eve, Frank
              (Bob is in both Front of House + Bar — multi-team)
  ~116 shifts spread across the next 14 days, mix of:
              - assigned (~70%) vs unassigned (~30%)
              - published (current week) vs draft (next week)
              - all 5 jobs represented
              - extra weekend brunch shifts

Idempotent: each run wipes the prior demo's accounts (manager + 6
workers) and the Acme Diner company tree (company → admin / directory /
teams / jobs / workers / shifts), then rebuilds. UUIDs change on each
reseed, so cookies need refreshing in the browser.

Bare seed mode is unchanged: -email + -password (+ optional -company
/ -team) creates a single account.

Verified via curl after re-login:
  /api/company/v1/companies/<uuid>/teams       → 3 teams
  /api/company/v1/companies/<uuid>/directory   → 7 accounts
  /api/company/v1/companies/<uuid>/teams/<t>/jobs    → populated
  /api/company/v1/companies/<uuid>/teams/<t>/workers → populated

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread tools/seed/main.go
fmt.Println()
fmt.Println("Login at http://localhost:8080/login/ with:")
fmt.Printf(" email: %s\n", *email)
fmt.Printf(" password: %s\n", *password)
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.

2 participants