-
Notifications
You must be signed in to change notification settings - Fork 0
[codex] promote dev workflow cleanup to main #77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
60bcf61
68908b5
d453f70
859b7f1
8c7c938
abf8c97
888ca50
41b65e7
7f91978
878c6e8
332446b
304d773
8cb1be6
e225080
578c5eb
da5fb27
4f92039
c9d6530
65d26af
99f74c6
a3ec41f
5c9198a
6f9d7ce
90c5ffe
bd049ee
4d7220b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| #!/usr/bin/env node | ||
| import fs from "node:fs"; | ||
| import path from "node:path"; | ||
| import { execFileSync } from "node:child_process"; | ||
|
|
||
| const args = process.argv.slice(2); | ||
| const base = args.includes("--base") ? args[args.indexOf("--base") + 1] : process.env.GITHUB_BASE_REF; | ||
| const dryRun = args.includes("--dry-run"); | ||
|
|
||
| if (!base || !["dev", "main"].includes(base)) { | ||
| console.error("Usage: node .github/scripts/pr-version-bump.mjs --base <dev|main> [--dry-run]"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| function git(args, fallback = "") { | ||
| try { | ||
| return execFileSync("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim(); | ||
| } catch { | ||
| return fallback; | ||
| } | ||
| } | ||
|
|
||
| function readJson(file) { | ||
| return JSON.parse(fs.readFileSync(file, "utf8")); | ||
| } | ||
|
|
||
| function writeJson(file, data) { | ||
| fs.writeFileSync(file, JSON.stringify(data, null, 2) + "\n"); | ||
| } | ||
|
|
||
| function bump(version) { | ||
| const parts = String(version || "0.0.0").split(".").map((part) => Number.parseInt(part, 10)); | ||
| const minor = Number.isFinite(parts[1]) ? parts[1] : 0; | ||
| const patch = Number.isFinite(parts[2]) ? parts[2] : 0; | ||
| if (base === "main") return `0.${minor + 1}.0`; | ||
| return `0.${minor}.${patch + 1}`; | ||
| } | ||
|
|
||
| function baseJson(file) { | ||
| const fromGit = git(["show", `origin/${base}:${file}`], ""); | ||
| if (!fromGit) return null; | ||
| try { | ||
| return JSON.parse(fromGit); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| function packageCandidates() { | ||
| const changed = git(["diff", "--name-only", `origin/${base}...HEAD`], "") | ||
| .split("\n") | ||
| .filter(Boolean); | ||
| const candidates = new Set(); | ||
| for (const file of changed) { | ||
| const appMatch = file.match(/^apps\/([^/]+)\//); | ||
| if (appMatch && fs.existsSync(path.join("apps", appMatch[1], "package.json"))) { | ||
| candidates.add(path.join("apps", appMatch[1], "package.json")); | ||
| } | ||
| if (file.startsWith("app/") && fs.existsSync(path.join("app", "package.json"))) { | ||
| candidates.add(path.join("app", "package.json")); | ||
| } | ||
| } | ||
| if (candidates.size === 0 && fs.existsSync("package.json")) candidates.add("package.json"); | ||
| if (candidates.size === 0 && fs.existsSync(path.join("app", "package.json"))) candidates.add(path.join("app", "package.json")); | ||
| return [...candidates]; | ||
| } | ||
|
|
||
| function updatePackage(file) { | ||
| const current = readJson(file); | ||
| const basePkg = baseJson(file) || current; | ||
| const nextVersion = bump(basePkg.version); | ||
| if (current.version === nextVersion) { | ||
| console.log(`${file} already at ${nextVersion}`); | ||
| return; | ||
| } | ||
| console.log(`${file}: ${current.version || "(none)"} -> ${nextVersion}`); | ||
| if (!dryRun) { | ||
| current.version = nextVersion; | ||
| writeJson(file, current); | ||
| } | ||
|
|
||
| const lockFile = path.join(path.dirname(file), "package-lock.json"); | ||
| if (fs.existsSync(lockFile)) { | ||
| const lock = readJson(lockFile); | ||
| if (lock.name === current.name || path.dirname(file) !== ".") lock.version = nextVersion; | ||
| if (lock.packages && lock.packages[""]) lock.packages[""].version = nextVersion; | ||
| if (!dryRun) writeJson(lockFile, lock); | ||
| } | ||
| } | ||
|
|
||
| const candidates = packageCandidates(); | ||
| if (candidates.length === 0) { | ||
| console.error("No package.json candidate found for version bump."); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| for (const candidate of candidates) updatePackage(candidate); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| name: PR Version Bump | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened, ready_for_review] | ||
| branches: | ||
| - dev | ||
| - main | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: read | ||
|
|
||
| jobs: | ||
| version-bump: | ||
| if: ${{ github.event.pull_request.draft == false }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Reject forked PR writeback | ||
| if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} | ||
| run: | | ||
| echo "PR version bump writes back to same-repo branches only. Please apply the expected package.json version bump manually for forked PRs." | ||
| exit 1 | ||
|
|
||
| - name: Check out PR branch | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.ref }} | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Fetch base branch | ||
| run: git fetch origin ${{ github.base_ref }} --depth=1 | ||
|
|
||
| - name: Apply expected version bump | ||
| run: node .github/scripts/pr-version-bump.mjs --base ${{ github.base_ref }} | ||
|
|
||
| - name: Commit version bump | ||
| run: | | ||
| if git diff --quiet; then | ||
| echo "Version already matches expected bump." | ||
| exit 0 | ||
| fi | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| git add package.json package-lock.json app/package.json app/package-lock.json apps/*/package.json apps/*/package-lock.json 2>/dev/null || true | ||
| if git diff --cached --quiet; then | ||
| echo "No package version files were staged." | ||
| exit 0 | ||
| fi | ||
| git commit -m "chore: bump PR version" | ||
| git push | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,7 +24,6 @@ Source files are organized under the `app/` directory. Agent workflow artefacts | |
| ``` | ||
| .github/workflows/ # PR template + CI workflows for build, lint, supabase, secret scanning | ||
| agent-context/ # logs and recurring agent workflow context | ||
| ├─ session-log.md # Mandatory - append-only per session, new entries at top of file, v ↑ per edit | ||
| ├─ db-workflow.md # CI/CD overview for database changes | ||
| ├─ app-context.md # Problem, approach, value prop | ||
| ├─ style-guide.md # Style for the wallet app | ||
|
|
@@ -48,7 +47,6 @@ services/ # Node service modules and worker entrypoints for index | |
| styles/ # global styles | ||
| supabase/ | ||
| ├─ sql-schema.sql # latest sql schema (github action runs db pull on PR) | ||
| ├─ migrations/ # Agent-generated incremental SQL patches (file name starts with session version referencing session-log.md) | ||
| └─ functions/ # Supabase Edge Functions and shared Deno-safe helpers | ||
| ├─ _shared/ # Shared auth, app scoping, RBAC, validation and domain helpers | ||
| └─ */ # Domain edge functions (for example user-settings, bia-service, store-operations) | ||
|
|
@@ -92,7 +90,6 @@ AGENTS.md # this file | |
| * **Pull Requests** | ||
| * Keep pull request descriptions concise and reviewer-focused. | ||
| * If any related issues are known, mention them in PR (e.g. "Issues: #10, #11") | ||
| * **Session version tags** | ||
| * Follow SemVer (v2.0.0-alpha) | ||
| * Major IDs ("v1.0", "v2.0") mirror new feature branches | ||
| * Minor IDs ("v2.0", "v2.1") mirror different coding sesssions on the same feature branch | ||
|
|
@@ -118,9 +115,18 @@ Agents **must** read and follow `workflow.md` each time. | |
|
|
||
| * SQL migrations must be **idempotent & reversible** where practical (include rollback notes or a `-- DOWN` section; each DROP/ALTER should be preceded by IF EXISTS/IF NOT EXISTS where supported). | ||
| * Pre-commit hook **warns** (not blocks) if ESLint and similar (e.g. in Foundry) cannot start. | ||
| * Session log must bump version +1 for each session | ||
| * All new external calls must use SafeERC20 / Address.functionCall and be covered in tests. | ||
| * Agents must **never** directly modify the linked Supabase database. Only a human may run commands that target the linked database and change its state. | ||
| * Agents must always stop and ask for explicit human permission before proposing or running any Supabase command that could change the linked database, including `supabase db push`, `supabase migration up`, `supabase db reset --linked`, `supabase link`, or any `supabase --linked` write operation. | ||
| * This repo qualifies for the stricter multi-frontend Supabase boundary rule: app-facing wallet/sparechange/contracts flows should use typed Edge Functions, narrow RPCs, read-model helpers, or documented server boundaries rather than broad direct browser/client table access. Existing direct-access compatibility paths should be treated as cleanup candidates unless `docs/engineering/supabase-boundary-contract.md` and `scripts/check-no-direct-supabase-db.mjs` explicitly allow them. | ||
| * Deployed Next.js/Vercel runtime should not require `SUPABASE_SERVICE_ROLE_KEY`. That key belongs only in privileged Supabase Edge Functions and the external indexer/onramp worker/runtime paths that intentionally need service-role access. | ||
|
|
||
| ## Branch-Scoped Session Logs And Todos | ||
|
|
||
| - Use `agent-context/session-log/` for active session logs. Do not add new entries to legacy `agent-context/session-log.md` files. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This new branch-log rule conflicts with the still-mandatory Useful? React with 👍 / 👎. |
||
| - For feature branches, update the branch log immediately before each commit. Use `YYYY-MM-DD-featurebranch.md` in single-app repos and `YYYY-MM-DD-app-featurebranch.md` in monorepos. | ||
| - Direct work on `main` may use `agent-context/session-log/main.md`; direct work on `dev` may use `agent-context/session-log/dev.md`. | ||
| - Each entry must include UTC timestamp, agent, branch, head, summary, validation, and follow-ups. | ||
| - Keep `agent-context/todo.md` focused on roadmap items and active follow-ups. Completed work belongs in the current branch log. | ||
| - See `agent-context/session-log/README.md` for naming and archival rules. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forked PRs to
dev/mainhit this step and fail before checkout or version verification. The message asks contributors to apply the bump manually, but even a manually corrected fork PR can never get this check green, which blocks the PR if this workflow is required; skip writeback for forks or run a read-only verification instead of exiting failure.Useful? React with 👍 / 👎.