From 1ec60123784f8bc265708d28a2f4624ad6d70ada Mon Sep 17 00:00:00 2001 From: Willie Chalmers III Date: Mon, 28 Sep 2026 12:05:32 -0700 Subject: [PATCH 1/2] fix(tooling): push Git LFS objects from the shared pre-push hook A repository that stores files with Git LFS had to add git lfs pre-push to its own .githooks/pre-push, because the shared hook replaced the one git lfs install writes. The website did, so its stub differs from the standard's and would lose the step if owned hooks were ever restored. The shared hook now keeps the refs Git passes on standard input and, after pnpm check passes, runs git lfs pre-push with them when git-lfs is installed and .gitattributes has a filter=lfs rule. Co-Authored-By: Claude Opus 5.5 --- packages/cli/hooks/pre-push.sh | 7 ++++++ tests/hooks.test.mjs | 40 +++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/cli/hooks/pre-push.sh b/packages/cli/hooks/pre-push.sh index bb3a6e3..f8b7fe0 100755 --- a/packages/cli/hooks/pre-push.sh +++ b/packages/cli/hooks/pre-push.sh @@ -9,5 +9,12 @@ while IFS= read -r variable; do done </dev/null 2>&1 && grep -qs 'filter=lfs' "$ROOT/.gitattributes"; then + printf '%s\n' "$REFS" | git lfs pre-push "$@" +fi diff --git a/tests/hooks.test.mjs b/tests/hooks.test.mjs index 1647289..b8229b2 100644 --- a/tests/hooks.test.mjs +++ b/tests/hooks.test.mjs @@ -1,5 +1,5 @@ import assert from 'node:assert/strict'; -import { chmod, mkdir, mkdtemp, readFile, writeFile } from 'node:fs/promises'; +import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; @@ -193,6 +193,44 @@ test('the pre-push hook clears repository-local Git variables before checks', as assert.equal(await readFile(resultFile, 'utf8'), 'unset|unset'); }); +test('the pre-push hook uploads Git LFS objects after the check, only where LFS is used', async (t) => { + const directory = await mkdtemp(path.join(tmpdir(), 'lvbt-pre-push-lfs-')); + t.after(() => rm(directory, { recursive: true, force: true })); + const repository = path.join(directory, 'repository'); + const log = path.join(directory, 'log'); + spawnSync('git', ['init', '--quiet', repository]); + await writeFile(path.join(directory, 'pnpm'), `#!/bin/sh\necho check >> "${log}"\n`); + await writeFile(path.join(directory, 'git-lfs'), `#!/bin/sh\necho "lfs $* $(cat)" >> "${log}"\n`); + await chmod(path.join(directory, 'pnpm'), 0o755); + await chmod(path.join(directory, 'git-lfs'), 0o755); + const push = () => + spawnSync( + path.join(repositoryRoot, 'packages/cli/hooks/pre-push.sh'), + ['origin', 'git@example.org:repo.git'], + { + cwd: repository, + encoding: 'utf8', + input: 'refs/heads/main abc refs/heads/main def\n', + env: { ...process.env, PATH: `${directory}:${process.env.PATH}` }, + }, + ); + + assert.equal(push().status, 0); + assert.equal(await readFile(log, 'utf8'), 'check\n', 'no LFS upload without an LFS rule'); + + await writeFile( + path.join(repository, '.gitattributes'), + '*.png filter=lfs diff=lfs merge=lfs -text\n', + ); + await rm(log); + const result = push(); + assert.equal(result.status, 0, result.stderr); + assert.equal( + await readFile(log, 'utf8'), + 'check\nlfs pre-push origin git@example.org:repo.git refs/heads/main abc refs/heads/main def\n', + ); +}); + test('the shared and source repository hooks pass ShellCheck', (context) => { const available = spawnSync('shellcheck', ['--version'], { encoding: 'utf8' }); if (available.error?.code === 'ENOENT') { From 1e2214177f4d4449613edbc44367cdc9dcd6832e Mon Sep 17 00:00:00 2001 From: Willie Chalmers III Date: Mon, 28 Sep 2026 12:05:56 -0700 Subject: [PATCH 2/2] chore(tooling): release v0.5.3 Publish Git LFS support in the shared pre-push hook as a patch release of the shared web standard. Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/marketplace.json | 2 +- docs/reference/release-0-5-3.md | 9 +++++++++ examples/basic/.claude/settings.json | 2 +- examples/basic/package.json | 4 ++-- examples/basic/packages/example/package.json | 6 +++--- examples/with-astro/.claude/settings.json | 2 +- examples/with-astro/apps/site/package.json | 8 ++++---- examples/with-astro/package.json | 4 ++-- examples/with-vite-react/.claude/settings.json | 2 +- examples/with-vite-react/apps/app/package.json | 8 ++++---- examples/with-vite-react/package.json | 4 ++-- package.json | 2 +- packages/cli/package.json | 2 +- .../lvbt-contributions/.claude-plugin/plugin.json | 2 +- .../plugins/lvbt-contributions/.codex-plugin/plugin.json | 2 +- packages/eslint-config/package.json | 2 +- packages/playwright-config/package.json | 2 +- packages/prettier-config/package.json | 2 +- packages/typescript-config/package.json | 2 +- packages/vitest-config/package.json | 2 +- packages/web-platform/package.json | 2 +- 21 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 docs/reference/release-0-5-3.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f8c0ae7..6b591be 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ { "name": "lvbt-contributions", "description": "Create readable LVBT GitHub issues and pull requests.", - "version": "0.5.2", + "version": "0.5.3", "source": "./packages/cli/plugins/lvbt-contributions" } ] diff --git a/docs/reference/release-0-5-3.md b/docs/reference/release-0-5-3.md new file mode 100644 index 0000000..39db547 --- /dev/null +++ b/docs/reference/release-0-5-3.md @@ -0,0 +1,9 @@ +# Repository tooling 0.5.3 + +A repository that stores files with Git LFS no longer needs its own step in `.githooks/pre-push`. +The shared pre-push hook now uploads LFS objects with the push, as the hook `git lfs install` writes +would, once `pnpm check` passes. It does this only when `git-lfs` is installed and `.gitattributes` +has a `filter=lfs` rule, so nothing changes for a repository that doesn't use LFS. + +If you added `git lfs pre-push` to your repository's `.githooks/pre-push`, remove it after updating; +the file then matches the standard's copy again and `pnpm standards:check` stops warning about it. diff --git a/examples/basic/.claude/settings.json b/examples/basic/.claude/settings.json index 39b3306..ef6bb4e 100644 --- a/examples/basic/.claude/settings.json +++ b/examples/basic/.claude/settings.json @@ -4,7 +4,7 @@ "source": { "source": "github", "repo": "LasVegasForTransit/repository-tooling", - "ref": "v0.5.2" + "ref": "v0.5.3" } } }, diff --git a/examples/basic/package.json b/examples/basic/package.json index 31805b1..d9925f4 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -21,8 +21,8 @@ "*": "prettier --write --ignore-unknown" }, "devDependencies": { - "@lasvegasfortransit/cli": "0.5.2", - "@lasvegasfortransit/prettier-config": "0.5.2", + "@lasvegasfortransit/cli": "0.5.3", + "@lasvegasfortransit/prettier-config": "0.5.3", "lint-staged": "catalog:", "markdownlint-cli2": "catalog:", "markdownlint-rule-relative-links": "catalog:", diff --git a/examples/basic/packages/example/package.json b/examples/basic/packages/example/package.json index 1932630..0d4bf04 100644 --- a/examples/basic/packages/example/package.json +++ b/examples/basic/packages/example/package.json @@ -16,9 +16,9 @@ "test": "vitest run" }, "devDependencies": { - "@lasvegasfortransit/eslint-config": "0.5.2", - "@lasvegasfortransit/typescript-config": "0.5.2", - "@lasvegasfortransit/vitest-config": "0.5.2", + "@lasvegasfortransit/eslint-config": "0.5.3", + "@lasvegasfortransit/typescript-config": "0.5.3", + "@lasvegasfortransit/vitest-config": "0.5.3", "@types/node": "catalog:", "eslint": "catalog:", "typescript": "catalog:", diff --git a/examples/with-astro/.claude/settings.json b/examples/with-astro/.claude/settings.json index 39b3306..ef6bb4e 100644 --- a/examples/with-astro/.claude/settings.json +++ b/examples/with-astro/.claude/settings.json @@ -4,7 +4,7 @@ "source": { "source": "github", "repo": "LasVegasForTransit/repository-tooling", - "ref": "v0.5.2" + "ref": "v0.5.3" } } }, diff --git a/examples/with-astro/apps/site/package.json b/examples/with-astro/apps/site/package.json index 8f18b97..1738170 100644 --- a/examples/with-astro/apps/site/package.json +++ b/examples/with-astro/apps/site/package.json @@ -21,10 +21,10 @@ }, "devDependencies": { "@astrojs/check": "catalog:", - "@lasvegasfortransit/eslint-config": "0.5.2", - "@lasvegasfortransit/playwright-config": "0.5.2", - "@lasvegasfortransit/typescript-config": "0.5.2", - "@lasvegasfortransit/vitest-config": "0.5.2", + "@lasvegasfortransit/eslint-config": "0.5.3", + "@lasvegasfortransit/playwright-config": "0.5.3", + "@lasvegasfortransit/typescript-config": "0.5.3", + "@lasvegasfortransit/vitest-config": "0.5.3", "@playwright/test": "catalog:", "@types/node": "catalog:", "eslint": "catalog:", diff --git a/examples/with-astro/package.json b/examples/with-astro/package.json index 1c75559..f49a276 100644 --- a/examples/with-astro/package.json +++ b/examples/with-astro/package.json @@ -23,8 +23,8 @@ "*": "prettier --write --ignore-unknown" }, "devDependencies": { - "@lasvegasfortransit/cli": "0.5.2", - "@lasvegasfortransit/prettier-config": "0.5.2", + "@lasvegasfortransit/cli": "0.5.3", + "@lasvegasfortransit/prettier-config": "0.5.3", "lint-staged": "catalog:", "markdownlint-cli2": "catalog:", "markdownlint-rule-relative-links": "catalog:", diff --git a/examples/with-vite-react/.claude/settings.json b/examples/with-vite-react/.claude/settings.json index 39b3306..ef6bb4e 100644 --- a/examples/with-vite-react/.claude/settings.json +++ b/examples/with-vite-react/.claude/settings.json @@ -4,7 +4,7 @@ "source": { "source": "github", "repo": "LasVegasForTransit/repository-tooling", - "ref": "v0.5.2" + "ref": "v0.5.3" } } }, diff --git a/examples/with-vite-react/apps/app/package.json b/examples/with-vite-react/apps/app/package.json index 9e209af..680e16e 100644 --- a/examples/with-vite-react/apps/app/package.json +++ b/examples/with-vite-react/apps/app/package.json @@ -17,10 +17,10 @@ "react-dom": "catalog:" }, "devDependencies": { - "@lasvegasfortransit/eslint-config": "0.5.2", - "@lasvegasfortransit/playwright-config": "0.5.2", - "@lasvegasfortransit/typescript-config": "0.5.2", - "@lasvegasfortransit/vitest-config": "0.5.2", + "@lasvegasfortransit/eslint-config": "0.5.3", + "@lasvegasfortransit/playwright-config": "0.5.3", + "@lasvegasfortransit/typescript-config": "0.5.3", + "@lasvegasfortransit/vitest-config": "0.5.3", "@playwright/test": "catalog:", "@tailwindcss/vite": "catalog:", "@types/node": "catalog:", diff --git a/examples/with-vite-react/package.json b/examples/with-vite-react/package.json index dc1bbf2..efece57 100644 --- a/examples/with-vite-react/package.json +++ b/examples/with-vite-react/package.json @@ -23,8 +23,8 @@ "*": "prettier --write --ignore-unknown" }, "devDependencies": { - "@lasvegasfortransit/cli": "0.5.2", - "@lasvegasfortransit/prettier-config": "0.5.2", + "@lasvegasfortransit/cli": "0.5.3", + "@lasvegasfortransit/prettier-config": "0.5.3", "lint-staged": "catalog:", "markdownlint-cli2": "catalog:", "markdownlint-rule-relative-links": "catalog:", diff --git a/package.json b/package.json index 20900d9..42d9499 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "lvbt-repository-tooling", "private": true, - "version": "0.5.2", + "version": "0.5.3", "type": "module", "description": "Source of truth for the LVBT repository standard: the shared @lasvegasfortransit packages and the example repositories create-turbo copies.", "packageManager": "pnpm@11.25.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index 54bc966..37e3ad8 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@lasvegasfortransit/cli", - "version": "0.5.2", + "version": "0.5.3", "description": "The lvbt command every LVBT repository runs for bootstrap, preflight, and deploy, plus the production platform setup, the shared git hooks, and the lvbt-contributions agent plugin.", "license": "MIT", "type": "module", diff --git a/packages/cli/plugins/lvbt-contributions/.claude-plugin/plugin.json b/packages/cli/plugins/lvbt-contributions/.claude-plugin/plugin.json index ce879c6..bede3d2 100644 --- a/packages/cli/plugins/lvbt-contributions/.claude-plugin/plugin.json +++ b/packages/cli/plugins/lvbt-contributions/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "lvbt-contributions", - "version": "0.5.2", + "version": "0.5.3", "description": "Create readable LVBT GitHub issues and pull requests through the organization workflow.", "author": { "name": "Las Vegans for Better Transit", diff --git a/packages/cli/plugins/lvbt-contributions/.codex-plugin/plugin.json b/packages/cli/plugins/lvbt-contributions/.codex-plugin/plugin.json index f18002b..e837208 100644 --- a/packages/cli/plugins/lvbt-contributions/.codex-plugin/plugin.json +++ b/packages/cli/plugins/lvbt-contributions/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "lvbt-contributions", - "version": "0.5.2", + "version": "0.5.3", "description": "Create readable LVBT GitHub issues and pull requests through the organization workflow.", "author": { "name": "Las Vegans for Better Transit", diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index d1d9c1b..b6b4edf 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@lasvegasfortransit/eslint-config", - "version": "0.5.2", + "version": "0.5.3", "description": "The ESLint configurations every LVBT repository uses.", "license": "MIT", "type": "module", diff --git a/packages/playwright-config/package.json b/packages/playwright-config/package.json index 2d45257..151991d 100644 --- a/packages/playwright-config/package.json +++ b/packages/playwright-config/package.json @@ -1,6 +1,6 @@ { "name": "@lasvegasfortransit/playwright-config", - "version": "0.5.2", + "version": "0.5.3", "description": "The Playwright configuration every LVBT repository spreads into its own: end-to-end tests under tests/e2e, desktop and mobile projects, traces on failure.", "license": "MIT", "type": "module", diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index 8502cee..d9c38a3 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@lasvegasfortransit/prettier-config", - "version": "0.5.2", + "version": "0.5.3", "description": "The Prettier configuration every LVBT repository uses.", "license": "MIT", "type": "module", diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json index a39afe9..4e431c0 100644 --- a/packages/typescript-config/package.json +++ b/packages/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@lasvegasfortransit/typescript-config", - "version": "0.5.2", + "version": "0.5.3", "description": "TypeScript configurations every LVBT repository extends.", "license": "MIT", "repository": { diff --git a/packages/vitest-config/package.json b/packages/vitest-config/package.json index f3edfbe..3aeb4d0 100644 --- a/packages/vitest-config/package.json +++ b/packages/vitest-config/package.json @@ -1,6 +1,6 @@ { "name": "@lasvegasfortransit/vitest-config", - "version": "0.5.2", + "version": "0.5.3", "description": "The Vitest configuration every LVBT repository spreads into its own.", "license": "MIT", "type": "module", diff --git a/packages/web-platform/package.json b/packages/web-platform/package.json index e7ed44a..de966a8 100644 --- a/packages/web-platform/package.json +++ b/packages/web-platform/package.json @@ -1,6 +1,6 @@ { "name": "@lasvegasfortransit/web-platform", - "version": "0.5.2", + "version": "0.5.3", "description": "Provider-neutral deployment, provisioning, and validation primitives for LVBT web repositories.", "license": "MIT", "type": "module",