git-format-staged 2.0.0 → 2.1.3
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 +18 -3
- package/git-format-staged +31 -9
- package/package.json +33 -25
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ For detailed information run:
|
|
|
61
61
|
The command expects a shell command to run a formatter, and one or more file
|
|
62
62
|
patterns to identify which files should be formatted. For example:
|
|
63
63
|
|
|
64
|
-
$ git-format-staged --formatter 'prettier --stdin' 'src/*.js'
|
|
64
|
+
$ git-format-staged --formatter 'prettier --stdin-filepath "{}"' 'src/*.js'
|
|
65
65
|
|
|
66
66
|
That will format all files under `src/` and its subdirectories using
|
|
67
67
|
`prettier`. The file pattern is tested against staged files using Python's
|
|
@@ -75,7 +75,7 @@ content to `stdout`.
|
|
|
75
75
|
|
|
76
76
|
Files can be excluded by prefixing a pattern with `!`. For example:
|
|
77
77
|
|
|
78
|
-
$ git-format-staged --formatter 'prettier --stdin' '*.js' '!flow-typed/*'
|
|
78
|
+
$ git-format-staged --formatter 'prettier --stdin-filepath "{}"' '*.js' '!flow-typed/*'
|
|
79
79
|
|
|
80
80
|
Patterns are evaluated from left-to-right: if a file matches multiple patterns
|
|
81
81
|
the right-most pattern determines whether the file is included or excluded.
|
|
@@ -84,6 +84,16 @@ git-format-staged never operates on files that are excluded from version
|
|
|
84
84
|
control. So it is not necessary to explicitly exclude stuff like
|
|
85
85
|
`node_modules/`.
|
|
86
86
|
|
|
87
|
+
The formatter command may include a placeholder, `{}`, which will be replaced
|
|
88
|
+
with the path of the file that is being formatted. This is useful if your
|
|
89
|
+
formatter needs to know the file extension to determine how to format or to
|
|
90
|
+
lint each file. For example:
|
|
91
|
+
|
|
92
|
+
$ git-format-staged -f 'prettier --stdin-filepath "{}"' '*.js' '*.css'
|
|
93
|
+
|
|
94
|
+
Do not attempt to read or write to `{}` in your formatter command! The
|
|
95
|
+
placeholder exists only for referencing the file name and path.
|
|
96
|
+
|
|
87
97
|
### Check staged changes with a linter without formatting
|
|
88
98
|
|
|
89
99
|
Perhaps you do not want to reformat files automatically; but you do want to
|
|
@@ -91,7 +101,7 @@ prevent files from being committed if they do not conform to style rules. You
|
|
|
91
101
|
can use git-format-staged with the `--no-write` option, and supply a lint
|
|
92
102
|
command instead of a format command. Here is an example using ESLint:
|
|
93
103
|
|
|
94
|
-
$ git-format-staged --no-write -f 'eslint --stdin >&2' 'src/*.js'
|
|
104
|
+
$ git-format-staged --no-write -f 'eslint --stdin --stdin-filename "{}" >&2' 'src/*.js'
|
|
95
105
|
|
|
96
106
|
If this command is run in a pre-commit hook, and the lint command fails the
|
|
97
107
|
commit will be aborted and error messages will be displayed. The lint command
|
|
@@ -166,6 +176,10 @@ Some more comparisons:
|
|
|
166
176
|
lint-staged does provide powerful configuration options around which files
|
|
167
177
|
should be linted or formatted, what should happen before and after linting,
|
|
168
178
|
and so on.
|
|
179
|
+
- [pretty-quick][] formats staged files with prettier. By default pretty-quick
|
|
180
|
+
will abort the commit if files are partially staged to allow the user to
|
|
181
|
+
decide how to re-stage changes from formatting. The result is more manual
|
|
182
|
+
effort compared to git-format-staged.
|
|
169
183
|
- the one-liner
|
|
170
184
|
`git diff --diff-filter=d --cached | grep '^[+-]' | grep -Ev '^(--- a/|\+\+\+ b/)' | LINT_COMMAND`
|
|
171
185
|
(described [here][lint changed hunks]) extracts changed hunks and feeds them
|
|
@@ -175,5 +189,6 @@ Some more comparisons:
|
|
|
175
189
|
|
|
176
190
|
[precise-commits]: https://github.com/nrwl/precise-commits
|
|
177
191
|
[pre-commit]: https://pre-commit.com/#pre-commit-during-commits
|
|
192
|
+
[pretty-quick]: https://www.npmjs.com/package/pretty-quick
|
|
178
193
|
[lint-staged]: https://github.com/okonet/lint-staged
|
|
179
194
|
[lint changed hunks]: https://github.com/okonet/lint-staged/issues/62#issuecomment-383217916
|
package/git-format-staged
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# ignoring unstaged changes.
|
|
8
8
|
#
|
|
9
9
|
# Usage: git-format-staged [OPTION]... [FILE]...
|
|
10
|
-
# Example: git-format-staged --formatter 'prettier --stdin' '*.js'
|
|
10
|
+
# Example: git-format-staged --formatter 'prettier --stdin-filepath "{}"' '*.js'
|
|
11
11
|
#
|
|
12
12
|
# Tested with Python 3.6 and Python 2.7.
|
|
13
13
|
#
|
|
@@ -22,8 +22,8 @@ import re
|
|
|
22
22
|
import subprocess
|
|
23
23
|
import sys
|
|
24
24
|
|
|
25
|
-
# The string 2.
|
|
26
|
-
VERSION = '2.
|
|
25
|
+
# The string 2.1.3 is replaced during the publish process.
|
|
26
|
+
VERSION = '2.1.3'
|
|
27
27
|
PROG = sys.argv[0]
|
|
28
28
|
|
|
29
29
|
def info(msg):
|
|
@@ -48,6 +48,9 @@ def format_staged_files(file_patterns, formatter, git_root, update_working_tree=
|
|
|
48
48
|
for line in output.splitlines():
|
|
49
49
|
entry = parse_diff(line.decode('utf-8'))
|
|
50
50
|
entry_path = normalize_path(entry['src_path'], relative_to=git_root)
|
|
51
|
+
if entry['dst_mode'] == '120000':
|
|
52
|
+
# Do not process symlinks
|
|
53
|
+
continue
|
|
51
54
|
if not (matches_some_path(file_patterns, entry_path)):
|
|
52
55
|
continue
|
|
53
56
|
if format_file_in_index(formatter, entry, update_working_tree=update_working_tree, write=write):
|
|
@@ -60,12 +63,18 @@ def format_staged_files(file_patterns, formatter, git_root, update_working_tree=
|
|
|
60
63
|
# Returns hash of the new object if formatting produced any changes.
|
|
61
64
|
def format_file_in_index(formatter, diff_entry, update_working_tree=True, write=True):
|
|
62
65
|
orig_hash = diff_entry['dst_hash']
|
|
63
|
-
new_hash = format_object(formatter, orig_hash)
|
|
66
|
+
new_hash = format_object(formatter, orig_hash, diff_entry['src_path'])
|
|
64
67
|
|
|
65
68
|
# If the new hash is the same then the formatter did not make any changes.
|
|
66
69
|
if not write or new_hash == orig_hash:
|
|
67
70
|
return None
|
|
68
71
|
|
|
72
|
+
# If the content of the new object is empty then the formatter did not
|
|
73
|
+
# produce any output. We want to abort instead of replacing the file with an
|
|
74
|
+
# empty one.
|
|
75
|
+
if object_is_empty(new_hash):
|
|
76
|
+
return None
|
|
77
|
+
|
|
69
78
|
replace_file_in_index(diff_entry, new_hash)
|
|
70
79
|
|
|
71
80
|
if update_working_tree:
|
|
@@ -77,16 +86,17 @@ def format_file_in_index(formatter, diff_entry, update_working_tree=True, write=
|
|
|
77
86
|
|
|
78
87
|
return new_hash
|
|
79
88
|
|
|
89
|
+
file_path_placeholder = re.compile('\{\}')
|
|
80
90
|
|
|
81
91
|
# Run formatter on a git blob identified by its hash. Writes output to a new git
|
|
82
92
|
# blob, and returns the hash of the new blob.
|
|
83
|
-
def format_object(formatter, object_hash):
|
|
93
|
+
def format_object(formatter, object_hash, file_path):
|
|
84
94
|
get_content = subprocess.Popen(
|
|
85
95
|
['git', 'cat-file', '-p', object_hash],
|
|
86
96
|
stdout=subprocess.PIPE
|
|
87
97
|
)
|
|
88
98
|
format_content = subprocess.Popen(
|
|
89
|
-
formatter,
|
|
99
|
+
re.sub(file_path_placeholder, file_path, formatter),
|
|
90
100
|
shell=True,
|
|
91
101
|
stdin=get_content.stdout,
|
|
92
102
|
stdout=subprocess.PIPE
|
|
@@ -113,6 +123,18 @@ def format_object(formatter, object_hash):
|
|
|
113
123
|
|
|
114
124
|
return new_hash.decode('utf-8').rstrip()
|
|
115
125
|
|
|
126
|
+
def object_is_empty(object_hash):
|
|
127
|
+
get_content = subprocess.Popen(
|
|
128
|
+
['git', 'cat-file', '-p', object_hash],
|
|
129
|
+
stdout=subprocess.PIPE
|
|
130
|
+
)
|
|
131
|
+
content, err = get_content.communicate()
|
|
132
|
+
|
|
133
|
+
if get_content.returncode != 0:
|
|
134
|
+
raise Exception('unable to verify content of formatted object')
|
|
135
|
+
|
|
136
|
+
return not content
|
|
137
|
+
|
|
116
138
|
def replace_file_in_index(diff_entry, new_object_hash):
|
|
117
139
|
subprocess.check_call(['git', 'update-index',
|
|
118
140
|
'--cacheinfo', '{},{},{}'.format(
|
|
@@ -209,12 +231,12 @@ class CustomArgumentParser(argparse.ArgumentParser):
|
|
|
209
231
|
if __name__ == '__main__':
|
|
210
232
|
parser = CustomArgumentParser(
|
|
211
233
|
description='Transform staged files using a formatting command that accepts content via stdin and produces a result via stdout.',
|
|
212
|
-
epilog='Example: %(prog)s --formatter "prettier --stdin" "src/*.js" "test/*.js"'
|
|
234
|
+
epilog='Example: %(prog)s --formatter "prettier --stdin-filepath \'{}\'" "src/*.js" "test/*.js"'
|
|
213
235
|
)
|
|
214
236
|
parser.add_argument(
|
|
215
237
|
'--formatter', '-f',
|
|
216
238
|
required=True,
|
|
217
|
-
help='Shell command to format files, will run once per file. (Example: "prettier --stdin")'
|
|
239
|
+
help='Shell command to format files, will run once per file. Occurrences of the placeholder `{}` will be replaced with a path to the file being formatted. (Example: "prettier --stdin-filepath \'{}\'")'
|
|
218
240
|
)
|
|
219
241
|
parser.add_argument(
|
|
220
242
|
'--no-update-working-tree',
|
|
@@ -224,7 +246,7 @@ if __name__ == '__main__':
|
|
|
224
246
|
parser.add_argument(
|
|
225
247
|
'--no-write',
|
|
226
248
|
action='store_true',
|
|
227
|
-
help='Prevents %(prog)s from modifying staged or working tree files. You can use this option to check staged changes with a linter instead of formatting. With this option stdout from the formatter command is ignored. Example: %(prog)s --no-write -f "eslint --stdin >&2" "*.js"'
|
|
249
|
+
help='Prevents %(prog)s from modifying staged or working tree files. You can use this option to check staged changes with a linter instead of formatting. With this option stdout from the formatter command is ignored. Example: %(prog)s --no-write -f "eslint --stdin --stdin-filename \'{}\' >&2" "*.js"'
|
|
228
250
|
)
|
|
229
251
|
parser.add_argument(
|
|
230
252
|
'--version',
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-format-staged",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Git command to transform staged files according to a command that accepts file content on stdin and produces output on stdout.",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"precommit": "./git-format-staged --formatter prettier-standard '*.js'",
|
|
7
|
-
"commitmsg": "commitlint -e $GIT_PARAMS",
|
|
8
6
|
"test": "ava",
|
|
9
7
|
"prepublishOnly": "sed -i \"s/\\$VERSION/$npm_package_version/\" git-format-staged",
|
|
10
8
|
"semantic-release": "semantic-release"
|
|
11
9
|
},
|
|
12
|
-
"bin":
|
|
10
|
+
"bin": {
|
|
11
|
+
"git-format-staged": "git-format-staged"
|
|
12
|
+
},
|
|
13
13
|
"main": "./no-main.js",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
@@ -29,32 +29,40 @@
|
|
|
29
29
|
"git-format-staged"
|
|
30
30
|
],
|
|
31
31
|
"release": {
|
|
32
|
-
"
|
|
32
|
+
"branches": "master"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@
|
|
36
|
-
"@commitlint/
|
|
37
|
-
"@
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
35
|
+
"@commitlint/cli": "^8.3.5",
|
|
36
|
+
"@commitlint/config-conventional": "^8.3.4",
|
|
37
|
+
"@types/fs-extra": "^8.1.0",
|
|
38
|
+
"@types/tmp": "^0.1.0",
|
|
39
|
+
"ava": "^3.8.1",
|
|
40
|
+
"eslint": "^5.16.0",
|
|
41
|
+
"fs-extra": "^9.0.0",
|
|
42
|
+
"husky": "^4.2.5",
|
|
43
|
+
"micromatch": "^4.0.2",
|
|
44
|
+
"prettier-standard": "^9.1.1",
|
|
45
|
+
"semantic-release": "^17.2.3",
|
|
46
|
+
"strip-indent": "^3.0.0",
|
|
47
|
+
"tmp": "0.2.0",
|
|
48
|
+
"ts-node": "^8.9.1",
|
|
49
|
+
"typescript": "^3.8.3"
|
|
46
50
|
},
|
|
47
51
|
"ava": {
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
"color": false,
|
|
52
|
+
"extensions": [
|
|
53
|
+
"ts"
|
|
54
|
+
],
|
|
55
|
+
"require": [
|
|
56
|
+
"ts-node/register"
|
|
57
|
+
],
|
|
56
58
|
"files": [
|
|
57
|
-
"test/**/*_test.
|
|
59
|
+
"test/**/*_test.ts"
|
|
58
60
|
]
|
|
61
|
+
},
|
|
62
|
+
"husky": {
|
|
63
|
+
"hooks": {
|
|
64
|
+
"commit-msg": "commitlint -e $HUSKY_GIT_PARAMS",
|
|
65
|
+
"pre-commit": "./git-format-staged --formatter prettier-standard '*.js'"
|
|
66
|
+
}
|
|
59
67
|
}
|
|
60
68
|
}
|