travis 1.6.4.travis.410.4 → 1.6.4.travis.411.4
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 +8 -8
- data/assets/travis.sh +3 -3
- data/lib/travis/cli/api_command.rb +1 -0
- data/lib/travis/cli/login.rb +53 -52
- data/lib/travis/tools/github.rb +260 -0
- data/spec/cli/login_spec.rb +1 -1
- data/spec/support/fake_github.rb +4 -0
- data/travis.gemspec +1 -1
- metadata +2 -2
- data/lib/travis/tools/token_finder.rb +0 -52
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
OTVmNWY5ZWVjOGE3MjAxYjAxZDFmZWJlZTM4MjVlMTQxNWJkZGIyYQ==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
ZjFlYjIwMzEzYTNjOGVhZGQ5ZTdiMGU4Nzk4ZGZiNGM0ZGUwMjBkNg==
|
|
7
7
|
SHA512:
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
MTkwZmZkZTA0ZjIwNGExZDEzM2ZhZWY3MmI1YmI1MTM4ZjMzN2U5YjBkMjZh
|
|
10
|
+
N2Y0ZDdiOTVkNWYxNzQ0NGE1NGIyZjZjNGVhYTM4ZGEwYmIzNTkzZDhhYmFj
|
|
11
|
+
MGY0YjQwMzVkNDJjMTQyOTNhOWUwZjg5ODdjZGMzZWRmYzJjOWM=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
N2FmM2JlZmYzN2MxNTA3ZGNjMGVjZmEzYzZlZjhjNTAwNGRhNzM0NWJkNDVh
|
|
14
|
+
ZDY2NDhlOTJmNzBiZDNhODI5ZmUyNGMzOTI4ODJhNTJmM2ZiZjFjY2JkMzAy
|
|
15
|
+
OTk2MWY4MDNmMjAxNDVlMzc4MTQzODk0MWY4MDAwMTE1YTBmNmE=
|
data/assets/travis.sh
CHANGED
|
@@ -36,7 +36,7 @@ if type compdef 1>/dev/null 2>/dev/null; then
|
|
|
36
36
|
help) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" '*:file:_files' && return 0;;
|
|
37
37
|
history) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" "-e[Travis API server to talk to]" "--api-endpoint[Travis API server to talk to]" "-I[do not verify SSL certificate of API endpoint]" "--insecure[do not verify SSL certificate of API endpoint]" "--no-insecure[do not verify SSL certificate of API endpoint]" "--pro[short-cut for --api-endpoint 'https://api.travis-ci.com/']" "--org[short-cut for --api-endpoint 'https://api.travis-ci.org/']" "--staging[talks to staging system]" "-t[access token to use]" "--token[access token to use]" "--debug[show API requests]" "-X[use enterprise setup (optionally takes name for multiple setups)]" "--enterprise[use enterprise setup (optionally takes name for multiple setups)]" "--adapter[Faraday adapter to use for HTTP requests]" "-r[repository to use (will try to detect from current git clone)]" "--repo[repository to use (will try to detect from current git clone)]" "-a[Only show history after a given build number]" "--after[Only show history after a given build number]" "-p[Only show history for the given Pull Request]" "--pull-request[Only show history for the given Pull Request]" "-b[Only show history for the given branch]" "--branch[Only show history for the given branch]" "-l[Maximum number of history items]" "--limit[Maximum number of history items]" "-d[Include date in output]" "--date[Include date in output]" "--all[Display all history items]" "--no-all[Display all history items]" '*:file:_files' && return 0;;
|
|
38
38
|
init) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" "-e[Travis API server to talk to]" "--api-endpoint[Travis API server to talk to]" "-I[do not verify SSL certificate of API endpoint]" "--insecure[do not verify SSL certificate of API endpoint]" "--no-insecure[do not verify SSL certificate of API endpoint]" "--pro[short-cut for --api-endpoint 'https://api.travis-ci.com/']" "--org[short-cut for --api-endpoint 'https://api.travis-ci.org/']" "--staging[talks to staging system]" "-t[access token to use]" "--token[access token to use]" "--debug[show API requests]" "-X[use enterprise setup (optionally takes name for multiple setups)]" "--enterprise[use enterprise setup (optionally takes name for multiple setups)]" "--adapter[Faraday adapter to use for HTTP requests]" "-r[repository to use (will try to detect from current git clone)]" "--repo[repository to use (will try to detect from current git clone)]" "-s[don't trigger a sync if the repo is unknown]" "--skip-sync[don't trigger a sync if the repo is unknown]" "-f[override .travis.yml if it already exists]" "--force[override .travis.yml if it already exists]" "-k[do not enable project, only add .travis.yml]" "--skip-enable[do not enable project, only add .travis.yml]" "-p[print generated config instead of writing to file]" "--print-conf[print generated config instead of writing to file]" "--script[sets script option in .travis.yml (can be used more than once)]" "--before-script[sets before_script option in .travis.yml (can be used more than once)]" "--after-script[sets after_script option in .travis.yml (can be used more than once)]" "--after-success[sets after_success option in .travis.yml (can be used more than once)]" "--install[sets install option in .travis.yml (can be used more than once)]" "--before-install[sets before_install option in .travis.yml (can be used more than once)]" "--compiler[sets compiler option in .travis.yml (can be used more than once)]" "--otp-release[sets otp_release option in .travis.yml (can be used more than once)]" "--go[sets go option in .travis.yml (can be used more than once)]" "--jdk[sets jdk option in .travis.yml (can be used more than once)]" "--node-js[sets node_js option in .travis.yml (can be used more than once)]" "--perl[sets perl option in .travis.yml (can be used more than once)]" "--php[sets php option in .travis.yml (can be used more than once)]" "--python[sets python option in .travis.yml (can be used more than once)]" "--rvm[sets rvm option in .travis.yml (can be used more than once)]" "--scala[sets scala option in .travis.yml (can be used more than once)]" "--env[sets env option in .travis.yml (can be used more than once)]" "--gemfile[sets gemfile option in .travis.yml (can be used more than once)]" '*:file:_files' && return 0;;
|
|
39
|
-
login) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" "-e[Travis API server to talk to]" "--api-endpoint[Travis API server to talk to]" "-I[do not verify SSL certificate of API endpoint]" "--insecure[do not verify SSL certificate of API endpoint]" "--no-insecure[do not verify SSL certificate of API endpoint]" "--pro[short-cut for --api-endpoint 'https://api.travis-ci.com/']" "--org[short-cut for --api-endpoint 'https://api.travis-ci.org/']" "--staging[talks to staging system]" "-t[access token to use]" "--token[access token to use]" "--debug[show API requests]" "-X[use enterprise setup (optionally takes name for multiple setups)]" "--enterprise[use enterprise setup (optionally takes name for multiple setups)]" "--adapter[Faraday adapter to use for HTTP requests]" "--github-token[identify by GitHub token]" "--auto[try to figure out who you are automatically (might send another apps token to Travis, token will not be stored)]" '*:file:_files' && return 0;;
|
|
39
|
+
login) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" "-e[Travis API server to talk to]" "--api-endpoint[Travis API server to talk to]" "-I[do not verify SSL certificate of API endpoint]" "--insecure[do not verify SSL certificate of API endpoint]" "--no-insecure[do not verify SSL certificate of API endpoint]" "--pro[short-cut for --api-endpoint 'https://api.travis-ci.com/']" "--org[short-cut for --api-endpoint 'https://api.travis-ci.org/']" "--staging[talks to staging system]" "-t[access token to use]" "--token[access token to use]" "--debug[show API requests]" "-X[use enterprise setup (optionally takes name for multiple setups)]" "--enterprise[use enterprise setup (optionally takes name for multiple setups)]" "--adapter[Faraday adapter to use for HTTP requests]" "-g[identify by GitHub token]" "--github-token[identify by GitHub token]" "-T[try to figure out who you are automatically (might send another apps token to Travis, token will not be stored)]" "--auto-token[try to figure out who you are automatically (might send another apps token to Travis, token will not be stored)]" "-p[try to load password from OSX keychain (will not be stored)]" "--auto-password[try to load password from OSX keychain (will not be stored)]" "-a[shorthand for --auto-token --auto-password]" "--auto[shorthand for --auto-token --auto-password]" "-u[user to log in as]" "--user[user to log in as]" "-M[do not use interactive login]" "--no-manual[do not use interactive login]" "--list-github-token[instead of actually logging in, list found GitHub tokens]" "--skip-token-check[don't verify the token with github]" '*:file:_files' && return 0;;
|
|
40
40
|
logout) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" "-e[Travis API server to talk to]" "--api-endpoint[Travis API server to talk to]" "-I[do not verify SSL certificate of API endpoint]" "--insecure[do not verify SSL certificate of API endpoint]" "--no-insecure[do not verify SSL certificate of API endpoint]" "--pro[short-cut for --api-endpoint 'https://api.travis-ci.com/']" "--org[short-cut for --api-endpoint 'https://api.travis-ci.org/']" "--staging[talks to staging system]" "-t[access token to use]" "--token[access token to use]" "--debug[show API requests]" "-X[use enterprise setup (optionally takes name for multiple setups)]" "--enterprise[use enterprise setup (optionally takes name for multiple setups)]" "--adapter[Faraday adapter to use for HTTP requests]" '*:file:_files' && return 0;;
|
|
41
41
|
logs) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" "-e[Travis API server to talk to]" "--api-endpoint[Travis API server to talk to]" "-I[do not verify SSL certificate of API endpoint]" "--insecure[do not verify SSL certificate of API endpoint]" "--no-insecure[do not verify SSL certificate of API endpoint]" "--pro[short-cut for --api-endpoint 'https://api.travis-ci.com/']" "--org[short-cut for --api-endpoint 'https://api.travis-ci.org/']" "--staging[talks to staging system]" "-t[access token to use]" "--token[access token to use]" "--debug[show API requests]" "-X[use enterprise setup (optionally takes name for multiple setups)]" "--enterprise[use enterprise setup (optionally takes name for multiple setups)]" "--adapter[Faraday adapter to use for HTTP requests]" "-r[repository to use (will try to detect from current git clone)]" "--repo[repository to use (will try to detect from current git clone)]" '*:file:_files' && return 0;;
|
|
42
42
|
monitor) _arguments -s -S "-h[Display help]" "--help[Display help]" "-i[be interactive and colorful]" "--interactive[be interactive and colorful]" "--no-interactive[be interactive and colorful]" "-E[don't rescue exceptions]" "--explode[don't rescue exceptions]" "--no-explode[don't rescue exceptions]" "--skip-version-check[don't check if travis client is up to date]" "--skip-completion-check[don't check if auto-completion is set up]" "-e[Travis API server to talk to]" "--api-endpoint[Travis API server to talk to]" "-I[do not verify SSL certificate of API endpoint]" "--insecure[do not verify SSL certificate of API endpoint]" "--no-insecure[do not verify SSL certificate of API endpoint]" "--pro[short-cut for --api-endpoint 'https://api.travis-ci.com/']" "--org[short-cut for --api-endpoint 'https://api.travis-ci.org/']" "--staging[talks to staging system]" "-t[access token to use]" "--token[access token to use]" "--debug[show API requests]" "-X[use enterprise setup (optionally takes name for multiple setups)]" "--enterprise[use enterprise setup (optionally takes name for multiple setups)]" "--adapter[Faraday adapter to use for HTTP requests]" "-m[Only monitor my own repositories]" "--my-repos[Only monitor my own repositories]" "-r[monitor given repository (can be used more than once)]" "--repo[monitor given repository (can be used more than once)]" "-n[send out desktop notifications (optional type: osx, growl, libnotify)]" "--notify[send out desktop notifications (optional type: osx, growl, libnotify)]" "--no-notify[send out desktop notifications (optional type: osx, growl, libnotify)]" "-b[only monitor builds, not jobs]" "--builds[only monitor builds, not jobs]" "-p[monitor push events]" "--push[monitor push events]" "-P[monitor pull request events]" "--pull[monitor pull request events]" '*:file:_files' && return 0;;
|
|
@@ -76,7 +76,7 @@ elif type compctl 1>/dev/null 2>/dev/null; then
|
|
|
76
76
|
help) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check");;
|
|
77
77
|
history) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check" "--api-endpoint" "-e" "--insecure" "--no-insecure" "-I" "--pro" "--org" "--staging" "--token" "-t" "--debug" "--enterprise" "-X" "--adapter" "--repo" "-r" "--after" "-a" "--pull-request" "-p" "--branch" "-b" "--limit" "-l" "--date" "-d" "--all" "--no-all");;
|
|
78
78
|
init) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check" "--api-endpoint" "-e" "--insecure" "--no-insecure" "-I" "--pro" "--org" "--staging" "--token" "-t" "--debug" "--enterprise" "-X" "--adapter" "--repo" "-r" "--skip-sync" "-s" "--force" "-f" "--skip-enable" "-k" "--print-conf" "-p" "--script" "--before-script" "--after-script" "--after-success" "--install" "--before-install" "--compiler" "--otp-release" "--go" "--jdk" "--node-js" "--perl" "--php" "--python" "--rvm" "--scala" "--env" "--gemfile");;
|
|
79
|
-
login) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check" "--api-endpoint" "-e" "--insecure" "--no-insecure" "-I" "--pro" "--org" "--staging" "--token" "-t" "--debug" "--enterprise" "-X" "--adapter" "--github-token" "--auto");;
|
|
79
|
+
login) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check" "--api-endpoint" "-e" "--insecure" "--no-insecure" "-I" "--pro" "--org" "--staging" "--token" "-t" "--debug" "--enterprise" "-X" "--adapter" "--github-token" "-g" "--auto-token" "-T" "--auto-password" "-p" "--auto" "-a" "--user" "-u" "--no-manual" "-M" "--list-github-token" "--skip-token-check");;
|
|
80
80
|
logout) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check" "--api-endpoint" "-e" "--insecure" "--no-insecure" "-I" "--pro" "--org" "--staging" "--token" "-t" "--debug" "--enterprise" "-X" "--adapter");;
|
|
81
81
|
logs) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check" "--api-endpoint" "-e" "--insecure" "--no-insecure" "-I" "--pro" "--org" "--staging" "--token" "-t" "--debug" "--enterprise" "-X" "--adapter" "--repo" "-r");;
|
|
82
82
|
monitor) reply=("--help" "-h" "--interactive" "--no-interactive" "-i" "--explode" "--no-explode" "-E" "--skip-version-check" "--skip-completion-check" "--api-endpoint" "-e" "--insecure" "--no-insecure" "-I" "--pro" "--org" "--staging" "--token" "-t" "--debug" "--enterprise" "-X" "--adapter" "--my-repos" "-m" "--repo" "-r" "--notify" "--no-notify" "-n" "--builds" "-b" "--push" "-p" "--pull" "-P");;
|
|
@@ -117,7 +117,7 @@ elif type complete 1>/dev/null 2>/dev/null; then
|
|
|
117
117
|
help) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check";;
|
|
118
118
|
history) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check --api-endpoint -e --insecure --no-insecure -I --pro --org --staging --token -t --debug --enterprise -X --adapter --repo -r --after -a --pull-request -p --branch -b --limit -l --date -d --all --no-all";;
|
|
119
119
|
init) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check --api-endpoint -e --insecure --no-insecure -I --pro --org --staging --token -t --debug --enterprise -X --adapter --repo -r --skip-sync -s --force -f --skip-enable -k --print-conf -p --script --before-script --after-script --after-success --install --before-install --compiler --otp-release --go --jdk --node-js --perl --php --python --rvm --scala --env --gemfile";;
|
|
120
|
-
login) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check --api-endpoint -e --insecure --no-insecure -I --pro --org --staging --token -t --debug --enterprise -X --adapter --github-token --auto";;
|
|
120
|
+
login) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check --api-endpoint -e --insecure --no-insecure -I --pro --org --staging --token -t --debug --enterprise -X --adapter --github-token -g --auto-token -T --auto-password -p --auto -a --user -u --no-manual -M --list-github-token --skip-token-check";;
|
|
121
121
|
logout) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check --api-endpoint -e --insecure --no-insecure -I --pro --org --staging --token -t --debug --enterprise -X --adapter";;
|
|
122
122
|
logs) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check --api-endpoint -e --insecure --no-insecure -I --pro --org --staging --token -t --debug --enterprise -X --adapter --repo -r";;
|
|
123
123
|
monitor) options="--help -h --interactive --no-interactive -i --explode --no-explode -E --skip-version-check --skip-completion-check --api-endpoint -e --insecure --no-insecure -I --pro --org --staging --token -t --debug --enterprise -X --adapter --my-repos -m --repo -r --notify --no-notify -n --builds -b --push -p --pull -P";;
|
|
@@ -124,6 +124,7 @@ module Travis
|
|
|
124
124
|
gh_config ||= {}
|
|
125
125
|
gh_config[:ssl] = Travis::Client::Session::SSL_OPTIONS
|
|
126
126
|
gh_config[:ssl] = { :verify => false } if gh_config[:api_url] and gh_config[:api_url] != "https://api.github.com"
|
|
127
|
+
gh_config.delete :scopes
|
|
127
128
|
|
|
128
129
|
gh_config[:instrumenter] = proc do |type, payload, &block|
|
|
129
130
|
next block.call unless type == 'http.gh'
|
data/lib/travis/cli/login.rb
CHANGED
|
@@ -1,71 +1,72 @@
|
|
|
1
1
|
require 'travis/cli'
|
|
2
|
-
require 'travis/tools/
|
|
2
|
+
require 'travis/tools/github'
|
|
3
3
|
require 'json'
|
|
4
4
|
|
|
5
5
|
module Travis
|
|
6
6
|
module CLI
|
|
7
7
|
class Login < ApiCommand
|
|
8
8
|
description "authenticates against the API and stores the token"
|
|
9
|
-
on '--github-token TOKEN', 'identify by GitHub token'
|
|
10
|
-
on '--auto',
|
|
9
|
+
on('-g', '--github-token TOKEN', 'identify by GitHub token')
|
|
10
|
+
on('-T', '--auto-token', 'try to figure out who you are automatically (might send another apps token to Travis, token will not be stored)')
|
|
11
|
+
on('-p', '--auto-password', 'try to load password from OSX keychain (will not be stored)')
|
|
12
|
+
on('-a', '--auto', 'shorthand for --auto-token --auto-password') { |c| c.auto_token = c.auto_password = true }
|
|
13
|
+
on('-u', '--user LOGIN', 'user to log in as') { |c,n| c.user_login = n }
|
|
14
|
+
on('-M', '--no-manual', 'do not use interactive login')
|
|
15
|
+
on('--list-github-token', 'instead of actually logging in, list found GitHub tokens')
|
|
16
|
+
on('--skip-token-check', 'don\'t verify the token with github')
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
attr_accessor :github_login, :github_password, :github_token, :github_otp, :callback
|
|
18
|
+
attr_accessor :user_login
|
|
14
19
|
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ensure
|
|
21
|
-
callback.call if callback
|
|
20
|
+
def list_token
|
|
21
|
+
github.after_tokens = proc { }
|
|
22
|
+
github.each_token do |token|
|
|
23
|
+
say token
|
|
24
|
+
end
|
|
22
25
|
end
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
options = { :username => github_login, :password => github_password }
|
|
31
|
-
options[:headers] = { "X-GitHub-OTP" => github_otp } if github_otp
|
|
32
|
-
gh = GH.with(options)
|
|
33
|
-
|
|
34
|
-
reply = gh.post('/authorizations', :scopes => github_scopes, :note => "temporary token to identify on #{api_endpoint}")
|
|
35
|
-
|
|
36
|
-
self.github_token = reply['token']
|
|
37
|
-
self.callback = proc { gh.delete reply['_links']['self']['href'] }
|
|
38
|
-
rescue GH::Error => error
|
|
39
|
-
if error.info[:response_status] == 401
|
|
40
|
-
ask_2fa
|
|
41
|
-
generate_github_token
|
|
42
|
-
else
|
|
43
|
-
raise error if explode?
|
|
44
|
-
error(JSON.parse(error.info[:response_body])["message"])
|
|
45
|
-
end
|
|
27
|
+
def login
|
|
28
|
+
github.with_token do |token|
|
|
29
|
+
endpoint_config['access_token'] = github_auth(token)
|
|
30
|
+
error("user mismatch: logged in as %p instead of %p" % [user.login, user_login]) if user_login and user.login != user_login
|
|
31
|
+
success("Successfully logged in as #{user.login}!")
|
|
46
32
|
end
|
|
33
|
+
end
|
|
47
34
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
def run
|
|
36
|
+
list_github_token ? list_token : login
|
|
37
|
+
end
|
|
51
38
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
39
|
+
def github
|
|
40
|
+
@github ||= begin
|
|
41
|
+
load_gh
|
|
42
|
+
Tools::Github.new(session.config['github']) do |g|
|
|
43
|
+
g.note = "temporary token to identify with the travis command line client against #{api_endpoint}"
|
|
44
|
+
g.manual_login = no_manual.nil?
|
|
45
|
+
g.explode = explode?
|
|
46
|
+
g.github_token = github_token
|
|
47
|
+
g.auto_token = auto_token
|
|
48
|
+
g.auto_password = auto_password
|
|
49
|
+
g.github_login = user_login
|
|
50
|
+
g.check_token = !skip_token_check?
|
|
51
|
+
g.drop_token = true
|
|
52
|
+
g.ask_login = proc { ask("Username: ") }
|
|
53
|
+
g.ask_password = proc { |user| ask("Password for #{user}: ") { |q| q.echo = "*" } }
|
|
54
|
+
g.ask_otp = proc { |user| ask("Two-factor authentication code for #{user}: ") }
|
|
55
|
+
g.login_header = proc { login_header }
|
|
56
|
+
g.debug = proc { |log| debug(log) }
|
|
57
|
+
g.after_tokens = proc { g.explode = true and error("no suitable github token found") }
|
|
58
|
+
end
|
|
63
59
|
end
|
|
60
|
+
end
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
def login_header
|
|
63
|
+
say "We need your #{color("GitHub login", :important)} to identify you."
|
|
64
|
+
say "This information will #{color("not be sent to Travis CI", :important)}, only to #{color(github_endpoint.host, :info)}."
|
|
65
|
+
say "The password will not be displayed."
|
|
66
|
+
empty_line
|
|
67
|
+
say "Try running with #{color("--github-token", :info)} or #{color("--auto", :info)} if you don't want to enter your password anyways."
|
|
68
|
+
empty_line
|
|
69
|
+
end
|
|
69
70
|
end
|
|
70
71
|
end
|
|
71
72
|
end
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
require 'travis/tools/system'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Travis
|
|
6
|
+
module Tools
|
|
7
|
+
class Github
|
|
8
|
+
TOKEN_SIZE = 40
|
|
9
|
+
GITHUB_API = 'api.github.com'
|
|
10
|
+
GITHUB_HOST = 'github.com'
|
|
11
|
+
|
|
12
|
+
attr_accessor :api_url, :scopes, :github_token, :github_login, :drop_token, :callback, :explode, :after_tokens,
|
|
13
|
+
:ask_login, :ask_password, :ask_otp, :login_header, :auto_token, :auto_password, :manual_login, :note,
|
|
14
|
+
:netrc_path, :hub_path, :oauth_paths, :composer_path, :git_config_keys, :debug, :no_token, :check_token
|
|
15
|
+
|
|
16
|
+
def initialize(options = nil)
|
|
17
|
+
@check_token = true
|
|
18
|
+
@manual_login = true
|
|
19
|
+
@ask_login = proc { raise "ask_login callback not set" }
|
|
20
|
+
@after_tokens = proc { }
|
|
21
|
+
@ask_password = proc { |_| raise "ask_password callback not set" }
|
|
22
|
+
@ask_otp = proc { |_| raise "ask_otp callback not set" }
|
|
23
|
+
@debug = proc { |_| }
|
|
24
|
+
@netrc_path = '~/.netrc'
|
|
25
|
+
@hub_path = ENV['HUB_CONFIG'] || '~/.config/hub'
|
|
26
|
+
@oauth_paths = ['~/.github-oauth-token']
|
|
27
|
+
@composer_path = "~/.composer/config.json"
|
|
28
|
+
@note = 'temporary token'
|
|
29
|
+
@git_config_keys = %w[github.token github.oauth-token]
|
|
30
|
+
@scopes = ['user', 'user:email', 'repo'] # overridden by value from /config
|
|
31
|
+
options.each_pair { |k,v| send("#{k}=", v) if respond_to? "#{k}=" } if options
|
|
32
|
+
yield self if block_given?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def with_token
|
|
36
|
+
each_token { |t| break yield(t) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def each_token
|
|
40
|
+
require 'gh' unless defined? GH
|
|
41
|
+
possible_tokens { |t| yield(t) if acceptable?(t) }
|
|
42
|
+
ensure
|
|
43
|
+
callback, self.callback = self.callback, nil
|
|
44
|
+
callback.call if callback
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def with_session(&block)
|
|
48
|
+
with_token { |t| GH.with(:token => t, &block) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def possible_tokens(&block)
|
|
52
|
+
return block[github_token] if github_token
|
|
53
|
+
|
|
54
|
+
if auto_token
|
|
55
|
+
netrc_tokens(&block)
|
|
56
|
+
git_tokens(&block)
|
|
57
|
+
hub_tokens(&block)
|
|
58
|
+
oauth_file_tokens(&block)
|
|
59
|
+
github_for_mac_token(&block)
|
|
60
|
+
issuepost_token(&block)
|
|
61
|
+
composer_token(&block)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if auto_password
|
|
65
|
+
possible_logins do |user, password|
|
|
66
|
+
yield login(user, password, false)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
if manual_login
|
|
71
|
+
login_header.call if login_header
|
|
72
|
+
user = github_login || ask_login.call
|
|
73
|
+
password = ask_password.call(user)
|
|
74
|
+
yield login(user, password, true)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
after_tokens.call
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def possible_logins(&block)
|
|
81
|
+
netrc_logins(&block)
|
|
82
|
+
hub_logins(&block)
|
|
83
|
+
keychain_login(&block)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def netrc_tokens
|
|
87
|
+
netrc.each do |entry|
|
|
88
|
+
next unless entry["machine"] == api_host or entry["machine"] == host
|
|
89
|
+
entry.values_at("token", "login", "password").each do |entry|
|
|
90
|
+
next if entry.to_s.size != TOKEN_SIZE
|
|
91
|
+
debug "found oauth token in netrc"
|
|
92
|
+
yield entry
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def git_tokens
|
|
98
|
+
return unless System.has? 'git'
|
|
99
|
+
git_config_keys.each do |key|
|
|
100
|
+
`git config --get-all #{key}`.each_line do |line|
|
|
101
|
+
token = line.strip
|
|
102
|
+
yield token unless token.empty?
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def composer_token
|
|
108
|
+
file(composer_path) do |content|
|
|
109
|
+
token = JSON.parse(content)['config'].fetch('github-oauth', {})[host]
|
|
110
|
+
yield token if token
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def hub_tokens
|
|
115
|
+
hub.fetch(host, []).each do |entry|
|
|
116
|
+
next if github_login and github_login != entry["user"]
|
|
117
|
+
yield entry["oauth_token"] if entry["oauth_token"]
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def oauth_file_tokens(&block)
|
|
122
|
+
oauth_paths.each do |path|
|
|
123
|
+
file(path) do |content|
|
|
124
|
+
token = content.strip
|
|
125
|
+
yield token unless token.empty?
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def netrc_logins
|
|
131
|
+
netrc.each do |entry|
|
|
132
|
+
next unless entry["machine"] == api_host or entry["machine"] == host
|
|
133
|
+
next if github_login and github_login != entry["login"]
|
|
134
|
+
yield entry["login"], entry["password"] if entry["login"] and entry["password"]
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def hub_logins
|
|
139
|
+
hub.fetch(host, []).each do |entry|
|
|
140
|
+
next if github_login and github_login != entry["user"]
|
|
141
|
+
yield entry["user"], entry["password"] if entry["user"] and entry["password"]
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def keychain_login
|
|
146
|
+
if github_login
|
|
147
|
+
security(:internet, :w, "-s #{host} -a #{github_login}", "#{host} password for #{github_login}") do |password|
|
|
148
|
+
yield github_login, password if password and not password.empty?
|
|
149
|
+
end
|
|
150
|
+
else
|
|
151
|
+
security(:internet, :g, "-s #{host}", "#{host} login and password") do |data|
|
|
152
|
+
username = data[/^\s+"acct"<blob>="(.*)"$/, 1].to_s
|
|
153
|
+
password = data[/^password: "(.*)"$/, 1].to_s
|
|
154
|
+
yield username, password unless username.empty? or password.empty?
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def netrc
|
|
160
|
+
file(netrc_path, []) do |contents|
|
|
161
|
+
contents.scan(/^\s*(\S+)\s+(\S+)\s*$/).inject([]) do |mapping, (key, value)|
|
|
162
|
+
mapping << {} if key == "machine"
|
|
163
|
+
mapping.last[key] = value if mapping.last
|
|
164
|
+
mapping
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def hub
|
|
170
|
+
file(hub_path, {}) do |contents|
|
|
171
|
+
YAML.load(contents)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def issuepost_token(&block)
|
|
176
|
+
security(:generic, :w, "-l issuepost.github.access_token", "issuepost token", &block) if host == 'github.com'
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def github_for_mac_token(&block)
|
|
180
|
+
command = '-s "github.com/mac"'
|
|
181
|
+
command << " -a #{github_login}" if github_login
|
|
182
|
+
security(:internet, :w, command, "GitHub for Mac token", &block) if host == 'github.com'
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def host
|
|
186
|
+
api_host == GITHUB_API ? GITHUB_HOST : api_host
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def api_host
|
|
190
|
+
return GITHUB_API unless api_url
|
|
191
|
+
api_url[%r{^(?:https?://)?([^/]+)}, 1]
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def login(user, password, die = true, otp = nil)
|
|
195
|
+
opt = { :username => user, :password => password }
|
|
196
|
+
opt[:headers] = { "X-GitHub-OTP" => otp } if otp
|
|
197
|
+
gh = GH.with(opt)
|
|
198
|
+
reply = gh.post('/authorizations', :scopes => scopes, :note => note)
|
|
199
|
+
self.callback = proc { gh.delete reply['_links']['self']['href'] }
|
|
200
|
+
reply['token']
|
|
201
|
+
rescue GH::Error => error
|
|
202
|
+
if error.info[:response_status] == 401
|
|
203
|
+
login(user, password, die, ask_otp.call(user))
|
|
204
|
+
elsif die
|
|
205
|
+
raise gh_error(error)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def acceptable?(token)
|
|
210
|
+
return true unless check_token
|
|
211
|
+
gh = GH.with(:token => token)
|
|
212
|
+
user = gh['user']
|
|
213
|
+
|
|
214
|
+
if github_login and github_login != user['login']
|
|
215
|
+
debug "token is not acceptable: identifies %p instead of %p" % [user['login'], github_login]
|
|
216
|
+
false
|
|
217
|
+
else
|
|
218
|
+
true
|
|
219
|
+
end
|
|
220
|
+
rescue GH::Error => error
|
|
221
|
+
debug "token is not acceptable: #{gh_error(error)}"
|
|
222
|
+
false
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
private
|
|
226
|
+
|
|
227
|
+
def gh_error(error)
|
|
228
|
+
raise error if explode
|
|
229
|
+
JSON.parse(error.info[:response_body])["message"].to_s
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def debug(line)
|
|
233
|
+
return unless @debug
|
|
234
|
+
@debug.call "Tools::Github: #{line}"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def security(type, key, arg, name)
|
|
238
|
+
return false unless System.has? 'security'
|
|
239
|
+
return false unless system "security find-#{type}-password #{arg} 2>/dev/null >/dev/null"
|
|
240
|
+
debug "requesting to load #{name} from keychain"
|
|
241
|
+
result = %x[security find-#{type}-password #{arg} -#{key} 2>&1].chomp
|
|
242
|
+
$?.success? ? yield(result) : debug("request denied")
|
|
243
|
+
rescue => e
|
|
244
|
+
raise e if explode
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def file(path, default = nil)
|
|
248
|
+
path &&= File.expand_path(path)
|
|
249
|
+
@file ||= {}
|
|
250
|
+
@file[path] ||= if path and File.readable?(path)
|
|
251
|
+
debug "reading #{path}"
|
|
252
|
+
yield File.read(path)
|
|
253
|
+
end
|
|
254
|
+
@file[path] || default
|
|
255
|
+
rescue => e
|
|
256
|
+
raise e if explode
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
data/spec/cli/login_spec.rb
CHANGED
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Travis::CLI::Login do
|
|
4
4
|
example "travis login", :unless => Travis::Tools::System.windows? do
|
|
5
|
-
run_cli('login') { |i| i.puts('rkh', 'password') }.should be_success
|
|
5
|
+
run_cli('login', '-E', '--skip-token-check') { |i| i.puts('rkh', 'password') }.should be_success
|
|
6
6
|
run_cli('whoami').out.should be == "rkh\n"
|
|
7
7
|
end
|
|
8
8
|
|
data/spec/support/fake_github.rb
CHANGED
|
@@ -7,6 +7,10 @@ module GH
|
|
|
7
7
|
super
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
def http(*)
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
def post(key, body)
|
|
11
15
|
raise GH::Error unless @authenticated and key == '/authorizations'
|
|
12
16
|
frontend.load("url" => "https://api.github.com/authorizations/1", "token" => "github_token")
|
data/travis.gemspec
CHANGED
|
@@ -171,10 +171,10 @@ Gem::Specification.new do |s|
|
|
|
171
171
|
"lib/travis/tools/assets.rb",
|
|
172
172
|
"lib/travis/tools/completion.rb",
|
|
173
173
|
"lib/travis/tools/formatter.rb",
|
|
174
|
+
"lib/travis/tools/github.rb",
|
|
174
175
|
"lib/travis/tools/notification.rb",
|
|
175
176
|
"lib/travis/tools/safe_string.rb",
|
|
176
177
|
"lib/travis/tools/system.rb",
|
|
177
|
-
"lib/travis/tools/token_finder.rb",
|
|
178
178
|
"lib/travis/version.rb",
|
|
179
179
|
"spec/cli/cancel_spec.rb",
|
|
180
180
|
"spec/cli/encrypt_spec.rb",
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: travis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.4.travis.
|
|
4
|
+
version: 1.6.4.travis.411.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Haase
|
|
@@ -364,10 +364,10 @@ files:
|
|
|
364
364
|
- lib/travis/tools/assets.rb
|
|
365
365
|
- lib/travis/tools/completion.rb
|
|
366
366
|
- lib/travis/tools/formatter.rb
|
|
367
|
+
- lib/travis/tools/github.rb
|
|
367
368
|
- lib/travis/tools/notification.rb
|
|
368
369
|
- lib/travis/tools/safe_string.rb
|
|
369
370
|
- lib/travis/tools/system.rb
|
|
370
|
-
- lib/travis/tools/token_finder.rb
|
|
371
371
|
- lib/travis/version.rb
|
|
372
372
|
- spec/cli/cancel_spec.rb
|
|
373
373
|
- spec/cli/encrypt_spec.rb
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
require 'netrc'
|
|
2
|
-
require 'yaml'
|
|
3
|
-
|
|
4
|
-
module Travis
|
|
5
|
-
module Tools
|
|
6
|
-
# This is used when running `travis login --auto`
|
|
7
|
-
class TokenFinder
|
|
8
|
-
attr_accessor :netrc, :hub, :explode, :github
|
|
9
|
-
|
|
10
|
-
def self.find(options = {})
|
|
11
|
-
new(options).find
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def initialize(options = {})
|
|
15
|
-
self.netrc = options[:netrc] || Netrc.default_path
|
|
16
|
-
self.hub = options[:hub] || ENV['HUB_CONFIG'] || '~/.config/hub'
|
|
17
|
-
self.github = options[:github]
|
|
18
|
-
self.github = 'github.com' if github.nil? or github == 'api.github.com'
|
|
19
|
-
self.explode = options[:explode]
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def hub=(file)
|
|
23
|
-
@hub = File.expand_path(file)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def netrc=(file)
|
|
27
|
-
@netrc = File.expand_path(file)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def find
|
|
31
|
-
find_netrc || find_hub
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def find_netrc
|
|
35
|
-
return unless File.readable? netrc
|
|
36
|
-
data = Netrc.read(netrc)[github]
|
|
37
|
-
data.detect { |e| e.size == 40 } if data
|
|
38
|
-
rescue => e
|
|
39
|
-
raise e if explode
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def find_hub
|
|
43
|
-
return unless File.readable? hub
|
|
44
|
-
data = YAML.load_file(File.expand_path(hub))
|
|
45
|
-
data &&= Array(data[github])
|
|
46
|
-
data.first['oauth_token'] if data.size == 1
|
|
47
|
-
rescue => e
|
|
48
|
-
raise e if explode
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|