git_stage_formatter 2.2.0 → 3.0.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.releaserc.yaml +3 -0
- data/.travis.yml +3 -2
- data/CHANGELOG.md +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +34 -0
- data/README.md +59 -22
- data/Rakefile +21 -0
- data/git-format-staged +26 -14
- data/git_stage_formatter.gemspec +26 -0
- data/lib/git_stage_formatter/version.rb +1 -1
- data/lib/git_stage_formatter.rb +2 -1
- data/package-lock.json +16327 -6227
- data/package.json +1 -4
- metadata +13 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64a3dd9bf65c6bb93cb17974466d6a638bf68690e61a3ec9c113db4be63a6ac1
|
4
|
+
data.tar.gz: ded69b5da94227a628edb0c2f2341f960a340a3113fa8587b6be1f0405226346
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d6523769d0021592706c94ce8f9b47bce70abaa8b74d9c025c4bc33ff65803fd60381fc0e38882dcd1993ce8b3ae9d86e21cfbf0f7a046eb89b0bbfa8d495a0
|
7
|
+
data.tar.gz: 70492bc58d979e5105524e168353a82d2216f946cf1b776d774ff21fa22e9ab31277fd6e1c1438ee321d32e5df538ab7d87b067dc06b7dd64eb07c668fb4621e
|
data/.gitignore
CHANGED
data/.releaserc.yaml
ADDED
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
git_stage_formatter (3.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
pastel (0.8.0)
|
10
|
+
tty-color (~> 0.5)
|
11
|
+
rake (13.0.6)
|
12
|
+
tty-color (0.6.0)
|
13
|
+
tty-cursor (0.7.1)
|
14
|
+
tty-prompt (0.23.1)
|
15
|
+
pastel (~> 0.8)
|
16
|
+
tty-reader (~> 0.8)
|
17
|
+
tty-reader (0.9.0)
|
18
|
+
tty-cursor (~> 0.7)
|
19
|
+
tty-screen (~> 0.8)
|
20
|
+
wisper (~> 2.0)
|
21
|
+
tty-screen (0.8.1)
|
22
|
+
wisper (2.0.1)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
arm64-darwin-21
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
bundler (~> 2)
|
29
|
+
git_stage_formatter!
|
30
|
+
rake
|
31
|
+
tty-prompt
|
32
|
+
|
33
|
+
BUNDLED WITH
|
34
|
+
2.4.18
|
data/README.md
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
[](https://travis-ci.org/hallettj/git-format-staged)
|
4
4
|
|
5
5
|
Consider a project where you want all code formatted consistently. So you use
|
6
|
-
a formatting command. (For example I use [prettier
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
a formatting command. (For example I use [prettier][] in my Javascript and
|
7
|
+
Typescript projects.) You want to make sure that everyone working on the project
|
8
|
+
runs the formatter, so you use a tool like [husky][] to install a git pre-commit
|
9
|
+
hook. The naive way to write that hook would be to:
|
10
10
|
|
11
11
|
- get a list of staged files
|
12
12
|
- run the formatter on those files
|
@@ -30,14 +30,15 @@ version of the file that is committed will be formatted properly - the warning
|
|
30
30
|
just means that working tree copy of the file has been left unformatted. The
|
31
31
|
patch step can be disabled with the `--no-update-working-tree` option.
|
32
32
|
|
33
|
-
[prettier
|
33
|
+
[prettier]: https://prettier.io/
|
34
34
|
[husky]: https://www.npmjs.com/package/husky
|
35
35
|
|
36
|
-
|
37
36
|
## How to install
|
38
37
|
|
39
38
|
Requires Python version 3 or 2.7.
|
40
39
|
|
40
|
+
### npm
|
41
|
+
|
41
42
|
Install as a development dependency in a project that uses npm packages:
|
42
43
|
|
43
44
|
$ npm install --save-dev git-format-staged
|
@@ -46,11 +47,25 @@ Or install globally:
|
|
46
47
|
|
47
48
|
$ npm install --global git-format-staged
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
### bundler
|
51
|
+
|
52
|
+
Add this gem to your Gemfile:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
gem 'git_stage_formatter'
|
56
|
+
```
|
57
|
+
|
58
|
+
### gem
|
53
59
|
|
60
|
+
Install the binary via gem:
|
61
|
+
|
62
|
+
```sh
|
63
|
+
gem install git_stage_formatter
|
64
|
+
```
|
65
|
+
|
66
|
+
### Manually
|
67
|
+
|
68
|
+
If you don't use `npm`, `bundler` or `gem`, you can copy the [`git-format-staged`](./git-format-staged) script from this repository and place it in your executable path, or somewhere convenient. The script is MIT-licensed - so you can check the script into version control in your own open source project if you wish.
|
54
69
|
|
55
70
|
## How to use
|
56
71
|
|
@@ -61,7 +76,7 @@ For detailed information run:
|
|
61
76
|
The command expects a shell command to run a formatter, and one or more file
|
62
77
|
patterns to identify which files should be formatted. For example:
|
63
78
|
|
64
|
-
$ git-format-staged --formatter 'prettier --stdin
|
79
|
+
$ git-format-staged --formatter 'prettier --stdin-filepath "{}"' 'src/*.js'
|
65
80
|
|
66
81
|
That will format all files under `src/` and its subdirectories using
|
67
82
|
`prettier`. The file pattern is tested against staged files using Python's
|
@@ -73,9 +88,16 @@ file names.
|
|
73
88
|
The formatter command must read file content from `stdin`, and output formatted
|
74
89
|
content to `stdout`.
|
75
90
|
|
91
|
+
Note that the syntax of the `fnmatch` glob match is a is a bit different from
|
92
|
+
normal shell globbing. So if you need to match multiple patterns, you should
|
93
|
+
pass multiple arguments with different patterns, and they will be grouped.
|
94
|
+
So instead of e.g. `'src/**/*.{js,jsx,ts}'`, you would use:
|
95
|
+
|
96
|
+
$ git-format-staged --formatter 'prettier --stdin-filepath "{}"' 'src/*.js' 'src/*.jsx' 'src/*.ts'
|
97
|
+
|
76
98
|
Files can be excluded by prefixing a pattern with `!`. For example:
|
77
99
|
|
78
|
-
$ git-format-staged --formatter 'prettier --stdin' '*.js' '!flow-typed/*'
|
100
|
+
$ git-format-staged --formatter 'prettier --stdin-filepath "{}"' '*.js' '!flow-typed/*'
|
79
101
|
|
80
102
|
Patterns are evaluated from left-to-right: if a file matches multiple patterns
|
81
103
|
the right-most pattern determines whether the file is included or excluded.
|
@@ -89,7 +111,7 @@ with the path of the file that is being formatted. This is useful if your
|
|
89
111
|
formatter needs to know the file extension to determine how to format or to
|
90
112
|
lint each file. For example:
|
91
113
|
|
92
|
-
$ git-format-staged -f 'prettier --stdin
|
114
|
+
$ git-format-staged -f 'prettier --stdin-filepath "{}"' '*.js' '*.css'
|
93
115
|
|
94
116
|
Do not attempt to read or write to `{}` in your formatter command! The
|
95
117
|
placeholder exists only for referencing the file name and path.
|
@@ -116,23 +138,26 @@ notation) so that you can see them.
|
|
116
138
|
Follow these steps to automatically format all Javascript files on commit in
|
117
139
|
a project that uses npm.
|
118
140
|
|
119
|
-
Install git-format-staged, husky, and a formatter (I use prettier
|
141
|
+
Install git-format-staged, husky, and a formatter (I use `prettier`):
|
120
142
|
|
121
|
-
$ npm install --save-dev git-format-staged husky prettier
|
143
|
+
$ npm install --save-dev git-format-staged husky prettier
|
122
144
|
|
123
|
-
Add a `
|
145
|
+
Add a `prepare` script to install husky when running `npm install`:
|
124
146
|
|
125
|
-
"
|
126
|
-
|
127
|
-
}
|
147
|
+
$ npm set-script prepare "husky install"
|
148
|
+
$ npm run prepare
|
128
149
|
|
129
|
-
|
130
|
-
|
150
|
+
Add the pre-commit hook:
|
151
|
+
|
152
|
+
$ npx husky add .husky/pre-commit "git-format-staged --formatter 'prettier --stdin-filepath \"{}\"' '*.js' '*.ts'"
|
153
|
+
$ git add .husky/pre-commit
|
154
|
+
|
155
|
+
Once again note that the formatter command and the `'*.js'` and `'*.ts'`
|
156
|
+
patterns are quoted!
|
131
157
|
|
132
158
|
That's it! Whenever a file is changed as a result of formatting on commit you
|
133
159
|
will see a message in the output from `git commit`.
|
134
160
|
|
135
|
-
|
136
161
|
## Comparisons to similar utilities
|
137
162
|
|
138
163
|
There are other tools that will format or lint staged files. What distinguishes
|
@@ -192,3 +217,15 @@ Some more comparisons:
|
|
192
217
|
[pretty-quick]: https://www.npmjs.com/package/pretty-quick
|
193
218
|
[lint-staged]: https://github.com/okonet/lint-staged
|
194
219
|
[lint changed hunks]: https://github.com/okonet/lint-staged/issues/62#issuecomment-383217916
|
220
|
+
|
221
|
+
# Development
|
222
|
+
|
223
|
+
To bump the lib's version, run `bundle exec rake bump[1.2.3]` (replacing the value with the desired version).
|
224
|
+
|
225
|
+
To release a new version, update the version number in `version.rb` (likely done via `rake bump` above), and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
226
|
+
|
227
|
+
# Contributing
|
228
|
+
|
229
|
+
If you spot something wrong, missing, or if you'd like to propose improvements to this project, please open an Issue or a Pull Request with your ideas and I promise to get back to you within 24 hours! 😇
|
230
|
+
|
231
|
+
For a list of issues worth tackling check out: https://github.com/rogerluan/git_stage_formatter/issues
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "tty-prompt"
|
5
|
+
|
6
|
+
task default: %i[]
|
7
|
+
|
8
|
+
desc "Sets lib version to the semantic version given, and push it to remote."
|
9
|
+
task :bump, [:v] do |_t, args|
|
10
|
+
version = args[:v] || raise("A version is required. Pass it like `rake bump[1.2.3]`")
|
11
|
+
next unless TTY::Prompt.new.yes?("Would you like to set the new version of the app to be '#{version}'?")
|
12
|
+
|
13
|
+
version_filename = Dir.glob("lib/*/version.rb").first
|
14
|
+
version_file_contents = File.read(version_filename)
|
15
|
+
new_version_file_contents = version_file_contents.gsub(/VERSION = "(?:.*)"/, "VERSION = \"#{version}\"")
|
16
|
+
File.open(version_filename, "w") { |file| file.puts new_version_file_contents }
|
17
|
+
sh("bundle install")
|
18
|
+
sh("git add #{version_filename} Gemfile.lock")
|
19
|
+
sh("git commit -m 'Bump app version to v#{version}.'")
|
20
|
+
sh("git push origin")
|
21
|
+
end
|
data/git-format-staged
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/env
|
1
|
+
#!/usr/bin/env python3
|
2
2
|
#
|
3
3
|
# Git command to transform staged files according to a command that accepts file
|
4
4
|
# content on stdin and produces output on stdout. This command is useful in
|
@@ -7,9 +7,9 @@
|
|
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
|
-
# Tested with Python 3.
|
12
|
+
# Tested with Python 3.10 and Python 2.7.
|
13
13
|
#
|
14
14
|
# Original author: Jesse Hallett <jesse@sitr.us>
|
15
15
|
|
@@ -27,7 +27,7 @@ VERSION = '$VERSION'
|
|
27
27
|
PROG = sys.argv[0]
|
28
28
|
|
29
29
|
def info(msg):
|
30
|
-
print(msg, file=sys.
|
30
|
+
print(msg, file=sys.stdout)
|
31
31
|
|
32
32
|
def warn(msg):
|
33
33
|
print('{}: warning: {}'.format(PROG, msg), file=sys.stderr)
|
@@ -36,7 +36,7 @@ def fatal(msg):
|
|
36
36
|
print('{}: error: {}'.format(PROG, msg), file=sys.stderr)
|
37
37
|
exit(1)
|
38
38
|
|
39
|
-
def format_staged_files(file_patterns, formatter, git_root, update_working_tree=True, write=True):
|
39
|
+
def format_staged_files(file_patterns, formatter, git_root, update_working_tree=True, write=True, verbose=False):
|
40
40
|
try:
|
41
41
|
output = subprocess.check_output([
|
42
42
|
'git', 'diff-index',
|
@@ -48,9 +48,12 @@ 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
|
-
if format_file_in_index(formatter, entry, update_working_tree=update_working_tree, write=write):
|
56
|
+
if format_file_in_index(formatter, entry, update_working_tree=update_working_tree, write=write, verbose=verbose):
|
54
57
|
info('Reformatted {} with {}'.format(entry['src_path'], formatter))
|
55
58
|
except Exception as err:
|
56
59
|
fatal(str(err))
|
@@ -58,9 +61,9 @@ def format_staged_files(file_patterns, formatter, git_root, update_working_tree=
|
|
58
61
|
# Run formatter on file in the git index. Creates a new git object with the
|
59
62
|
# result, and replaces the content of the file in the index with that object.
|
60
63
|
# Returns hash of the new object if formatting produced any changes.
|
61
|
-
def format_file_in_index(formatter, diff_entry, update_working_tree=True, write=True):
|
64
|
+
def format_file_in_index(formatter, diff_entry, update_working_tree=True, write=True, verbose=False):
|
62
65
|
orig_hash = diff_entry['dst_hash']
|
63
|
-
new_hash = format_object(formatter, orig_hash, diff_entry['src_path'])
|
66
|
+
new_hash = format_object(formatter, orig_hash, diff_entry['src_path'], verbose=verbose)
|
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:
|
@@ -87,13 +90,16 @@ file_path_placeholder = re.compile('\{\}')
|
|
87
90
|
|
88
91
|
# Run formatter on a git blob identified by its hash. Writes output to a new git
|
89
92
|
# blob, and returns the hash of the new blob.
|
90
|
-
def format_object(formatter, object_hash, file_path):
|
93
|
+
def format_object(formatter, object_hash, file_path, verbose=False):
|
91
94
|
get_content = subprocess.Popen(
|
92
95
|
['git', 'cat-file', '-p', object_hash],
|
93
96
|
stdout=subprocess.PIPE
|
94
97
|
)
|
98
|
+
command = re.sub(file_path_placeholder, file_path, formatter)
|
99
|
+
if verbose:
|
100
|
+
info(command)
|
95
101
|
format_content = subprocess.Popen(
|
96
|
-
|
102
|
+
command,
|
97
103
|
shell=True,
|
98
104
|
stdin=get_content.stdout,
|
99
105
|
stdout=subprocess.PIPE
|
@@ -142,7 +148,7 @@ def replace_file_in_index(diff_entry, new_object_hash):
|
|
142
148
|
|
143
149
|
def patch_working_file(path, orig_object_hash, new_object_hash):
|
144
150
|
patch = subprocess.check_output(
|
145
|
-
['git', 'diff', orig_object_hash, new_object_hash]
|
151
|
+
['git', 'diff', '--no-ext-diff', '--color=never', orig_object_hash, new_object_hash]
|
146
152
|
)
|
147
153
|
|
148
154
|
# Substitute object hashes in patch header with path to working tree file
|
@@ -228,12 +234,12 @@ class CustomArgumentParser(argparse.ArgumentParser):
|
|
228
234
|
if __name__ == '__main__':
|
229
235
|
parser = CustomArgumentParser(
|
230
236
|
description='Transform staged files using a formatting command that accepts content via stdin and produces a result via stdout.',
|
231
|
-
epilog='Example: %(prog)s --formatter "prettier --stdin" "src/*.js" "test/*.js"'
|
237
|
+
epilog='Example: %(prog)s --formatter "prettier --stdin-filepath \'{}\'" "src/*.js" "test/*.js"'
|
232
238
|
)
|
233
239
|
parser.add_argument(
|
234
240
|
'--formatter', '-f',
|
235
241
|
required=True,
|
236
|
-
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
|
242
|
+
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 \'{}\'")'
|
237
243
|
)
|
238
244
|
parser.add_argument(
|
239
245
|
'--no-update-working-tree',
|
@@ -251,6 +257,11 @@ if __name__ == '__main__':
|
|
251
257
|
version='%(prog)s version {}'.format(VERSION),
|
252
258
|
help='Display version of %(prog)s'
|
253
259
|
)
|
260
|
+
parser.add_argument(
|
261
|
+
'--verbose',
|
262
|
+
help='Show the formatting commands that are running',
|
263
|
+
action='store_true'
|
264
|
+
)
|
254
265
|
parser.add_argument(
|
255
266
|
'files',
|
256
267
|
nargs='+',
|
@@ -263,5 +274,6 @@ if __name__ == '__main__':
|
|
263
274
|
formatter=vars(args)['formatter'],
|
264
275
|
git_root=get_git_root(),
|
265
276
|
update_working_tree=not vars(args)['no_update_working_tree'],
|
266
|
-
write=not vars(args)['no_write']
|
277
|
+
write=not vars(args)['no_write'],
|
278
|
+
verbose=vars(args)['verbose']
|
267
279
|
)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/git_stage_formatter/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "git_stage_formatter"
|
7
|
+
spec.version = GitStageFormatter::VERSION
|
8
|
+
spec.authors = ["Roger Oba"]
|
9
|
+
spec.email = ["rogerluan.oba@gmail.com"]
|
10
|
+
spec.summary = "Script to transform staged files using a formatting command"
|
11
|
+
spec.homepage = "https://github.com/rogerluan/git_stage_formatter"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
14
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
15
|
+
spec.metadata["source_code_uri"] = "https://github.com/rogerluan/git_stage_formatter"
|
16
|
+
spec.metadata["changelog_uri"] = "https://github.com/rogerluan/git_stage_formatter/blob/master/CHANGELOG.md"
|
17
|
+
|
18
|
+
# Specify which files should be added to the gem when it is released.
|
19
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
22
|
+
end
|
23
|
+
spec.bindir = "bin"
|
24
|
+
spec.executables = ['git_stage_formatter']
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
end
|
data/lib/git_stage_formatter.rb
CHANGED
@@ -2,7 +2,8 @@ require_relative "git_stage_formatter/version"
|
|
2
2
|
|
3
3
|
module GitStageFormatter
|
4
4
|
def self.run(args)
|
5
|
-
|
5
|
+
# Wrap each argument in quotes to handle spaces in paths
|
6
|
+
args = args.map { |arg| "\"#{arg}\"" }.join(' ')
|
6
7
|
script_path = File.expand_path('../git-format-staged', File.dirname(__FILE__))
|
7
8
|
exec("#{script_path} #{args}")
|
8
9
|
end
|