@smoothbricks/cli 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/monorepo/git-config.d.ts.map +1 -1
- package/dist/monorepo/git-config.js +7 -0
- package/dist/monorepo/managed-files.d.ts.map +1 -1
- package/dist/monorepo/managed-files.js +11 -0
- package/managed/raw/gitattributes +8 -0
- package/managed/raw/tooling/direnv/merge-newer-pins.sh +48 -0
- package/package.json +1 -1
- package/src/monorepo/git-config.ts +10 -0
- package/src/monorepo/managed-files.ts +11 -0
- package/src/monorepo/merge-newer-pins.test.ts +59 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-config.d.ts","sourceRoot":"","sources":["../../src/monorepo/git-config.ts"],"names":[],"mappings":"AAKA,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"git-config.d.ts","sourceRoot":"","sources":["../../src/monorepo/git-config.ts"],"names":[],"mappings":"AAKA,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBzE"}
|
|
@@ -10,6 +10,13 @@ export async function applyWorkspaceGitConfig(root) {
|
|
|
10
10
|
const gitDir = resolve(root, decode(gitDirResult.stdout).trim());
|
|
11
11
|
const tooling = join(root, 'tooling');
|
|
12
12
|
await $ `git config --local include.path ${join(tooling, 'workspace.gitconfig')}`.cwd(root);
|
|
13
|
+
// Keep the newer runtime version pins on any merge (nvfetcher overlay +
|
|
14
|
+
// devenv.lock) so a mirror sync's `git am --3way` never stalls on a version
|
|
15
|
+
// conflict. Mapped by the managed .gitattributes (merge=smoo-newer-pins);
|
|
16
|
+
// implemented in tooling/direnv/merge-newer-pins.sh. The next `devenv shell`
|
|
17
|
+
// regenerates package.json fields from the resulting runtime.
|
|
18
|
+
await $ `git config --local merge.smoo-newer-pins.name ${'keep the newer devenv/nvfetcher runtime pins'}`.cwd(root);
|
|
19
|
+
await $ `git config --local merge.smoo-newer-pins.driver ${'bash tooling/direnv/merge-newer-pins.sh %O %A %B %P'}`.cwd(root);
|
|
13
20
|
linkHook(gitDir, tooling, 'pre-commit');
|
|
14
21
|
linkHook(gitDir, tooling, 'commit-msg');
|
|
15
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;CACxG;
|
|
1
|
+
{"version":3,"file":"managed-files.d.ts","sourceRoot":"","sources":["../../src/monorepo/managed-files.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,GAAG,YAAY,CAAC;CACxG;AA8GD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,EAAE,CAG/F;AA4KD,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAIxD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQzD"}
|
|
@@ -46,6 +46,17 @@ const managedFiles = [
|
|
|
46
46
|
source: 'git-format-staged.yml',
|
|
47
47
|
target: '.git-format-staged.yml',
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
kind: 'raw',
|
|
51
|
+
source: 'gitattributes',
|
|
52
|
+
target: '.gitattributes',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
kind: 'raw',
|
|
56
|
+
source: 'tooling/direnv/merge-newer-pins.sh',
|
|
57
|
+
target: 'tooling/direnv/merge-newer-pins.sh',
|
|
58
|
+
executable: true,
|
|
59
|
+
},
|
|
49
60
|
{
|
|
50
61
|
kind: 'generated',
|
|
51
62
|
source: 'ci-workflow',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# smoo-managed. Keep the newer runtime version pins on any merge (especially a
|
|
2
|
+
# mirror sync's `git am --3way`) instead of stalling on a conflict. The driver
|
|
3
|
+
# `smoo-newer-pins` is defined by `smoo` (git config, installed at devenv setup)
|
|
4
|
+
# and implemented in tooling/direnv/merge-newer-pins.sh. Files not present in a
|
|
5
|
+
# given repo are simply ignored.
|
|
6
|
+
tooling/direnv/nixpkgs-overlay/_sources/generated.json merge=smoo-newer-pins
|
|
7
|
+
tooling/direnv/nixpkgs-overlay/_sources/generated.nix merge=smoo-newer-pins
|
|
8
|
+
tooling/direnv/devenv.lock merge=smoo-newer-pins
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# smoo-managed git merge driver: keep whichever side pins the NEWER version.
|
|
3
|
+
#
|
|
4
|
+
# Runtime version pins (nvfetcher overlay _sources/generated.{json,nix}) and the
|
|
5
|
+
# devenv/flake lock (devenv.lock) frequently differ across branches or across a
|
|
6
|
+
# mirror sync's `git am --3way`. Instead of stalling on a conflict, keep the
|
|
7
|
+
# higher pin wholesale so the tree always converges to the newest runtime; the
|
|
8
|
+
# next `devenv shell` then regenerates package.json engine/packageManager from
|
|
9
|
+
# it (see monorepo/runtime.ts syncRootRuntimeVersions).
|
|
10
|
+
#
|
|
11
|
+
# Wired by `smoo` (managed .gitattributes -> merge=smoo-newer-pins, and
|
|
12
|
+
# `git config merge.smoo-newer-pins.driver` installed by applyWorkspaceGitConfig).
|
|
13
|
+
# git invokes it as: merge-newer-pins.sh %O %A %B %P
|
|
14
|
+
# %O base, %A ours (result written here), %B theirs, %P pathname.
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
ours="$2"
|
|
18
|
+
theirs="$3"
|
|
19
|
+
|
|
20
|
+
# Flake locks are ordered by lastModified (unix seconds); nvfetcher outputs by
|
|
21
|
+
# the semver in their version fields. A given file is one kind or the other.
|
|
22
|
+
max_last_modified() {
|
|
23
|
+
grep -oE '"lastModified"[[:space:]]*:[[:space:]]*[0-9]+' "$1" 2>/dev/null \
|
|
24
|
+
| grep -oE '[0-9]+' | sort -n | tail -1
|
|
25
|
+
}
|
|
26
|
+
max_semver() {
|
|
27
|
+
grep -oE 'version[[:space:]":=]*[0-9]+\.[0-9]+\.[0-9]+' "$1" 2>/dev/null \
|
|
28
|
+
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | sort -V | tail -1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
ours_lm="$(max_last_modified "$ours" || true)"
|
|
32
|
+
theirs_lm="$(max_last_modified "$theirs" || true)"
|
|
33
|
+
|
|
34
|
+
if [ -n "${ours_lm}${theirs_lm}" ]; then
|
|
35
|
+
# Flake lock: numeric lastModified comparison.
|
|
36
|
+
if [ -n "$theirs_lm" ] && [ "${theirs_lm:-0}" -gt "${ours_lm:-0}" ]; then
|
|
37
|
+
cp "$theirs" "$ours"
|
|
38
|
+
fi
|
|
39
|
+
else
|
|
40
|
+
# nvfetcher / version-pinned file: semver comparison.
|
|
41
|
+
ov="$(max_semver "$ours" || true)"
|
|
42
|
+
tv="$(max_semver "$theirs" || true)"
|
|
43
|
+
newest="$(printf '%s\n%s\n' "${ov:-0.0.0}" "${tv:-0.0.0}" | sort -V | tail -1)"
|
|
44
|
+
if [ -n "$tv" ] && [ "$newest" = "$tv" ] && [ "$tv" != "${ov:-}" ]; then
|
|
45
|
+
cp "$theirs" "$ours"
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
exit 0
|
package/package.json
CHANGED
|
@@ -13,6 +13,16 @@ export async function applyWorkspaceGitConfig(root: string): Promise<void> {
|
|
|
13
13
|
const tooling = join(root, 'tooling');
|
|
14
14
|
|
|
15
15
|
await $`git config --local include.path ${join(tooling, 'workspace.gitconfig')}`.cwd(root);
|
|
16
|
+
|
|
17
|
+
// Keep the newer runtime version pins on any merge (nvfetcher overlay +
|
|
18
|
+
// devenv.lock) so a mirror sync's `git am --3way` never stalls on a version
|
|
19
|
+
// conflict. Mapped by the managed .gitattributes (merge=smoo-newer-pins);
|
|
20
|
+
// implemented in tooling/direnv/merge-newer-pins.sh. The next `devenv shell`
|
|
21
|
+
// regenerates package.json fields from the resulting runtime.
|
|
22
|
+
await $`git config --local merge.smoo-newer-pins.name ${'keep the newer devenv/nvfetcher runtime pins'}`.cwd(root);
|
|
23
|
+
await $`git config --local merge.smoo-newer-pins.driver ${'bash tooling/direnv/merge-newer-pins.sh %O %A %B %P'}`.cwd(
|
|
24
|
+
root,
|
|
25
|
+
);
|
|
16
26
|
linkHook(gitDir, tooling, 'pre-commit');
|
|
17
27
|
linkHook(gitDir, tooling, 'commit-msg');
|
|
18
28
|
}
|
|
@@ -78,6 +78,17 @@ const managedFiles: ManagedFile[] = [
|
|
|
78
78
|
source: 'git-format-staged.yml',
|
|
79
79
|
target: '.git-format-staged.yml',
|
|
80
80
|
},
|
|
81
|
+
{
|
|
82
|
+
kind: 'raw',
|
|
83
|
+
source: 'gitattributes',
|
|
84
|
+
target: '.gitattributes',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
kind: 'raw',
|
|
88
|
+
source: 'tooling/direnv/merge-newer-pins.sh',
|
|
89
|
+
target: 'tooling/direnv/merge-newer-pins.sh',
|
|
90
|
+
executable: true,
|
|
91
|
+
},
|
|
81
92
|
{
|
|
82
93
|
kind: 'generated',
|
|
83
94
|
source: 'ci-workflow',
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const script = resolve(
|
|
9
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
10
|
+
'..',
|
|
11
|
+
'..',
|
|
12
|
+
'managed/raw/tooling/direnv/merge-newer-pins.sh',
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
// Invoke the merge driver as git does: `driver %O %A %B %P`, result written to %A (ours).
|
|
16
|
+
function mergedOurs(oursContent: string, theirsContent: string): string {
|
|
17
|
+
const dir = mkdtempSync(join(tmpdir(), 'mnp-'));
|
|
18
|
+
try {
|
|
19
|
+
const base = join(dir, 'base');
|
|
20
|
+
const ours = join(dir, 'ours');
|
|
21
|
+
const theirs = join(dir, 'theirs');
|
|
22
|
+
writeFileSync(base, '');
|
|
23
|
+
writeFileSync(ours, oursContent);
|
|
24
|
+
writeFileSync(theirs, theirsContent);
|
|
25
|
+
const r = spawnSync('bash', [script, base, ours, theirs, 'pins'], { encoding: 'utf8' });
|
|
26
|
+
expect(r.status).toBe(0);
|
|
27
|
+
return readFileSync(ours, 'utf8');
|
|
28
|
+
} finally {
|
|
29
|
+
rmSync(dir, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('smoo-newer-pins merge driver', () => {
|
|
34
|
+
it('nvfetcher JSON: takes theirs when it pins a newer semver', () => {
|
|
35
|
+
expect(mergedOurs('{"bun":{"version": "1.3.13"}}', '{"bun":{"version": "1.3.14"}}')).toContain('1.3.14');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('nvfetcher JSON: keeps ours when ours pins the newer semver', () => {
|
|
39
|
+
expect(mergedOurs('{"bun":{"version": "1.3.14"}}', '{"bun":{"version": "1.3.13"}}')).toContain('1.3.14');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('nvfetcher nix form: takes the newer semver', () => {
|
|
43
|
+
expect(mergedOurs('version = "1.3.13";', 'version = "1.3.14";')).toContain('1.3.14');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('flake lock: takes theirs when lastModified is newer', () => {
|
|
47
|
+
const out = mergedOurs('{"nixpkgs":{"lastModified": 1777573317}}', '{"nixpkgs":{"lastModified": 1779717400}}');
|
|
48
|
+
expect(out).toContain('1779717400');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('flake lock: keeps ours when ours lastModified is newer', () => {
|
|
52
|
+
const out = mergedOurs('{"nixpkgs":{"lastModified": 1779717400}}', '{"nixpkgs":{"lastModified": 1777573317}}');
|
|
53
|
+
expect(out).toContain('1779717400');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('equal versions: keeps ours unchanged (idempotent)', () => {
|
|
57
|
+
expect(mergedOurs('{"v": "1.3.14", "note": "ours"}', '{"v": "1.3.14", "note": "theirs"}')).toContain('ours');
|
|
58
|
+
});
|
|
59
|
+
});
|