mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-09 04:36:11 +10:00
Import from Github using Personal Access Tokens.
This stands as an alternative to using OAuth to access a user's Github repositories. This is setup in such a way that it can be used without OAuth configuration. From a UI perspective, the how to import modal has been replaced by a full page, which includes a form for posting a personal access token back to the Import::GithubController. If the user has logged in via GitHub, skip the Personal Access Token and go directly to Github for an access token via OAuth.
This commit is contained in:
committed by
Rémy Coutable
parent
c5d164d1df
commit
12aa1f898d
@@ -1,14 +1,29 @@
|
||||
class Import::GithubController < Import::BaseController
|
||||
before_action :verify_github_import_enabled
|
||||
before_action :github_auth, except: :callback
|
||||
before_action :github_auth, except: [:callback, :new, :personal_access_token]
|
||||
|
||||
rescue_from Octokit::Unauthorized, with: :github_unauthorized
|
||||
|
||||
helper_method :logged_in_with_github?
|
||||
|
||||
def new
|
||||
if logged_in_with_github?
|
||||
go_to_github_for_permissions
|
||||
elsif session[:github_access_token]
|
||||
redirect_to status_import_github_url
|
||||
end
|
||||
end
|
||||
|
||||
def callback
|
||||
session[:github_access_token] = client.get_token(params[:code])
|
||||
redirect_to status_import_github_url
|
||||
end
|
||||
|
||||
def personal_access_token
|
||||
session[:github_access_token] = params[:personal_access_token]
|
||||
redirect_to status_import_github_url
|
||||
end
|
||||
|
||||
def status
|
||||
@repos = client.repos
|
||||
@already_added_projects = current_user.created_projects.where(import_type: "github")
|
||||
@@ -57,10 +72,14 @@ class Import::GithubController < Import::BaseController
|
||||
end
|
||||
|
||||
def github_unauthorized
|
||||
go_to_github_for_permissions
|
||||
session[:github_access_token] = nil
|
||||
redirect_to new_import_github_url,
|
||||
alert: 'Access denied to your GitHub account.'
|
||||
end
|
||||
|
||||
private
|
||||
def logged_in_with_github?
|
||||
current_user.identities.exists?(provider: 'github')
|
||||
end
|
||||
|
||||
def access_params
|
||||
{ github_access_token: session[:github_access_token] }
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
- page_title "GitHub Import"
|
||||
- header_title "Projects", root_path
|
||||
|
||||
%h3.page-title
|
||||
= icon 'github', text: 'Import Projects from GitHub'
|
||||
|
||||
%p.light
|
||||
To import a project from GitHub, you can use a
|
||||
= link_to 'Personal Access Token', 'https://github.com/settings/tokens'
|
||||
to access your GitHub account. When you create your Personal Access Token,
|
||||
you will need to select the <code>repo</code> scope, so we can display a
|
||||
list of your public and private repositories which are available for import.
|
||||
|
||||
= form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do
|
||||
.form-group
|
||||
= text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40
|
||||
= submit_tag 'List Repositories', class: 'btn btn-create'
|
||||
|
||||
- if github_import_configured?
|
||||
- unless logged_in_with_github?
|
||||
%hr
|
||||
%p.light
|
||||
Note: If you go to
|
||||
= link_to 'your profile', profile_account_path
|
||||
and connect your account to GitHub, you can import projects without
|
||||
generating a Personal Access Token.
|
||||
- else
|
||||
%hr
|
||||
%p.light
|
||||
Note:
|
||||
- if current_user.admin?
|
||||
As an administrator you may like to configure
|
||||
- else
|
||||
Consider asking your GitLab administrator to configure
|
||||
= link_to 'GitHub integration', help_page_path("integration", "github")
|
||||
which will allow login via GitHub and allow importing projects without
|
||||
generating a Personal Access Token.
|
||||
@@ -1,13 +0,0 @@
|
||||
%div#github_import_modal.modal
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-header
|
||||
%a.close{href: "#", "data-dismiss" => "modal"} ×
|
||||
%h3 Import projects from GitHub
|
||||
.modal-body
|
||||
To enable importing projects from GitHub,
|
||||
- if current_user.admin?
|
||||
as administrator you need to configure
|
||||
- else
|
||||
ask your Gitlab administrator to configure
|
||||
== #{link_to 'OAuth integration', help_page_path("integration", "github")}.
|
||||
@@ -23,6 +23,7 @@
|
||||
.input-group-addon
|
||||
= root_url
|
||||
= f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user, display_path: true), {}, {class: 'select2 js-select-namespace', tabindex: 1}
|
||||
|
||||
- else
|
||||
.input-group-addon.static-namespace
|
||||
#{root_url}#{current_user.username}/
|
||||
@@ -44,15 +45,8 @@
|
||||
.col-sm-12.import-buttons
|
||||
%div
|
||||
- if github_import_enabled?
|
||||
- if github_import_configured?
|
||||
= link_to status_import_github_path, class: 'btn import_github' do
|
||||
%i.fa.fa-github
|
||||
GitHub
|
||||
- else
|
||||
= link_to '#', class: 'how_to_import_link btn import_github' do
|
||||
%i.fa.fa-github
|
||||
GitHub
|
||||
= render 'github_import_modal'
|
||||
= link_to new_import_github_path, class: 'btn import_github' do
|
||||
= icon 'github', text: 'GitHub'
|
||||
%div
|
||||
- if bitbucket_import_enabled?
|
||||
- if bitbucket_import_configured?
|
||||
|
||||
@@ -10,7 +10,8 @@ paths_to_be_protected = [
|
||||
"#{Rails.application.config.relative_url_root}/api/#{API::API.version}/session",
|
||||
"#{Rails.application.config.relative_url_root}/users",
|
||||
"#{Rails.application.config.relative_url_root}/users/confirmation",
|
||||
"#{Rails.application.config.relative_url_root}/unsubscribes/"
|
||||
"#{Rails.application.config.relative_url_root}/unsubscribes/",
|
||||
"#{Rails.application.config.relative_url_root}/import/github/personal_access_token"
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@ Rails.application.routes.draw do
|
||||
#
|
||||
namespace :import do
|
||||
resource :github, only: [:create, :new], controller: :github do
|
||||
post :personal_access_token
|
||||
get :status
|
||||
get :callback
|
||||
get :jobs
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# Import your project from GitHub to GitLab
|
||||
|
||||
>**Note:**
|
||||
In order to enable the GitHub import setting, you should first
|
||||
enable the [GitHub integration][gh-import] in your GitLab instance.
|
||||
In order to enable the GitHub import setting, you may also want to
|
||||
enable the [GitHub integration][gh-import] in your GitLab instance. This
|
||||
configuration is optional, you will be able import your GitHub repositories
|
||||
with a Personal Access Token.
|
||||
|
||||
At its current state, GitHub importer can import:
|
||||
|
||||
@@ -20,9 +22,13 @@ It is not yet possible to import your cross-repository pull requests (those from
|
||||
forks). We are working on improving this in the near future.
|
||||
|
||||
The importer page is visible when you [create a new project][new-project].
|
||||
Click on the **GitHub** link and you will be redirected to GitHub for
|
||||
permission to access your projects. After accepting, you'll be automatically
|
||||
redirected to the importer.
|
||||
Click on the **GitHub** link and, if you are logged in via the GitHub
|
||||
integration, you will be redirected to GitHub for permission to access your
|
||||
projects. After accepting, you'll be automatically redirected to the importer.
|
||||
|
||||
If you are not using the GitHub integration, when you click the **GithHub** link
|
||||
you'll be presented with instructions for creating Personal Access Token on
|
||||
GitHub. Once you upload your token, you'll be taken to the importer.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Background:
|
||||
Scenario: I should see instructions on how to import from GitHub
|
||||
Given I see "New Project" page
|
||||
When I click on "Import project from GitHub"
|
||||
Then I see instructions on how to import from GitHub
|
||||
Then I am redirected to the Github import page
|
||||
|
||||
@javascript
|
||||
Scenario: I should see Google Code import page
|
||||
|
||||
@@ -28,14 +28,8 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps
|
||||
first('.import_github').click
|
||||
end
|
||||
|
||||
step 'I see instructions on how to import from GitHub' do
|
||||
github_modal = first('.modal-body')
|
||||
expect(github_modal).to be_visible
|
||||
expect(github_modal).to have_content "To enable importing projects from GitHub"
|
||||
|
||||
page.all('.modal-body').each do |element|
|
||||
expect(element).not_to be_visible unless element == github_modal
|
||||
end
|
||||
step 'I am redirected to the Github import page' do
|
||||
expect(current_path).to eq new_import_github_path
|
||||
end
|
||||
|
||||
step 'I click on "Repo by URL"' do
|
||||
|
||||
@@ -4,26 +4,39 @@ module Gitlab
|
||||
GITHUB_SAFE_REMAINING_REQUESTS = 100
|
||||
GITHUB_SAFE_SLEEP_TIME = 500
|
||||
|
||||
attr_reader :client, :api
|
||||
attr_reader :access_token
|
||||
|
||||
def initialize(access_token)
|
||||
@client = ::OAuth2::Client.new(
|
||||
@access_token = access_token
|
||||
|
||||
if access_token
|
||||
::Octokit.auto_paginate = false
|
||||
end
|
||||
end
|
||||
|
||||
def api
|
||||
@api ||= ::Octokit::Client.new(
|
||||
access_token: access_token,
|
||||
api_endpoint: github_options[:site],
|
||||
# If there is no config, we're connecting to github.com and we
|
||||
# should verify ssl.
|
||||
connection_options: {
|
||||
ssl: { verify: config ? config['verify_ssl'] : true }
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def client
|
||||
unless config
|
||||
raise Projects::ImportService::Error,
|
||||
'OAuth configuration for GitHub missing.'
|
||||
end
|
||||
|
||||
@client ||= ::OAuth2::Client.new(
|
||||
config.app_id,
|
||||
config.app_secret,
|
||||
github_options.merge(ssl: { verify: config['verify_ssl'] })
|
||||
)
|
||||
|
||||
if access_token
|
||||
::Octokit.auto_paginate = false
|
||||
|
||||
@api = ::Octokit::Client.new(
|
||||
access_token: access_token,
|
||||
api_endpoint: github_options[:site],
|
||||
connection_options: {
|
||||
ssl: { verify: config['verify_ssl'] }
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_url(redirect_uri)
|
||||
@@ -56,7 +69,11 @@ module Gitlab
|
||||
end
|
||||
|
||||
def github_options
|
||||
config["args"]["client_options"].deep_symbolize_keys
|
||||
if config
|
||||
config["args"]["client_options"].deep_symbolize_keys
|
||||
else
|
||||
OmniAuth::Strategies::GitHub.default_options[:client_options].symbolize_keys
|
||||
end
|
||||
end
|
||||
|
||||
def rate_limit
|
||||
|
||||
@@ -16,6 +16,24 @@ describe Import::GithubController do
|
||||
allow(controller).to receive(:github_import_enabled?).and_return(true)
|
||||
end
|
||||
|
||||
describe "GET new" do
|
||||
it "redirects to GitHub for an access token if logged in with GitHub" do
|
||||
allow(controller).to receive(:logged_in_with_github?).and_return(true)
|
||||
expect(controller).to receive(:go_to_github_for_permissions)
|
||||
|
||||
get :new
|
||||
end
|
||||
|
||||
it "redirects to status if we already have a token" do
|
||||
assign_session_token
|
||||
allow(controller).to receive(:logged_in_with_github?).and_return(false)
|
||||
|
||||
get :new
|
||||
|
||||
expect(controller).to redirect_to(status_import_github_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET callback" do
|
||||
it "updates access token" do
|
||||
token = "asdasd12345"
|
||||
@@ -32,6 +50,20 @@ describe Import::GithubController do
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST personal_access_token" do
|
||||
it "updates access token" do
|
||||
token = "asdfasdf9876"
|
||||
|
||||
allow_any_instance_of(Gitlab::GithubImport::Client).
|
||||
to receive(:user).and_return(true)
|
||||
|
||||
post :personal_access_token, personal_access_token: token
|
||||
|
||||
expect(session[:github_access_token]).to eq(token)
|
||||
expect(controller).to redirect_to(status_import_github_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET status" do
|
||||
before do
|
||||
@repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim')
|
||||
@@ -59,6 +91,17 @@ describe Import::GithubController do
|
||||
expect(assigns(:already_added_projects)).to eq([@project])
|
||||
expect(assigns(:repos)).to eq([])
|
||||
end
|
||||
|
||||
it "handles an invalid access token" do
|
||||
allow_any_instance_of(Gitlab::GithubImport::Client).
|
||||
to receive(:repos).and_raise(Octokit::Unauthorized)
|
||||
|
||||
get :status
|
||||
|
||||
expect(session[:github_access_token]).to eq(nil)
|
||||
expect(controller).to redirect_to(new_import_github_url)
|
||||
expect(flash[:alert]).to eq('Access denied to your GitHub account.')
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST create" do
|
||||
|
||||
@@ -20,6 +20,20 @@ describe Gitlab::GithubImport::Client, lib: true do
|
||||
expect { client.api }.not_to raise_error
|
||||
end
|
||||
|
||||
context 'when config is missing' do
|
||||
before do
|
||||
allow(Gitlab.config.omniauth).to receive(:providers).and_return([])
|
||||
end
|
||||
|
||||
it 'is still possible to get an Octokit client' do
|
||||
expect { client.api }.not_to raise_error
|
||||
end
|
||||
|
||||
it 'is not be possible to get an OAuth2 client' do
|
||||
expect { client.client }.to raise_error(Projects::ImportService::Error)
|
||||
end
|
||||
end
|
||||
|
||||
context 'allow SSL verification to be configurable on API' do
|
||||
before do
|
||||
github_provider['verify_ssl'] = false
|
||||
|
||||
Reference in New Issue
Block a user