git_stage_formatter 2.2.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e24f5f48a24491053f2e2220ce055df6f61c6207a750f5a8ff6098afbde4120a
4
- data.tar.gz: 54553233ebdb102c78ab79d8a660c12f8df10647f3cfb65c22397516d8f0b965
3
+ metadata.gz: 64a3dd9bf65c6bb93cb17974466d6a638bf68690e61a3ec9c113db4be63a6ac1
4
+ data.tar.gz: ded69b5da94227a628edb0c2f2341f960a340a3113fa8587b6be1f0405226346
5
5
  SHA512:
6
- metadata.gz: 20911e08c4169554122387169899c2d93f9b0be2ef7d305370c059dba9be6ab88a8553efdbf0fbb74598a31ea62cc7945a04dcb416379fb7abef8f1d677700f4
7
- data.tar.gz: d86c46ed60800b49fd8ee4132226e97483a1fb15060d08642984d55fc23096f2d8147ea04a835763d48ef8c25ff1e05d7afd87472f6a8a745039b41872bc0b9c
6
+ metadata.gz: 5d6523769d0021592706c94ce8f9b47bce70abaa8b74d9c025c4bc33ff65803fd60381fc0e38882dcd1993ce8b3ae9d86e21cfbf0f7a046eb89b0bbfa8d495a0
7
+ data.tar.gz: 70492bc58d979e5105524e168353a82d2216f946cf1b776d774ff21fa22e9ab31277fd6e1c1438ee321d32e5df538ab7d87b067dc06b7dd64eb07c668fb4621e
data/.gitignore CHANGED
@@ -4,7 +4,7 @@ yarn-error.log
4
4
 
5
5
  # Ruby
6
6
  .bundle
7
- Gemfile.lock
7
+ /pkg/
8
8
 
9
9
  # Misc
10
10
  .DS_Store
data/.releaserc.yaml ADDED
@@ -0,0 +1,3 @@
1
+ branches:
2
+ - +([0-9])?(.{+([0-9]),x}).x # maintenance branches of the form 2.x
3
+ - release # pushes to `release` branch trigger automatic publish
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
+ dist: focal
1
2
  language: python
2
3
  python:
3
- - 3.8
4
- - 3.6
4
+ - 3.10
5
+ - 3.9
5
6
  - 2.7
6
7
 
7
8
  cache:
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 2.2.0 - RubyGem Support!
4
+
5
+ #### 2021-05-22
6
+
7
+ - Initial RubyGem support! Now you can install this script by adding `gem 'git_stage_formatter'` to your Gemfile, or by running `gem install git_stage_formatter` 🎉
data/Gemfile CHANGED
@@ -4,3 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  # Gem dependencies specified in git_stage_formatter.gemspec
6
6
  gemspec
7
+
8
+ gem "bundler", "~> 2"
9
+ gem "rake"
10
+ gem "tty-prompt"
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
  [![Build Status](https://travis-ci.org/hallettj/git-format-staged.svg?branch=master)](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-standard][] in my
7
- Javascript projects.) You want to make sure that everyone working on the
8
- project runs the formatter, so you use a tool like [husky][] to install a git
9
- pre-commit hook. The naive way to write that hook would be to:
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-standard]: https://www.npmjs.com/package/prettier-standard
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
- If you do not use npm you can copy the
50
- [`git-format-staged`](./git-format-staged) script from this repository and
51
- place it in your executable path. The script is MIT-licensed - so you can check
52
- the script into version control in your own open source project if you wish.
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 --stdin-filepath "{}"' 'src/*.js'
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 --stdin-filepath "{}"' '*.js' '*.css'
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-standard):
141
+ Install git-format-staged, husky, and a formatter (I use `prettier`):
120
142
 
121
- $ npm install --save-dev git-format-staged husky prettier-standard
143
+ $ npm install --save-dev git-format-staged husky prettier
122
144
 
123
- Add a `"precommit"` script in `package.json`:
145
+ Add a `prepare` script to install husky when running `npm install`:
124
146
 
125
- "scripts": {
126
- "precommit": "git-format-staged -f prettier-standard '*.js'"
127
- }
147
+ $ npm set-script prepare "husky install"
148
+ $ npm run prepare
128
149
 
129
- Once again note that the `'*.js'` pattern is quoted! If the formatter command
130
- included arguments it would also need to be quoted.
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 python
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.6 and Python 2.7.
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.stderr)
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
- re.sub(file_path_placeholder, file_path, formatter),
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 --stdin-filepath \'{}\'")'
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GitStageFormatter
4
- VERSION = "2.2.0"
4
+ VERSION = "3.0.1"
5
5
  end
@@ -2,7 +2,8 @@ require_relative "git_stage_formatter/version"
2
2
 
3
3
  module GitStageFormatter
4
4
  def self.run(args)
5
- args = args.join(' ')
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