faf 0.1.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 +7 -0
- data/CHANGELOG.md +3 -0
- data/CONTRIBUTING.md +125 -0
- data/LICENSE.md +22 -0
- data/README.md +67 -0
- data/bin/faf +53 -0
- data/lib/faf.rb +13 -0
- data/lib/faf/auth.rb +108 -0
- data/lib/faf/connection.rb +42 -0
- data/lib/faf/forks.rb +61 -0
- data/lib/faf/repo.rb +56 -0
- data/lib/faf/security.rb +40 -0
- data/lib/faf/shell.rb +11 -0
- data/lib/faf/version.rb +3 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9891acf05f5536961bacc63ba7eebf9d3e776c53e4ec4acbe12f282292514de4
|
4
|
+
data.tar.gz: ca5ae0e56664c71ce79266ef9a157425ae925eaaa43cd3aa0990fd6fc501a99f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ced0850a182bb36a39d947cd482cf51df80bb698fcb001284170b9d0e685677c154de19b64acb82b86e1eacb66a5787217f869b79a96f1c6d468b3f98be0ca44
|
7
|
+
data.tar.gz: d3ded6c244bd2cf1f7fab2d0d27f477f2eeaefd0a1db89210177885590459079e9ca27f3c5ac2d4549838a4ea25102ee0d4ef174fa62c090c956337ef6f88851
|
data/CHANGELOG.md
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# Contributing to Faf
|
2
|
+
|
3
|
+
This project is work of [many contributors](https://github.com/dblock/faf/graphs/contributors).
|
4
|
+
|
5
|
+
You're encouraged to submit [pull requests](https://github.com/dblock/faf/pulls), [propose features and discuss issues](https://github.com/dblock/faf/issues).
|
6
|
+
|
7
|
+
In the examples below, substitute your GitHub username for `contributor` in URLs.
|
8
|
+
|
9
|
+
### Fork the Project
|
10
|
+
|
11
|
+
Fork the [project on GitHub](https://github.com/dblock/faf) and check out your copy.
|
12
|
+
|
13
|
+
```
|
14
|
+
git clone https://github.com/contributor/faf.git
|
15
|
+
cd faf
|
16
|
+
git remote add upstream https://github.com/dblock/faf.git
|
17
|
+
```
|
18
|
+
|
19
|
+
### Bundle Install and Test
|
20
|
+
|
21
|
+
Ensure that you can build the project and run tests.
|
22
|
+
|
23
|
+
```
|
24
|
+
bundle install
|
25
|
+
bundle exec rake
|
26
|
+
```
|
27
|
+
|
28
|
+
## Contribute Code
|
29
|
+
|
30
|
+
### Create a Topic Branch
|
31
|
+
|
32
|
+
Make sure your fork is up-to-date and create a topic branch for your feature or bug fix.
|
33
|
+
|
34
|
+
```
|
35
|
+
git checkout master
|
36
|
+
git pull upstream master
|
37
|
+
git checkout -b my-feature-branch
|
38
|
+
```
|
39
|
+
|
40
|
+
### Write Tests
|
41
|
+
|
42
|
+
Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add tests to [spec](spec).
|
43
|
+
|
44
|
+
We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
|
45
|
+
|
46
|
+
### Write Code
|
47
|
+
|
48
|
+
Implement your feature or bug fix.
|
49
|
+
|
50
|
+
Ruby style is enforced with [Rubocop](https://github.com/bbatsov/rubocop). Run `bundle exec rubocop` and fix any style issues highlighted, auto-correct issues when possible with `bundle exec rubocop -a`. To silence generally ignored issues, including line lengths or code complexity metrics, run `bundle exec rubocop --auto-gen-config`.
|
51
|
+
|
52
|
+
Make sure that `bundle exec rake` completes without errors.
|
53
|
+
|
54
|
+
### Write Documentation
|
55
|
+
|
56
|
+
Document any external behavior in the [README](README.md).
|
57
|
+
|
58
|
+
### Update Changelog
|
59
|
+
|
60
|
+
Add a line to [CHANGELOG](CHANGELOG.md) under *Next Release*. Don't remove *Your contribution here*.
|
61
|
+
|
62
|
+
Make it look like every other line, including a link to the issue being fixed, your name and link to your Github account.
|
63
|
+
|
64
|
+
### Commit Changes
|
65
|
+
|
66
|
+
Make sure git knows your name and email address:
|
67
|
+
|
68
|
+
```
|
69
|
+
git config --global user.name "Your Name"
|
70
|
+
git config --global user.email "contributor@example.com"
|
71
|
+
```
|
72
|
+
|
73
|
+
Writing good commit logs is important. A commit log should describe what changed and why.
|
74
|
+
|
75
|
+
```
|
76
|
+
git add ...
|
77
|
+
git commit
|
78
|
+
```
|
79
|
+
|
80
|
+
### Push
|
81
|
+
|
82
|
+
```
|
83
|
+
git push origin my-feature-branch
|
84
|
+
```
|
85
|
+
|
86
|
+
### Make a Pull Request
|
87
|
+
|
88
|
+
Go to https://github.com/contributor/faf and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days.
|
89
|
+
|
90
|
+
### Update CHANGELOG Again
|
91
|
+
|
92
|
+
Update the [CHANGELOG](CHANGELOG.md) with the pull request number. A typical entry looks as follows.
|
93
|
+
|
94
|
+
```
|
95
|
+
* [#123](https://github.com/dblock/faf/pull/123): Reticulated splines - [@contributor](https://github.com/contributor).
|
96
|
+
```
|
97
|
+
|
98
|
+
Amend your previous commit and force push the changes.
|
99
|
+
|
100
|
+
```
|
101
|
+
git commit --amend
|
102
|
+
git push origin my-feature-branch -f
|
103
|
+
```
|
104
|
+
|
105
|
+
### Rebase
|
106
|
+
|
107
|
+
If you've been working on a change for a while, rebase with upstream/master.
|
108
|
+
|
109
|
+
```
|
110
|
+
git fetch upstream
|
111
|
+
git rebase upstream/master
|
112
|
+
git push origin my-feature-branch -f
|
113
|
+
```
|
114
|
+
|
115
|
+
### Check on Your Pull Request
|
116
|
+
|
117
|
+
Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
|
118
|
+
|
119
|
+
### Be Patient
|
120
|
+
|
121
|
+
It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there!
|
122
|
+
|
123
|
+
## Thank You
|
124
|
+
|
125
|
+
Please do know that we really appreciate and value your time and work. We love you, really.
|
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2019 Daniel Doubrovkine.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
Faf
|
2
|
+
===
|
3
|
+
|
4
|
+
[](https://badge.fury.io/rb/faf)
|
5
|
+
[](https://travis-ci.org/dblock/faf)
|
6
|
+
|
7
|
+
Find Active (Github) Forks.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
```
|
12
|
+
gem install faf
|
13
|
+
```
|
14
|
+
|
15
|
+
#### Show Github Forks
|
16
|
+
|
17
|
+
The `forks` command shows github forks.
|
18
|
+
|
19
|
+
```bash
|
20
|
+
$ faf forks dblock/fue
|
21
|
+
|
22
|
+
https://github.com/zacklayton/fue (21 days and 7 hours ago)
|
23
|
+
https://github.com/lhmzhou/fue (25 days and 4 hours ago)
|
24
|
+
```
|
25
|
+
|
26
|
+
Limit the number of forks with `--max`.
|
27
|
+
|
28
|
+
```bash
|
29
|
+
$ faf forks --max=3 dblock/slack-gamebot
|
30
|
+
|
31
|
+
https://github.com/tarikstafford/slack-gamebot (18 days ago)
|
32
|
+
https://github.com/dersam/slack-gamebot (30 days and 4 hours ago)
|
33
|
+
https://github.com/ccadoret/slack-gamebot (50 days and 3 hours ago)
|
34
|
+
```
|
35
|
+
|
36
|
+
#### Get Help
|
37
|
+
|
38
|
+
```
|
39
|
+
faf help
|
40
|
+
```
|
41
|
+
|
42
|
+
Displays additional options.
|
43
|
+
|
44
|
+
#### Access Tokens
|
45
|
+
|
46
|
+
Faf will prompt you for Github credentials and 2FA, if enabled.
|
47
|
+
|
48
|
+
```
|
49
|
+
$ faf forks dblock/fue
|
50
|
+
Enter dblock's GitHub password (never stored): ******************
|
51
|
+
Enter GitHub 2FA code: ******
|
52
|
+
Token saved to keychain.
|
53
|
+
```
|
54
|
+
|
55
|
+
The access token will be generated with `public_repo` scope and stored in the keychain. It can be later deleted from [here](https://github.com/settings/tokens). You can also skip the prompts and use a previously obtained token with `-t` or by setting the `GITHUB_ACCESS_TOKEN` environment variable.
|
56
|
+
|
57
|
+
See [Creating a Personal Access Token for the Command Line](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) for more information about personal tokens.
|
58
|
+
|
59
|
+
## Contributing
|
60
|
+
|
61
|
+
There are [a few feature requests and known issues](https://github.com/dblock/faf/issues). Please contribute! See [CONTRIBUTING](CONTRIBUTING.md).
|
62
|
+
|
63
|
+
## Copyright and License
|
64
|
+
|
65
|
+
Copyright (c) 2019, Daniel Doubrovkine.
|
66
|
+
|
67
|
+
This project is licensed under the [MIT License](LICENSE.md).
|
data/bin/faf
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'gli'
|
3
|
+
require 'faf'
|
4
|
+
|
5
|
+
class App
|
6
|
+
extend GLI::App
|
7
|
+
|
8
|
+
program_desc 'Find active GitHub forks.'
|
9
|
+
version Faf::VERSION
|
10
|
+
|
11
|
+
switch %i[v verbose], desc: 'Produce verbose output.', default_value: false
|
12
|
+
flag %i[t token], desc: 'GitHub access token.', default_value: ENV['GITHUB_ACCESS_TOKEN']
|
13
|
+
flag %i[u username], desc: 'GitHub username.', default_value: Faf::Auth.instance.username
|
14
|
+
|
15
|
+
arguments :strict
|
16
|
+
subcommand_option_handling :normal
|
17
|
+
|
18
|
+
pre do |global_options, _command, options, _args|
|
19
|
+
options = global_options.dup
|
20
|
+
token = options.delete(:token) || Faf::Auth.instance.token
|
21
|
+
$verbose = global_options[:verbose]
|
22
|
+
puts "Using token '#{token}'" if $verbose
|
23
|
+
$connection = Faf::Connection.initialize!(token, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
default_command :help
|
27
|
+
|
28
|
+
desc 'Show active GitHub forks.'
|
29
|
+
arg 'repo'
|
30
|
+
command :forks do |c|
|
31
|
+
c.flag %i[m max], desc: 'Maximum number of forks to show.'
|
32
|
+
c.action do |_global_options, options, args|
|
33
|
+
repo = args.first
|
34
|
+
puts "Exploring forks of '#{repo}' ..." if $verbose
|
35
|
+
github_repo = Faf::Repo.new(repo, options)
|
36
|
+
puts "Found #{github_repo.fork_count} forks ..." if $verbose
|
37
|
+
github_forks = github_repo.forks
|
38
|
+
github_forks = github_forks.take(options[:max].to_i) if options[:max]
|
39
|
+
github_forks.each do |f|
|
40
|
+
puts f
|
41
|
+
end
|
42
|
+
exit_now! nil, 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
on_error do |e|
|
47
|
+
warn "Error: #{e.message}"
|
48
|
+
warn ' ' + e.backtrace.join("\n ") if $verbose
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
exit App.run(ARGV)
|
data/lib/faf.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'graphlient'
|
2
|
+
require 'github_api'
|
3
|
+
require 'open3'
|
4
|
+
require 'English'
|
5
|
+
require 'time_ago_in_words'
|
6
|
+
|
7
|
+
require 'faf/version'
|
8
|
+
require 'faf/connection'
|
9
|
+
require 'faf/repo'
|
10
|
+
require 'faf/forks'
|
11
|
+
require 'faf/shell'
|
12
|
+
require 'faf/security'
|
13
|
+
require 'faf/auth'
|
data/lib/faf/auth.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
module Faf
|
2
|
+
class Auth
|
3
|
+
def self.instance
|
4
|
+
@instance ||= new
|
5
|
+
end
|
6
|
+
|
7
|
+
def token
|
8
|
+
stored_options = { username: username, server: 'github.com', label: 'faf' }
|
9
|
+
stored_token = Faf::Security.get(stored_options)
|
10
|
+
unless stored_token
|
11
|
+
stored_token = github_token
|
12
|
+
Faf::Security.store!(stored_options.merge(password: stored_token))
|
13
|
+
puts 'Token saved to keychain.'
|
14
|
+
end
|
15
|
+
stored_token
|
16
|
+
end
|
17
|
+
|
18
|
+
def username
|
19
|
+
@username ||= begin
|
20
|
+
username = get_git_username
|
21
|
+
username.chomp! if username
|
22
|
+
username = get_username if username.nil? || username.empty?
|
23
|
+
username
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def get_git_username
|
30
|
+
Faf::Shell.system!('git config github.user')
|
31
|
+
rescue RuntimeError
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def github_token(code = nil)
|
36
|
+
github(code).auth.create(scopes: ['public_repo'], note: note).token
|
37
|
+
rescue Github::Error::Unauthorized => e
|
38
|
+
case e.response_headers['X-GitHub-OTP']
|
39
|
+
when /required/ then
|
40
|
+
github_token(get_code)
|
41
|
+
else
|
42
|
+
raise e
|
43
|
+
end
|
44
|
+
rescue Github::Error::UnprocessableEntity => e
|
45
|
+
raise e, 'A faf token already exists! Please revoke all previously-generated faf personal access tokens at https://github.com/settings/tokens.'
|
46
|
+
end
|
47
|
+
|
48
|
+
def password
|
49
|
+
@password ||= get_password
|
50
|
+
end
|
51
|
+
|
52
|
+
def note
|
53
|
+
"Fui (https://github.com/dblock/faf) on #{Socket.gethostname}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def github(code = nil)
|
57
|
+
Github.new do |config|
|
58
|
+
config.basic_auth = [username, password].join(':')
|
59
|
+
if code
|
60
|
+
config.connection_options = {
|
61
|
+
headers: {
|
62
|
+
'X-GitHub-OTP' => code
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_username
|
70
|
+
print 'Enter GitHub username: '
|
71
|
+
username = $stdin.gets
|
72
|
+
username.chomp! if username
|
73
|
+
username
|
74
|
+
rescue Interrupt => e
|
75
|
+
raise e, 'ctrl + c'
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_password
|
79
|
+
print "Enter #{username}'s GitHub password (never stored): "
|
80
|
+
get_secure
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_code
|
84
|
+
print 'Enter GitHub 2FA code: '
|
85
|
+
get_secure
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_secure
|
89
|
+
current_tty = `stty -g`
|
90
|
+
system 'stty raw -echo -icanon isig' if $CHILD_STATUS.success?
|
91
|
+
input = ''
|
92
|
+
while (char = $stdin.getbyte) && !((char == 13) || (char == 10))
|
93
|
+
if (char == 127) || (char == 8)
|
94
|
+
input[-1, 1] = '' unless input.empty?
|
95
|
+
else
|
96
|
+
$stdout.write '*'
|
97
|
+
input << char.chr
|
98
|
+
end
|
99
|
+
end
|
100
|
+
print "\r\n"
|
101
|
+
input
|
102
|
+
rescue Interrupt => e
|
103
|
+
raise e, 'ctrl + c'
|
104
|
+
ensure
|
105
|
+
system "stty #{current_tty}" unless current_tty.empty?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Faf
|
2
|
+
class Connection
|
3
|
+
class << self
|
4
|
+
attr_reader :instance
|
5
|
+
|
6
|
+
def initialize!(token, options = {})
|
7
|
+
@instance ||= new(token, options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def reset!
|
11
|
+
@instance = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def query(query, options = {})
|
15
|
+
raise 'Not Initialized' unless instance
|
16
|
+
instance.query(query, options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :token
|
21
|
+
|
22
|
+
def initialize(token, _options = {})
|
23
|
+
@token = token
|
24
|
+
end
|
25
|
+
|
26
|
+
def query(query, options)
|
27
|
+
graphql_client.query(query, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def graphql_client
|
33
|
+
@graphql_client ||= Graphlient::Client.new(
|
34
|
+
'https://api.github.com/graphql',
|
35
|
+
headers: {
|
36
|
+
'Authorization' => "Bearer #{token}",
|
37
|
+
'Content-Type' => 'application/json'
|
38
|
+
}
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/faf/forks.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Faf
|
2
|
+
class Forks
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :repo
|
6
|
+
|
7
|
+
def initialize(repo, _options = {})
|
8
|
+
@repo = repo
|
9
|
+
end
|
10
|
+
|
11
|
+
def each
|
12
|
+
forks.each do |f|
|
13
|
+
yield(f)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def forks
|
20
|
+
@forks ||= get_forks
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_forks(_options = {})
|
24
|
+
query = <<-GRAPHQL
|
25
|
+
query($owner: String!, $name: String!, $cursor: String) {
|
26
|
+
repository(owner: $owner, name: $name) {
|
27
|
+
forks(first: 100, after: $cursor, orderBy: { field: PUSHED_AT, direction: DESC }) {
|
28
|
+
edges {
|
29
|
+
cursor
|
30
|
+
node {
|
31
|
+
nameWithOwner
|
32
|
+
pushedAt
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
GRAPHQL
|
39
|
+
|
40
|
+
query_options = {
|
41
|
+
owner: repo.owner,
|
42
|
+
name: repo.name
|
43
|
+
}
|
44
|
+
|
45
|
+
forks = []
|
46
|
+
|
47
|
+
loop do
|
48
|
+
response = Faf::Connection.query(query, query_options)
|
49
|
+
edges = response.data.repository.forks.edges if response
|
50
|
+
break unless edges && edges.any?
|
51
|
+
edges.each do |edge|
|
52
|
+
query_options[:cursor] = edge.cursor
|
53
|
+
node = edge.node
|
54
|
+
forks << Faf::Repo.new(node.name_with_owner, pushed_at: Time.parse(node.pushed_at))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
forks
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/faf/repo.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Faf
|
2
|
+
class Repo
|
3
|
+
attr_reader :owner
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :pushed_at
|
6
|
+
|
7
|
+
def initialize(url, options = {})
|
8
|
+
@owner, @name = url.split('/', 2)
|
9
|
+
@pushed_at = options[:pushed_at]
|
10
|
+
end
|
11
|
+
|
12
|
+
def forks
|
13
|
+
@forks ||= Faf::Forks.new(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def fork_count
|
17
|
+
repository.fork_count
|
18
|
+
end
|
19
|
+
|
20
|
+
def repository
|
21
|
+
data.repository
|
22
|
+
end
|
23
|
+
|
24
|
+
def url
|
25
|
+
"https://github.com/#{owner}/#{name}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"#{url} (#{pushed_at.ago_in_words})"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def data
|
35
|
+
@data ||= get_data.data
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_data
|
39
|
+
query = <<-GRAPHQL
|
40
|
+
query($owner: String!, $name: String!) {
|
41
|
+
repository(owner: $owner, name: $name) {
|
42
|
+
name
|
43
|
+
forkCount
|
44
|
+
}
|
45
|
+
}
|
46
|
+
GRAPHQL
|
47
|
+
|
48
|
+
query_options = {
|
49
|
+
owner: owner,
|
50
|
+
name: name
|
51
|
+
}
|
52
|
+
|
53
|
+
Faf::Connection.query(query, query_options)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/faf/security.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Faf
|
2
|
+
module Security
|
3
|
+
class << self
|
4
|
+
def store!(options)
|
5
|
+
Faf::Shell.system!(security('add', options))
|
6
|
+
end
|
7
|
+
|
8
|
+
def get(options)
|
9
|
+
Faf::Shell.system!(security('find', options))
|
10
|
+
rescue RuntimeError
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def security(command = nil, options = nil)
|
17
|
+
run = [security_path]
|
18
|
+
run << "#{command}-internet-password"
|
19
|
+
run << "-a #{options[:username]}"
|
20
|
+
run << "-s #{options[:server]}"
|
21
|
+
if command == 'add'
|
22
|
+
run << "-l #{options[:label]}"
|
23
|
+
run << '-U'
|
24
|
+
run << "-w #{options[:password]}" if options.key?(:password)
|
25
|
+
else
|
26
|
+
run << '-w'
|
27
|
+
end
|
28
|
+
run.join ' '
|
29
|
+
end
|
30
|
+
|
31
|
+
def security_path
|
32
|
+
@security_path ||= begin
|
33
|
+
`which security`.chomp
|
34
|
+
rescue StandardError
|
35
|
+
'security'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/faf/shell.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module Faf
|
2
|
+
module Shell
|
3
|
+
class << self
|
4
|
+
def system!(*cmd)
|
5
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
6
|
+
raise ["exit code #{status}", stderr].compact.join("\n") unless status.success?
|
7
|
+
stdout.slice!(0..-(1 + $INPUT_RECORD_SEPARATOR.size))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/faf/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: faf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Doubrovkine
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: github_api
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.18.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.18.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: gli
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.17'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.17'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: graphlient
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: time_ago_in_words
|
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
|
+
description:
|
70
|
+
email: dblock@dblock.org
|
71
|
+
executables:
|
72
|
+
- faf
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- CHANGELOG.md
|
77
|
+
- CONTRIBUTING.md
|
78
|
+
- LICENSE.md
|
79
|
+
- README.md
|
80
|
+
- bin/faf
|
81
|
+
- lib/faf.rb
|
82
|
+
- lib/faf/auth.rb
|
83
|
+
- lib/faf/connection.rb
|
84
|
+
- lib/faf/forks.rb
|
85
|
+
- lib/faf/repo.rb
|
86
|
+
- lib/faf/security.rb
|
87
|
+
- lib/faf/shell.rb
|
88
|
+
- lib/faf/version.rb
|
89
|
+
homepage: http://github.com/dblock/faf
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 1.3.6
|
107
|
+
requirements: []
|
108
|
+
rubygems_version: 3.0.1
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Find active GitHub forks.
|
112
|
+
test_files: []
|