travis 1.6.4.travis.410.4 → 1.6.4.travis.411.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|