@pgsql/lint 18.2.0 → 18.2.1
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/README.md +5 -2
- package/changed.d.ts +7 -9
- package/changed.js +16 -131
- package/esm/changed.js +16 -98
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -62,8 +62,11 @@ request's base branch (`$GITHUB_BASE_REF`) and otherwise to the repository's
|
|
|
62
62
|
default branch; the diff is taken against `git merge-base HEAD <base>`, so
|
|
63
63
|
commits landed on the base branch afterwards don't widen the set. Uncommitted and
|
|
64
64
|
untracked changes are included, deleted/renamed-away paths are dropped, and a
|
|
65
|
-
shallow clone or detached checkout (no resolvable
|
|
66
|
-
|
|
65
|
+
shallow clone or detached checkout (no resolvable base) falls back to working-tree
|
|
66
|
+
changes only. Nothing changed is an exit-0 pass.
|
|
67
|
+
|
|
68
|
+
Detection is [`git-changed`](https://npmjs.com/package/git-changed), shared with
|
|
69
|
+
`pgpm package --check`, so the two agree on what "changed" means.
|
|
67
70
|
|
|
68
71
|
### Config file
|
|
69
72
|
|
package/changed.d.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Changed-file detection for `--changed`, so a CI gate (or a human before a
|
|
3
3
|
* commit) pays only for the SQL that a branch actually touched.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* The git plumbing — base resolution, merge-base diff, working-tree union,
|
|
6
|
+
* rename targets, dropping paths that no longer exist — lives in `git-changed`,
|
|
7
|
+
* which is shared with pgpm's bundle-drift check. This module is the `.sql`
|
|
8
|
+
* filter over it, and the place where "no base" stays non-fatal: a lint gate
|
|
9
|
+
* that refuses to run on a shallow clone lints nothing, which is worse than
|
|
10
|
+
* linting the working tree.
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
13
13
|
* Resolve the ref to diff against. An explicit `base` wins; otherwise the PR
|
|
@@ -26,9 +26,7 @@ export interface ChangedFilesResult {
|
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* Collect the files that differ from `base` (via `git merge-base`) plus any
|
|
29
|
-
* uncommitted/untracked working-tree changes.
|
|
30
|
-
* when no base is resolvable or no merge base exists — a shallow clone or a
|
|
31
|
-
* detached CI checkout — rather than failing the run.
|
|
29
|
+
* uncommitted/untracked working-tree changes.
|
|
32
30
|
*/
|
|
33
31
|
export declare function changedFiles(options?: {
|
|
34
32
|
cwd?: string;
|
package/changed.js
CHANGED
|
@@ -3,80 +3,18 @@
|
|
|
3
3
|
* Changed-file detection for `--changed`, so a CI gate (or a human before a
|
|
4
4
|
* commit) pays only for the SQL that a branch actually touched.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* The git plumbing — base resolution, merge-base diff, working-tree union,
|
|
7
|
+
* rename targets, dropping paths that no longer exist — lives in `git-changed`,
|
|
8
|
+
* which is shared with pgpm's bundle-drift check. This module is the `.sql`
|
|
9
|
+
* filter over it, and the place where "no base" stays non-fatal: a lint gate
|
|
10
|
+
* that refuses to run on a shallow clone lints nothing, which is worse than
|
|
11
|
+
* linting the working tree.
|
|
12
12
|
*/
|
|
13
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
-
if (k2 === undefined) k2 = k;
|
|
15
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
-
}
|
|
19
|
-
Object.defineProperty(o, k2, desc);
|
|
20
|
-
}) : (function(o, m, k, k2) {
|
|
21
|
-
if (k2 === undefined) k2 = k;
|
|
22
|
-
o[k2] = m[k];
|
|
23
|
-
}));
|
|
24
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
-
}) : function(o, v) {
|
|
27
|
-
o["default"] = v;
|
|
28
|
-
});
|
|
29
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
-
var ownKeys = function(o) {
|
|
31
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
-
var ar = [];
|
|
33
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
-
return ar;
|
|
35
|
-
};
|
|
36
|
-
return ownKeys(o);
|
|
37
|
-
};
|
|
38
|
-
return function (mod) {
|
|
39
|
-
if (mod && mod.__esModule) return mod;
|
|
40
|
-
var result = {};
|
|
41
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
-
__setModuleDefault(result, mod);
|
|
43
|
-
return result;
|
|
44
|
-
};
|
|
45
|
-
})();
|
|
46
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
14
|
exports.resolveChangedBase = resolveChangedBase;
|
|
48
15
|
exports.changedFiles = changedFiles;
|
|
49
16
|
exports.changedSqlFiles = changedSqlFiles;
|
|
50
|
-
const
|
|
51
|
-
const fs_1 = require("fs");
|
|
52
|
-
const path = __importStar(require("path"));
|
|
53
|
-
function git(args, cwd) {
|
|
54
|
-
return (0, child_process_1.execFileSync)('git', args, {
|
|
55
|
-
cwd,
|
|
56
|
-
encoding: 'utf-8',
|
|
57
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
58
|
-
maxBuffer: 64 * 1024 * 1024
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
function tryGit(args, cwd) {
|
|
62
|
-
try {
|
|
63
|
-
return git(args, cwd);
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
/** The repository's default branch as a remote-tracking ref, when discoverable. */
|
|
70
|
-
function defaultBranch(cwd) {
|
|
71
|
-
const head = tryGit(['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], cwd);
|
|
72
|
-
if (head && head.trim())
|
|
73
|
-
return head.trim();
|
|
74
|
-
for (const candidate of ['origin/main', 'origin/master', 'main', 'master']) {
|
|
75
|
-
if (tryGit(['rev-parse', '--verify', '--quiet', candidate], cwd))
|
|
76
|
-
return candidate;
|
|
77
|
-
}
|
|
78
|
-
return undefined;
|
|
79
|
-
}
|
|
17
|
+
const git_changed_1 = require("git-changed");
|
|
80
18
|
/**
|
|
81
19
|
* Resolve the ref to diff against. An explicit `base` wins; otherwise the PR
|
|
82
20
|
* base branch (`origin/$GITHUB_BASE_REF`) when running in GitHub Actions;
|
|
@@ -84,76 +22,23 @@ function defaultBranch(cwd) {
|
|
|
84
22
|
* the caller falls back to working-tree changes only.
|
|
85
23
|
*/
|
|
86
24
|
function resolveChangedBase(base, cwd = process.cwd()) {
|
|
87
|
-
|
|
88
|
-
return base.trim();
|
|
89
|
-
const prBase = process.env.GITHUB_BASE_REF;
|
|
90
|
-
if (prBase && prBase.trim()) {
|
|
91
|
-
const ref = `origin/${prBase.trim()}`;
|
|
92
|
-
if (tryGit(['rev-parse', '--verify', '--quiet', ref], cwd))
|
|
93
|
-
return ref;
|
|
94
|
-
return prBase.trim();
|
|
95
|
-
}
|
|
96
|
-
return defaultBranch(cwd);
|
|
25
|
+
return (0, git_changed_1.resolveBase)(base, cwd);
|
|
97
26
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// `-uall` lists untracked *files*; the default collapses a new directory to
|
|
102
|
-
// the directory name, which would hide every file a new module adds.
|
|
103
|
-
const status = tryGit(['status', '--porcelain', '-uall'], cwd) ?? '';
|
|
104
|
-
for (const rawLine of status.split('\n')) {
|
|
105
|
-
const line = rawLine.trimEnd();
|
|
106
|
-
if (!line)
|
|
107
|
-
continue;
|
|
108
|
-
let p = line.slice(3);
|
|
109
|
-
const arrow = p.indexOf(' -> ');
|
|
110
|
-
if (arrow !== -1)
|
|
111
|
-
p = p.slice(arrow + 4);
|
|
112
|
-
p = p.replace(/^"|"$/g, '');
|
|
113
|
-
if (p)
|
|
114
|
-
out.push(p);
|
|
27
|
+
function collect(cwd, base, ext) {
|
|
28
|
+
if (!(0, git_changed_1.isRepo)(cwd)) {
|
|
29
|
+
throw new Error(`--changed needs a git repository; ${cwd} is not inside one`);
|
|
115
30
|
}
|
|
116
|
-
|
|
31
|
+
const result = (0, git_changed_1.changedFiles)({ cwd, base, ext });
|
|
32
|
+
return { files: result.paths, base: result.base, mergeBase: result.mergeBase };
|
|
117
33
|
}
|
|
118
34
|
/**
|
|
119
35
|
* Collect the files that differ from `base` (via `git merge-base`) plus any
|
|
120
|
-
* uncommitted/untracked working-tree changes.
|
|
121
|
-
* when no base is resolvable or no merge base exists — a shallow clone or a
|
|
122
|
-
* detached CI checkout — rather than failing the run.
|
|
36
|
+
* uncommitted/untracked working-tree changes.
|
|
123
37
|
*/
|
|
124
38
|
function changedFiles(options = {}) {
|
|
125
|
-
|
|
126
|
-
if (!tryGit(['rev-parse', '--git-dir'], cwd)) {
|
|
127
|
-
throw new Error(`--changed needs a git repository; ${cwd} is not inside one`);
|
|
128
|
-
}
|
|
129
|
-
const files = new Set(workingTreePaths(cwd));
|
|
130
|
-
const base = resolveChangedBase(options.base, cwd);
|
|
131
|
-
let mergeBase;
|
|
132
|
-
if (base) {
|
|
133
|
-
const found = tryGit(['merge-base', 'HEAD', base], cwd);
|
|
134
|
-
mergeBase = found?.trim() || undefined;
|
|
135
|
-
}
|
|
136
|
-
// No base, or no common ancestor (shallow clone / detached checkout): the
|
|
137
|
-
// uncommitted diff against HEAD is all the history we can see.
|
|
138
|
-
const diffArgs = mergeBase
|
|
139
|
-
? ['diff', '--name-only', '--diff-filter=ACMR', mergeBase, 'HEAD']
|
|
140
|
-
: ['diff', '--name-only', '--diff-filter=ACMR', 'HEAD'];
|
|
141
|
-
for (const rawLine of (tryGit(diffArgs, cwd) ?? '').split('\n')) {
|
|
142
|
-
const p = rawLine.trim();
|
|
143
|
-
if (p)
|
|
144
|
-
files.add(p);
|
|
145
|
-
}
|
|
146
|
-
const abs = [];
|
|
147
|
-
for (const rel of files) {
|
|
148
|
-
const full = path.resolve(cwd, rel);
|
|
149
|
-
// Deleted or renamed-away paths have nothing left to lint.
|
|
150
|
-
if ((0, fs_1.existsSync)(full) && (0, fs_1.statSync)(full).isFile())
|
|
151
|
-
abs.push(full);
|
|
152
|
-
}
|
|
153
|
-
return { files: abs.sort(), base, mergeBase };
|
|
39
|
+
return collect(options.cwd ?? process.cwd(), options.base);
|
|
154
40
|
}
|
|
155
41
|
/** {@link changedFiles}, narrowed to `.sql`. */
|
|
156
42
|
function changedSqlFiles(options = {}) {
|
|
157
|
-
|
|
158
|
-
return { ...result, files: result.files.filter((f) => f.toLowerCase().endsWith('.sql')) };
|
|
43
|
+
return collect(options.cwd ?? process.cwd(), options.base, '.sql');
|
|
159
44
|
}
|
package/esm/changed.js
CHANGED
|
@@ -2,43 +2,14 @@
|
|
|
2
2
|
* Changed-file detection for `--changed`, so a CI gate (or a human before a
|
|
3
3
|
* commit) pays only for the SQL that a branch actually touched.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* The git plumbing — base resolution, merge-base diff, working-tree union,
|
|
6
|
+
* rename targets, dropping paths that no longer exist — lives in `git-changed`,
|
|
7
|
+
* which is shared with pgpm's bundle-drift check. This module is the `.sql`
|
|
8
|
+
* filter over it, and the place where "no base" stays non-fatal: a lint gate
|
|
9
|
+
* that refuses to run on a shallow clone lints nothing, which is worse than
|
|
10
|
+
* linting the working tree.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
13
|
-
import { existsSync, statSync } from 'fs';
|
|
14
|
-
import * as path from 'path';
|
|
15
|
-
function git(args, cwd) {
|
|
16
|
-
return execFileSync('git', args, {
|
|
17
|
-
cwd,
|
|
18
|
-
encoding: 'utf-8',
|
|
19
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
20
|
-
maxBuffer: 64 * 1024 * 1024
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
function tryGit(args, cwd) {
|
|
24
|
-
try {
|
|
25
|
-
return git(args, cwd);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/** The repository's default branch as a remote-tracking ref, when discoverable. */
|
|
32
|
-
function defaultBranch(cwd) {
|
|
33
|
-
const head = tryGit(['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], cwd);
|
|
34
|
-
if (head && head.trim())
|
|
35
|
-
return head.trim();
|
|
36
|
-
for (const candidate of ['origin/main', 'origin/master', 'main', 'master']) {
|
|
37
|
-
if (tryGit(['rev-parse', '--verify', '--quiet', candidate], cwd))
|
|
38
|
-
return candidate;
|
|
39
|
-
}
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
12
|
+
import { changedFiles as gitChangedFiles, isRepo, resolveBase } from 'git-changed';
|
|
42
13
|
/**
|
|
43
14
|
* Resolve the ref to diff against. An explicit `base` wins; otherwise the PR
|
|
44
15
|
* base branch (`origin/$GITHUB_BASE_REF`) when running in GitHub Actions;
|
|
@@ -46,76 +17,23 @@ function defaultBranch(cwd) {
|
|
|
46
17
|
* the caller falls back to working-tree changes only.
|
|
47
18
|
*/
|
|
48
19
|
export function resolveChangedBase(base, cwd = process.cwd()) {
|
|
49
|
-
|
|
50
|
-
return base.trim();
|
|
51
|
-
const prBase = process.env.GITHUB_BASE_REF;
|
|
52
|
-
if (prBase && prBase.trim()) {
|
|
53
|
-
const ref = `origin/${prBase.trim()}`;
|
|
54
|
-
if (tryGit(['rev-parse', '--verify', '--quiet', ref], cwd))
|
|
55
|
-
return ref;
|
|
56
|
-
return prBase.trim();
|
|
57
|
-
}
|
|
58
|
-
return defaultBranch(cwd);
|
|
20
|
+
return resolveBase(base, cwd);
|
|
59
21
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// `-uall` lists untracked *files*; the default collapses a new directory to
|
|
64
|
-
// the directory name, which would hide every file a new module adds.
|
|
65
|
-
const status = tryGit(['status', '--porcelain', '-uall'], cwd) ?? '';
|
|
66
|
-
for (const rawLine of status.split('\n')) {
|
|
67
|
-
const line = rawLine.trimEnd();
|
|
68
|
-
if (!line)
|
|
69
|
-
continue;
|
|
70
|
-
let p = line.slice(3);
|
|
71
|
-
const arrow = p.indexOf(' -> ');
|
|
72
|
-
if (arrow !== -1)
|
|
73
|
-
p = p.slice(arrow + 4);
|
|
74
|
-
p = p.replace(/^"|"$/g, '');
|
|
75
|
-
if (p)
|
|
76
|
-
out.push(p);
|
|
22
|
+
function collect(cwd, base, ext) {
|
|
23
|
+
if (!isRepo(cwd)) {
|
|
24
|
+
throw new Error(`--changed needs a git repository; ${cwd} is not inside one`);
|
|
77
25
|
}
|
|
78
|
-
|
|
26
|
+
const result = gitChangedFiles({ cwd, base, ext });
|
|
27
|
+
return { files: result.paths, base: result.base, mergeBase: result.mergeBase };
|
|
79
28
|
}
|
|
80
29
|
/**
|
|
81
30
|
* Collect the files that differ from `base` (via `git merge-base`) plus any
|
|
82
|
-
* uncommitted/untracked working-tree changes.
|
|
83
|
-
* when no base is resolvable or no merge base exists — a shallow clone or a
|
|
84
|
-
* detached CI checkout — rather than failing the run.
|
|
31
|
+
* uncommitted/untracked working-tree changes.
|
|
85
32
|
*/
|
|
86
33
|
export function changedFiles(options = {}) {
|
|
87
|
-
|
|
88
|
-
if (!tryGit(['rev-parse', '--git-dir'], cwd)) {
|
|
89
|
-
throw new Error(`--changed needs a git repository; ${cwd} is not inside one`);
|
|
90
|
-
}
|
|
91
|
-
const files = new Set(workingTreePaths(cwd));
|
|
92
|
-
const base = resolveChangedBase(options.base, cwd);
|
|
93
|
-
let mergeBase;
|
|
94
|
-
if (base) {
|
|
95
|
-
const found = tryGit(['merge-base', 'HEAD', base], cwd);
|
|
96
|
-
mergeBase = found?.trim() || undefined;
|
|
97
|
-
}
|
|
98
|
-
// No base, or no common ancestor (shallow clone / detached checkout): the
|
|
99
|
-
// uncommitted diff against HEAD is all the history we can see.
|
|
100
|
-
const diffArgs = mergeBase
|
|
101
|
-
? ['diff', '--name-only', '--diff-filter=ACMR', mergeBase, 'HEAD']
|
|
102
|
-
: ['diff', '--name-only', '--diff-filter=ACMR', 'HEAD'];
|
|
103
|
-
for (const rawLine of (tryGit(diffArgs, cwd) ?? '').split('\n')) {
|
|
104
|
-
const p = rawLine.trim();
|
|
105
|
-
if (p)
|
|
106
|
-
files.add(p);
|
|
107
|
-
}
|
|
108
|
-
const abs = [];
|
|
109
|
-
for (const rel of files) {
|
|
110
|
-
const full = path.resolve(cwd, rel);
|
|
111
|
-
// Deleted or renamed-away paths have nothing left to lint.
|
|
112
|
-
if (existsSync(full) && statSync(full).isFile())
|
|
113
|
-
abs.push(full);
|
|
114
|
-
}
|
|
115
|
-
return { files: abs.sort(), base, mergeBase };
|
|
34
|
+
return collect(options.cwd ?? process.cwd(), options.base);
|
|
116
35
|
}
|
|
117
36
|
/** {@link changedFiles}, narrowed to `.sql`. */
|
|
118
37
|
export function changedSqlFiles(options = {}) {
|
|
119
|
-
|
|
120
|
-
return { ...result, files: result.files.filter((f) => f.toLowerCase().endsWith('.sql')) };
|
|
38
|
+
return collect(options.cwd ?? process.cwd(), options.base, '.sql');
|
|
121
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgsql/lint",
|
|
3
|
-
"version": "18.2.
|
|
3
|
+
"version": "18.2.1",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Source-level SQL/PL/pgSQL convention linter: fully-qualified references, no search_path, no dynamic SQL, with ESLint-style inline waivers. Pure AST, no database.",
|
|
6
6
|
"main": "index.js",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@pgsql/traverse": "18.7.3",
|
|
38
38
|
"chalk": "^4.1.0",
|
|
39
|
+
"git-changed": "^0.3.0",
|
|
39
40
|
"libpg-query": "18.1.4",
|
|
40
41
|
"minimist": "1.2.8",
|
|
41
42
|
"pgsql-parser": "18.2.3"
|
|
@@ -56,5 +57,5 @@
|
|
|
56
57
|
"search_path",
|
|
57
58
|
"dynamic-sql"
|
|
58
59
|
],
|
|
59
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "69cdce673db035fb1ee3b529480d39fac01512ab"
|
|
60
61
|
}
|