pr-with-params 1.3.0 → 2.0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +0 -5
- data/Gemfile.lock +24 -10
- data/README.md +10 -7
- data/bin/console +1 -1
- data/bin/setup +1 -1
- data/exe/pr-wip +6 -0
- data/lib/pr_with_params/cli.rb +77 -0
- data/lib/pr_with_params/config_parser.rb +51 -0
- data/lib/pr_with_params/options_validator.rb +44 -0
- data/lib/pr_with_params/version.rb +5 -0
- data/lib/pr_with_params.rb +4 -0
- data/pr-with-params.gemspec +9 -7
- metadata +98 -12
- data/exe/pr-with-params +0 -100
- data/lib/pr/with/params/config_parser.rb +0 -53
- data/lib/pr/with/params/options_validator.rb +0 -46
- data/lib/pr/with/params/version.rb +0 -9
- data/lib/pr/with/params.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb5d7b7436528a5a08568892974cc238bd5ffc1dd6fb40e2157be5600b72dd04
|
4
|
+
data.tar.gz: 8904c400e3fc49e1ac68f1434279af3d2b2a92f8c39fddc0b0b4b35c825d3b5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00473d4b542df9d312c51f8e6801b2050109108780f914fe49cd5f5048493792d002ab3bfb5b992461644352612e9cfc2c70ff80d010fcfc32d71596d14f7379
|
7
|
+
data.tar.gz: 4b86fc3db6832b59830123dce6a2b1077b90fc312d28cd360bcc648a931692680c03059c218e7acd2d8da3ccdbc3886541dd98ee677ed699347d3a5d1d523fbe
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
## [2.0.0] - 2023-06-05
|
2
|
+
|
3
|
+
To migrate to this version, simply run `gem update pr-with-params`
|
4
|
+
|
5
|
+
### Added
|
6
|
+
- Ability to specify a list of validators to run as an option
|
7
|
+
- Ability to set `ignore_conventional_commits` in config file
|
8
|
+
- Default path for config file at `~/.pwp/config.yml`
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
- `--conf` is now `--config_path` or `-path` or `-p`
|
12
|
+
- Make specifying config path optional - was previously a required
|
13
|
+
- CLI name is now `pr-wip` - was previously `pr-with-params`
|
14
|
+
- `--validate-conventional-commits` is now `--ignore-conventional-commits` - optionally turn off versus optionally turn on
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
- Occasional failures related to `launchy` not being loaded properly
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,21 +1,33 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pr-with-params (
|
4
|
+
pr-with-params (2.0.0)
|
5
|
+
activesupport
|
6
|
+
launchy (~> 2.5)
|
7
|
+
rake (~> 13.0)
|
8
|
+
thor
|
5
9
|
|
6
10
|
GEM
|
7
11
|
remote: https://rubygems.org/
|
8
12
|
specs:
|
9
|
-
|
10
|
-
|
13
|
+
activesupport (7.0.5)
|
14
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
+
i18n (>= 1.6, < 2)
|
16
|
+
minitest (>= 5.1)
|
17
|
+
tzinfo (~> 2.0)
|
18
|
+
addressable (2.8.4)
|
19
|
+
public_suffix (>= 2.0.2, < 6.0)
|
11
20
|
ast (2.4.2)
|
12
|
-
|
13
|
-
|
14
|
-
|
21
|
+
concurrent-ruby (1.2.2)
|
22
|
+
i18n (1.14.1)
|
23
|
+
concurrent-ruby (~> 1.0)
|
24
|
+
launchy (2.5.2)
|
25
|
+
addressable (~> 2.8)
|
26
|
+
minitest (5.18.0)
|
15
27
|
parallel (1.22.1)
|
16
28
|
parser (3.1.2.0)
|
17
29
|
ast (~> 2.4.1)
|
18
|
-
public_suffix (
|
30
|
+
public_suffix (5.0.1)
|
19
31
|
rainbow (3.1.1)
|
20
32
|
rake (13.0.6)
|
21
33
|
regexp_parser (2.5.0)
|
@@ -32,16 +44,18 @@ GEM
|
|
32
44
|
rubocop-ast (1.19.1)
|
33
45
|
parser (>= 3.1.1.0)
|
34
46
|
ruby-progressbar (1.11.0)
|
47
|
+
thor (1.2.2)
|
48
|
+
tzinfo (2.0.6)
|
49
|
+
concurrent-ruby (~> 1.0)
|
35
50
|
unicode-display_width (1.8.0)
|
36
51
|
|
37
52
|
PLATFORMS
|
38
53
|
arm64-darwin-21
|
54
|
+
arm64-darwin-22
|
39
55
|
|
40
56
|
DEPENDENCIES
|
41
|
-
|
42
|
-
minitest (~> 5.0)
|
57
|
+
minitest (~> 5.18.0)
|
43
58
|
pr-with-params!
|
44
|
-
rake (~> 13.0)
|
45
59
|
rubocop (~> 0.80)
|
46
60
|
|
47
61
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#
|
2
|
-
A lightweight gem that pushes current local branch to remote with upstream at origin/[local-branch-name]. It also opens a new pull request browser window at a URL with customized query params, based on specified options, which pre-populates certain fields in the pull request. This is especially useful when supporting multiple PR templates within a code base.
|
1
|
+
# PRWithParams [](https://badge.fury.io/rb/pr-with-params)
|
2
|
+
A lightweight ruby gem that pushes current local branch to remote with upstream at origin/[local-branch-name]. It also opens a new pull request browser window at a URL with customized query params, based on specified options, which pre-populates certain fields in the pull request. This is especially useful when supporting multiple PR templates within a code base.
|
3
3
|
|
4
4
|
Inspired by GitHub's documentation on [using query params to create pull requets](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/using-query-parameters-to-create-a-pull-request)
|
5
5
|
|
@@ -21,13 +21,15 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
24
|
+
NOTE: CLI name has changed as of v2.0.0 from `pr-with-params` to `pr-wip` along with some other breaking changes. See changelog for more details
|
25
|
+
|
24
26
|
Assuming you've committed your changes and your local branch is ready to be pushed, run:
|
25
27
|
|
26
28
|
```
|
27
|
-
$ pr-
|
29
|
+
$ pr-wip -t new_feature_template.md -l 'work in progress'
|
28
30
|
```
|
29
31
|
|
30
|
-
For a full list of options, run `$ pr-
|
32
|
+
For a full list of options, run `$ pr-wip -h`
|
31
33
|
|
32
34
|
#### Using Config File
|
33
35
|
|
@@ -46,8 +48,8 @@ bug_fix:
|
|
46
48
|
labels: bug,urgent
|
47
49
|
```
|
48
50
|
|
49
|
-
* To run with config file, use `$ pr-
|
50
|
-
* If you specify a config file (`--
|
51
|
+
* To run with config file, use `$ pr-wip --config_path='path/to/file.yml' --scope=bug_fix`. If `--scope` option is not specified, only `:default` scope will apply.
|
52
|
+
* If you specify a config file (`--config_path`) and also pass options by flag (e.g `--base-branch=develop`), the flag value will override the config value.
|
51
53
|
* All your defaults go in the `:default` scope.
|
52
54
|
* Only fields defined in another scope will override the defaults. In the example above, the final list of configs will be:
|
53
55
|
|
@@ -59,6 +61,7 @@ bug_fix:
|
|
59
61
|
| Config | Type | Example |
|
60
62
|
| :--- | :---: | :--- |
|
61
63
|
| validators | `Array` | \`[conventional_commits]\` |
|
64
|
+
| ignore_conventional_commits | `Boolean` | true |
|
62
65
|
| base_branch | `String` | develop |
|
63
66
|
| template | `String` | new_feature_template.md |
|
64
67
|
| title | `String` | 'Update login screen' |
|
@@ -66,7 +69,7 @@ bug_fix:
|
|
66
69
|
| assignees | `String` | 2k-joker |
|
67
70
|
|
68
71
|
#### Validators
|
69
|
-
* **Conventional Commits**: Gem supports validation of conventional commits for PR `:title
|
72
|
+
* **Conventional Commits**: Gem supports validation of conventional commits for PR `:title` by default. This is to encourage users to follow [conventional commit specs](https://www.conventionalcommits.org/en/v1.0.0/#specification). To turn it off, pass the `--ignore-conventional-commits` flag or add `conventional_commits` to the list of validators in your config file or set `ignore_conventional_commits: true` in your config file.
|
70
73
|
|
71
74
|
## Development
|
72
75
|
|
data/bin/console
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "bundler/setup"
|
5
|
-
require "
|
5
|
+
require "pr_with_params"
|
6
6
|
|
7
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
8
8
|
# with your gem easier. You can also use a different console, if you like.
|
data/bin/setup
CHANGED
data/exe/pr-wip
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'active_support/core_ext/hash'
|
2
|
+
require 'thor'
|
3
|
+
require 'launchy'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module PRWithParams
|
7
|
+
class CLI < Thor
|
8
|
+
desc "open", "Open a new pull request for local branch"
|
9
|
+
long_desc <<-LONGDESC
|
10
|
+
`pr-wip open [options]` will open a new browser window with a pull request at a URL with customized query params from <options>.
|
11
|
+
|
12
|
+
The pull request will be pre-populated with certain fields based on custom query params
|
13
|
+
LONGDESC
|
14
|
+
option :template, type: :string, aliases: ['-t'], desc: 'Specify the filename of the target custom PR template (e.g: bug_squash_template.md). Will use default template otherwise.'
|
15
|
+
option :config_path, type: :string, aliases: ['-path', '-p'], default: '/.pwp/config.yml', desc: 'Path to yaml file where configs are defined. Defaults to: ~/.pwp/config.yml'
|
16
|
+
option :scope, type: :string, aliases: ['-s'], default: 'default', desc: 'Specify the scope name under which options are defined.'
|
17
|
+
option :base_branch, type: :string, aliases: ['-b'], desc: 'Specify the base branch for your PR (e.g: develop). Will use default branch otherwise.'
|
18
|
+
option :title, type: :string, aliases: ['-d', '-desc', '--description'], desc: 'Specify a custom PR title. Will use the first branch commit message otherwise.'
|
19
|
+
option :labels, type: :string, aliases: ['-l'], desc: "Specify a list of labels (e.g: 'help+wanted,bug,urgent,work+in+progress')."
|
20
|
+
option :assignees, type: :string, aliases: ['-a'], desc: "Specify a list of assignees (e.g: 'octocat,codedog')."
|
21
|
+
option :validators, type: :array, default: [:conventional_commits], desc: 'Specify a list of validations to run against local branch before opening pull request'
|
22
|
+
option :ignore_conventional_commits, type: :boolean, desc: 'Allow PR titles that do not conform to conventional commits spec.'
|
23
|
+
def open
|
24
|
+
home_dir_path = `echo $HOME`.chomp
|
25
|
+
config_file_path = "#{home_dir_path}/#{options[:config_path].delete_prefix('/')}"
|
26
|
+
config_options = (options[:config_path].empty? ? {} : PRWithParams::ConfigParser.new(config_file_path: config_file_path, scope: options[:scope]).parse!).with_indifferent_access
|
27
|
+
options[:validators].delete(:conventional_commits) if options[:ignore_conventional_commits]
|
28
|
+
all_options = config_options.merge(options)
|
29
|
+
|
30
|
+
branch_name = `git rev-parse --abbrev-ref HEAD`.chomp
|
31
|
+
base_branch = all_options.delete(:base_branch) || `git remote show origin | grep "HEAD branch" | sed 's/.*: //'`.chomp
|
32
|
+
|
33
|
+
default_title = `git show-branch --no-name $(git log #{base_branch}..#{branch_name} --pretty=format:"%h" | tail -1)`.chomp
|
34
|
+
all_options[:title] ||= default_title
|
35
|
+
|
36
|
+
puts all_options
|
37
|
+
puts options
|
38
|
+
PRWithParams::OptionsValidator.validate!(all_options.except(:validators), validators: all_options[:validators])
|
39
|
+
|
40
|
+
remote_git_uri = `git config --get remote.origin.url`.sub('git@github.com:', '').sub('.git', '').chomp
|
41
|
+
uri_path = "/#{remote_git_uri}/compare/#{base_branch}...#{branch_name}"
|
42
|
+
|
43
|
+
push_local_to_remote(branch_name, base_branch, remote_git_uri)
|
44
|
+
open_pr_in_browser(uri_path, all_options)
|
45
|
+
rescue StandardError => e
|
46
|
+
message = "\e[31mERROR\e[0m: An error occurred while building or opening your custom pull request URL"
|
47
|
+
reason = "reason: #{e.message}"
|
48
|
+
backtrace = "backtrace: #{e.backtrace&.last(10)&.join("\n")}"
|
49
|
+
error_message = [message, reason, backtrace, "\n\n"].join("\n")
|
50
|
+
|
51
|
+
warn error_message
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def push_local_to_remote(branch_name, base_branch, remote_git_uri)
|
58
|
+
puts "current branch: \e[36m#{branch_name}\e[0m"
|
59
|
+
puts "base branch: \e[36m#{base_branch}\e[0m"
|
60
|
+
puts "repo path: \e[36m#{remote_git_uri}\e[0m"
|
61
|
+
|
62
|
+
push_message = "\nPushing your local branch to origin/#{branch_name}..."
|
63
|
+
puts "\e[32m#{push_message}\e[0m"
|
64
|
+
`sleep 1`
|
65
|
+
|
66
|
+
system("git push -u origin #{branch_name}", exception: true)
|
67
|
+
end
|
68
|
+
|
69
|
+
def open_pr_in_browser(uri_path, options)
|
70
|
+
uri_host = 'www.github.com'
|
71
|
+
uri_query = URI.encode_www_form(options)
|
72
|
+
url_string = URI::HTTPS.build(host: uri_host, path: uri_path, query: uri_query).to_s
|
73
|
+
|
74
|
+
Launchy.open(url_string)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module PRWithParams
|
4
|
+
class ConfigParser
|
5
|
+
class ParserError < StandardError; end
|
6
|
+
|
7
|
+
# Attributes
|
8
|
+
attr_reader :config_file_path, :scope, :parsed_config, :filtered_config
|
9
|
+
|
10
|
+
# Constants
|
11
|
+
VALID_CONFIG_KEYS = %i[validators base_branch template title labels assignees].freeze
|
12
|
+
|
13
|
+
def initialize(config_file_path:, scope: nil)
|
14
|
+
@config_file_path = config_file_path
|
15
|
+
@scope = scope&.to_sym || :default
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse!
|
19
|
+
validate_file_type!
|
20
|
+
parse_yaml_config
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def parse_yaml_config
|
26
|
+
@parsed_config = YAML.safe_load(IO.read(config_file_path)).to_h.transform_keys(&:to_sym)
|
27
|
+
@filtered_config = scoped_config.transform_keys(&:to_sym).slice(*VALID_CONFIG_KEYS)
|
28
|
+
end
|
29
|
+
|
30
|
+
def scoped_config
|
31
|
+
if scope == :default || parsed_config.fetch(scope, {}).empty?
|
32
|
+
parsed_config.fetch(:default, {})
|
33
|
+
else
|
34
|
+
parsed_config.fetch(:default, {}).merge(parsed_config[scope])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_file_type!
|
39
|
+
raise ParserError, 'Config file type must be YAML (.yaml or .yml)' unless yaml_file?
|
40
|
+
raise ParserError, "Config file path is invalid or file does not exist: #{config_file_path}" unless file_exists?
|
41
|
+
end
|
42
|
+
|
43
|
+
def yaml_file?
|
44
|
+
config_file_path.end_with?('.yaml') || config_file_path.end_with?('yml')
|
45
|
+
end
|
46
|
+
|
47
|
+
def file_exists?
|
48
|
+
File.file?(config_file_path)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module PRWithParams
|
2
|
+
class OptionsValidator
|
3
|
+
class ValidatorError < StandardError; end
|
4
|
+
|
5
|
+
VALIDATOR_CLASS_MAP = {
|
6
|
+
conventional_commits: 'PRWithParams::ConventionalCommitValidator'
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def validate!(options, validators: [])
|
11
|
+
validators.each do |validator|
|
12
|
+
validate_options(validator, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def validate_options(validator, options)
|
19
|
+
class_name = VALIDATOR_CLASS_MAP[validator.to_sym]
|
20
|
+
raise(ValidatorError, "Invalid or undefined validator: #{validator}") if class_name.nil?
|
21
|
+
|
22
|
+
Object.const_get(class_name).new(options).validate!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ConventionalCommitValidator
|
28
|
+
CONVENTIONAL_COMMIT_REGEX = /^((build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.*\))?(!)?(: (.*\s*)*))|(^Merge (.*\s*)*)|(^Initial commit$)/.freeze
|
29
|
+
|
30
|
+
def initialize(options)
|
31
|
+
@commit_message = options[:title]
|
32
|
+
end
|
33
|
+
|
34
|
+
def validate!
|
35
|
+
raise OptionsValidator::ValidatorError, "Conventional commit specifications not met for commit message: '#{@commit_message}'" unless valid_commit?
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def valid_commit?
|
41
|
+
CONVENTIONAL_COMMIT_REGEX.match?(@commit_message)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/pr-with-params.gemspec
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "lib/
|
3
|
+
require_relative "lib/pr_with_params/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "pr-with-params"
|
7
|
-
spec.version =
|
7
|
+
spec.version = PRWithParams::VERSION
|
8
8
|
spec.authors = ["2k-joker"]
|
9
9
|
spec.email = ["kum.vanjunior@gmail.com"]
|
10
10
|
|
11
11
|
spec.summary = "Pushes current local branch to remote with upstream at origin/[local-branch-name]. It also opens a new pull request browser window at a URL with customized query params, based on specified options, which pre-populates certain fields in the pull request. This is especially useful when supporting multiple PR templates within a code base."
|
12
12
|
spec.homepage = "https://github.com/2k-joker/pr-with-params"
|
13
13
|
spec.licenses = ["MIT"]
|
14
|
-
spec.required_ruby_version = Gem::Requirement.new("
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new("~> 3.1.0")
|
15
15
|
|
16
16
|
spec.metadata["homepage_uri"] = spec.homepage
|
17
17
|
|
@@ -24,9 +24,11 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ["lib"]
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
spec.add_dependency "launchy", "~> 2.5"
|
28
|
+
spec.add_dependency "rake", "~> 13.0"
|
29
|
+
spec.add_dependency "thor"
|
30
|
+
spec.add_dependency "activesupport"
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
+
spec.add_development_dependency "minitest", "~> 5.18.0"
|
33
|
+
spec.add_development_dependency "rubocop", "~> 0.80"
|
32
34
|
end
|
metadata
CHANGED
@@ -1,20 +1,104 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pr-with-params
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 2k-joker
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2023-06-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: launchy
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 5.18.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 5.18.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.80'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.80'
|
13
97
|
description:
|
14
98
|
email:
|
15
99
|
- kum.vanjunior@gmail.com
|
16
100
|
executables:
|
17
|
-
- pr-
|
101
|
+
- pr-wip
|
18
102
|
extensions: []
|
19
103
|
extra_rdoc_files: []
|
20
104
|
files:
|
@@ -22,6 +106,7 @@ files:
|
|
22
106
|
- ".github/PULL_REQUEST_TEMPLATE/new_feature_template.md"
|
23
107
|
- ".gitignore"
|
24
108
|
- ".rubocop.yml"
|
109
|
+
- CHANGELOG.md
|
25
110
|
- Gemfile
|
26
111
|
- Gemfile.lock
|
27
112
|
- LICENSE
|
@@ -29,11 +114,12 @@ files:
|
|
29
114
|
- Rakefile
|
30
115
|
- bin/console
|
31
116
|
- bin/setup
|
32
|
-
- exe/pr-
|
33
|
-
- lib/
|
34
|
-
- lib/
|
35
|
-
- lib/
|
36
|
-
- lib/
|
117
|
+
- exe/pr-wip
|
118
|
+
- lib/pr_with_params.rb
|
119
|
+
- lib/pr_with_params/cli.rb
|
120
|
+
- lib/pr_with_params/config_parser.rb
|
121
|
+
- lib/pr_with_params/options_validator.rb
|
122
|
+
- lib/pr_with_params/version.rb
|
37
123
|
- pr-with-params.gemspec
|
38
124
|
homepage: https://github.com/2k-joker/pr-with-params
|
39
125
|
licenses:
|
@@ -46,16 +132,16 @@ require_paths:
|
|
46
132
|
- lib
|
47
133
|
required_ruby_version: !ruby/object:Gem::Requirement
|
48
134
|
requirements:
|
49
|
-
- - "
|
135
|
+
- - "~>"
|
50
136
|
- !ruby/object:Gem::Version
|
51
|
-
version:
|
137
|
+
version: 3.1.0
|
52
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
139
|
requirements:
|
54
140
|
- - ">="
|
55
141
|
- !ruby/object:Gem::Version
|
56
142
|
version: '0'
|
57
143
|
requirements: []
|
58
|
-
rubygems_version: 3.
|
144
|
+
rubygems_version: 3.3.26
|
59
145
|
signing_key:
|
60
146
|
specification_version: 4
|
61
147
|
summary: Pushes current local branch to remote with upstream at origin/[local-branch-name].
|
data/exe/pr-with-params
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'bundler/setup' # support local testing/development
|
4
|
-
require_relative '../lib/pr/with/params'
|
5
|
-
require 'json'
|
6
|
-
require 'optparse'
|
7
|
-
require 'open3'
|
8
|
-
|
9
|
-
options = { expand: 1, validators: [] }
|
10
|
-
config_file_path = ''
|
11
|
-
config_scope = nil
|
12
|
-
|
13
|
-
# rubocop:disable Metrics/BlockLength
|
14
|
-
parser = OptionParser.new do |opt|
|
15
|
-
opt.banner = "Usage pr-with-params [options]"
|
16
|
-
|
17
|
-
opt.separator ''
|
18
|
-
|
19
|
-
opt.on('-h', '--help', 'Show this usage help menu') do |_h|
|
20
|
-
puts opt
|
21
|
-
exit
|
22
|
-
end
|
23
|
-
|
24
|
-
opt.separator ''
|
25
|
-
|
26
|
-
opt.on('--conf FILE_PATH', 'Path to yaml file where options are defined. NOTE that relative paths are not supported.') do |conf_file|
|
27
|
-
stdout, _stderr, _status = Open3.capture3("echo #{conf_file}")
|
28
|
-
config_file_path = stdout.chomp
|
29
|
-
end
|
30
|
-
|
31
|
-
opt.on('--scope CONFIG_SCOPE', 'Specify the scope name under which options are defined.') do |scope|
|
32
|
-
config_scope = scope
|
33
|
-
end
|
34
|
-
|
35
|
-
opt.on('--base-branch BRANCH', "Specify the base branch for your PR (e.g: 'develop'). Will use default branch otherwise.") do |pr_base_branch|
|
36
|
-
options[:base_branch] = pr_base_branch
|
37
|
-
end
|
38
|
-
|
39
|
-
opt.on('-t', '--template TEMPLATE', "Specify the filename of the target custom PR template (e.g: 'bug_squash_template.md'). Will use default template otherwise.") do |pr_template|
|
40
|
-
options[:template] = pr_template
|
41
|
-
end
|
42
|
-
|
43
|
-
opt.on('-d', '--description DESC', 'Specify a custom PR title. Will use the first branch commit message otherwise.') do |pr_description|
|
44
|
-
options[:title] = pr_description
|
45
|
-
end
|
46
|
-
|
47
|
-
opt.on('-l', '--labels LABELS', "Specify a list of labels (e.g: 'help+wanted,bug,urgent,work+in+progress').") do |pr_labels|
|
48
|
-
options[:labels] = pr_labels
|
49
|
-
end
|
50
|
-
|
51
|
-
opt.on('-a', '--assignees ASSIGNEES', "Specify a list of assignees (e.g: 'octocat,codedog').") do |pr_assignees|
|
52
|
-
options[:assignees] = pr_assignees
|
53
|
-
end
|
54
|
-
|
55
|
-
opt.on('--validate-conventional-commits', 'Validates that your PR title conforms to conventional commits specs.') do |_|
|
56
|
-
options[:validators] = options[:validators].to_a << :conventional_commits
|
57
|
-
end
|
58
|
-
end
|
59
|
-
# rubocop:enable Metrics/BlockLength
|
60
|
-
|
61
|
-
begin
|
62
|
-
parser.parse!
|
63
|
-
|
64
|
-
config_options = PR::With::Params.parse_config(config_file_path, config_scope)
|
65
|
-
options = config_options.merge(options)
|
66
|
-
|
67
|
-
branch_name = `git rev-parse --abbrev-ref HEAD`.chomp
|
68
|
-
base_branch = options.delete(:base_branch) || `git remote show origin | grep "HEAD branch" | sed 's/.*: //'`.chomp
|
69
|
-
|
70
|
-
default_title = `git show-branch --no-name $(git log #{base_branch}..#{branch_name} --pretty=format:"%h" | tail -1)`.chomp
|
71
|
-
options[:title] ||= default_title
|
72
|
-
|
73
|
-
PR::With::Params.validate_options(options)
|
74
|
-
|
75
|
-
remote_git_uri = `git config --get remote.origin.url`.sub('git@github.com:', '').sub('.git', '').chomp
|
76
|
-
uri_host = 'www.github.com'
|
77
|
-
uri_path = "/#{remote_git_uri}/compare/#{base_branch}...#{branch_name}"
|
78
|
-
|
79
|
-
puts "current branch: \e[36m#{branch_name}\e[0m"
|
80
|
-
puts "base branch: \e[36m#{base_branch}\e[0m"
|
81
|
-
puts "repo path: \e[36m#{remote_git_uri}\e[0m"
|
82
|
-
|
83
|
-
push_message = "\nPushing your local branch to origin/#{branch_name}..."
|
84
|
-
puts "\e[32m#{push_message}\e[0m"
|
85
|
-
`sleep 1`
|
86
|
-
system("git push -u origin #{branch_name}", exception: true)
|
87
|
-
|
88
|
-
open_url_message = "\nOpening pull request browser window..."
|
89
|
-
puts "\e[32m#{open_url_message}\e[0m"
|
90
|
-
`sleep 1`
|
91
|
-
PR::With::Params.open(host: uri_host, path: uri_path, query: options)
|
92
|
-
rescue StandardError => e
|
93
|
-
message = "\e[31mERROR\e[0m: An error occurred while building or opening your custom pull request URL"
|
94
|
-
reason = "reason: #{e.message}"
|
95
|
-
backtrace = "backtrace: #{e.backtrace&.last(10)&.join("\n")}"
|
96
|
-
error_message = [message, reason, backtrace, "\n\n"].join("\n")
|
97
|
-
|
98
|
-
warn error_message
|
99
|
-
exit 1
|
100
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
|
-
module PR
|
4
|
-
module With
|
5
|
-
module Params
|
6
|
-
class ConfigParser
|
7
|
-
# Attributes
|
8
|
-
attr_reader :config_file_path, :scope, :parsed_config, :filtered_config
|
9
|
-
|
10
|
-
# Constants
|
11
|
-
VALID_CONFIG_KEYS = %i[validators base_branch template title labels assignees].freeze
|
12
|
-
|
13
|
-
def initialize(config_file_path:, scope: nil)
|
14
|
-
@config_file_path = config_file_path
|
15
|
-
@scope = scope&.to_sym || :default
|
16
|
-
end
|
17
|
-
|
18
|
-
def parse!
|
19
|
-
validate_file_type!
|
20
|
-
parse_yaml_config
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def parse_yaml_config
|
26
|
-
@parsed_config = YAML.safe_load(IO.read(config_file_path)).transform_keys(&:to_sym)
|
27
|
-
@filtered_config = scoped_config.transform_keys(&:to_sym).slice(*VALID_CONFIG_KEYS)
|
28
|
-
end
|
29
|
-
|
30
|
-
def scoped_config
|
31
|
-
if scope == :default || parsed_config.fetch(scope, {}).empty?
|
32
|
-
parsed_config.fetch(:default, {})
|
33
|
-
else
|
34
|
-
parsed_config.fetch(:default, {}).merge(parsed_config[scope])
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def validate_file_type!
|
39
|
-
raise(TypeError, 'Config file type must be YAML (.yaml or .yml)') unless yaml_file?
|
40
|
-
raise(ArgumentError, "Config file path is invalid or file does not exist: #{config_file_path}") unless file_exists?
|
41
|
-
end
|
42
|
-
|
43
|
-
def yaml_file?
|
44
|
-
config_file_path.end_with?('.yaml') || config_file_path.end_with?('yml')
|
45
|
-
end
|
46
|
-
|
47
|
-
def file_exists?
|
48
|
-
File.file?(config_file_path)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module PR
|
2
|
-
module With
|
3
|
-
module Params
|
4
|
-
class OptionsValidator
|
5
|
-
VALIDATOR_CLASS_MAP = {
|
6
|
-
conventional_commits: 'PR::With::Params::ConventionalCommitValidator'
|
7
|
-
}.freeze
|
8
|
-
|
9
|
-
class << self
|
10
|
-
def validate!(options, validators: [])
|
11
|
-
validators.each do |validator|
|
12
|
-
validate_options(validator, options)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def validate_options(validator, options)
|
19
|
-
class_name = VALIDATOR_CLASS_MAP[validator.to_sym]
|
20
|
-
raise(ArgumentError, "Invalid or undefined validator: #{validator}") if class_name.nil?
|
21
|
-
|
22
|
-
Object.const_get(class_name).new(options).validate!
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class ConventionalCommitValidator
|
28
|
-
CONVENTIONAL_COMMIT_REGEX = /^((build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\(.*\))?(!)?(: (.*\s*)*))|(^Merge (.*\s*)*)|(^Initial commit$)/.freeze
|
29
|
-
|
30
|
-
def initialize(options)
|
31
|
-
@commit_message = options[:title]
|
32
|
-
end
|
33
|
-
|
34
|
-
def validate!
|
35
|
-
raise("Conventional commit specifications not met for commit message: '#{@commit_message}'") unless valid_commit?
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def valid_commit?
|
41
|
-
CONVENTIONAL_COMMIT_REGEX.match?(@commit_message)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
data/lib/pr/with/params.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'params/version'
|
4
|
-
require_relative 'params/config_parser'
|
5
|
-
require_relative 'params/options_validator'
|
6
|
-
require 'uri'
|
7
|
-
require 'json'
|
8
|
-
require 'launchy'
|
9
|
-
|
10
|
-
module PR
|
11
|
-
module With
|
12
|
-
module Params
|
13
|
-
class Error < StandardError; end
|
14
|
-
|
15
|
-
extend self
|
16
|
-
|
17
|
-
def open(host:, path:, query:)
|
18
|
-
uri_query = URI.encode_www_form(query)
|
19
|
-
url_string = URI::HTTPS.build(host: host, path: path, query: uri_query).to_s
|
20
|
-
Launchy.open(url_string)
|
21
|
-
end
|
22
|
-
|
23
|
-
def parse_config(file_path, scope)
|
24
|
-
ConfigParser.new(config_file_path: file_path, scope: scope).parse!
|
25
|
-
|
26
|
-
file_path.empty? ? {} : ConfigParser.new(config_file_path: file_path, scope: scope).parse!
|
27
|
-
rescue StandardError => e
|
28
|
-
message = "\e[35mWARNING\e[0m: Error parsing config file. Using defaults"
|
29
|
-
reason = "reason: #{e.message}"
|
30
|
-
backtrace = "backtrace: #{e.backtrace&.last(10)&.join("\n")}"
|
31
|
-
error_message = [message, reason, backtrace, "\n\n"].join("\n")
|
32
|
-
|
33
|
-
warn error_message
|
34
|
-
|
35
|
-
{}
|
36
|
-
end
|
37
|
-
|
38
|
-
def validate_options(options)
|
39
|
-
validators = options.delete(:validators)
|
40
|
-
OptionsValidator.validate!(options, validators: validators)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|