diff --git a/plugins/github/src/META-INF/plugin.xml b/plugins/github/src/META-INF/plugin.xml index ab5c98b0b48b..0a10d8490308 100644 --- a/plugins/github/src/META-INF/plugin.xml +++ b/plugins/github/src/META-INF/plugin.xml @@ -25,6 +25,7 @@ + diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiTaskExecutor.kt b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiTaskExecutor.kt index 657e0d13d2df..e25560153a4a 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiTaskExecutor.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiTaskExecutor.kt @@ -2,6 +2,7 @@ package org.jetbrains.plugins.github.api import com.intellij.openapi.application.invokeAndWaitIfNeed +import com.intellij.openapi.components.service import com.intellij.openapi.progress.EmptyProgressIndicator import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.ui.Messages @@ -91,6 +92,11 @@ class GithubApiTaskExecutor(private val authenticationManager: GithubAuthenticat return originalAuth.copyWithTwoFactorCode(code) } + + @JvmStatic + fun getInstance(): GithubApiTaskExecutor { + return service() + } } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/authentication/GithubAuthenticationManager.kt b/plugins/github/src/org/jetbrains/plugins/github/authentication/GithubAuthenticationManager.kt index 0e9d7ed313cb..20a7b54c4ee3 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/authentication/GithubAuthenticationManager.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/authentication/GithubAuthenticationManager.kt @@ -1,18 +1,28 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.github.authentication +import com.intellij.openapi.project.Project +import git4idea.DialogManager import com.intellij.openapi.components.service import org.jetbrains.annotations.CalledInAny +import org.jetbrains.annotations.CalledInAwt import org.jetbrains.annotations.TestOnly import org.jetbrains.plugins.github.api.GithubServerPath import org.jetbrains.plugins.github.authentication.accounts.GithubAccount import org.jetbrains.plugins.github.authentication.accounts.GithubAccountManager import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException +import org.jetbrains.plugins.github.authentication.ui.GithubLoginDialog /** * Entry point for interactions with Github authentication subsystem */ class GithubAuthenticationManager internal constructor(private val accountManager: GithubAccountManager) { + @CalledInAny + fun hasAccounts() = accountManager.accounts.isNotEmpty() + + @CalledInAny + fun getAccounts(): Set = accountManager.accounts + @CalledInAny internal fun getTokenForAccount(account: GithubAccount): String { val token = accountManager.getTokenForAccount(account) @@ -20,6 +30,22 @@ class GithubAuthenticationManager internal constructor(private val accountManage else return token } + @CalledInAwt + fun requestNewAccount(project: Project): GithubAccount? { + fun isAccountUnique(name: String, server: GithubServerPath) = + accountManager.accounts.none { it.name == name && it.server == server } + + val dialog = GithubLoginDialog(project, ::isAccountUnique) + DialogManager.show(dialog) + if (dialog.isOK) { + val account = GithubAccount(dialog.getLogin(), dialog.getServer()) + accountManager.accounts += account + accountManager.updateAccountToken(account, dialog.getToken()) + return account + } + return null + } + @TestOnly fun registerAccount(name: String, host: String, token: String): GithubAccount { val account = GithubAccount(name, GithubServerPath.from(host)) diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubRepositoryHostingService.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubRepositoryHostingService.java index 23eda1a14619..1093ba7e3634 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubRepositoryHostingService.java +++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubRepositoryHostingService.java @@ -5,64 +5,69 @@ import com.intellij.dvcs.hosting.RepositoryListLoader; import com.intellij.dvcs.hosting.RepositoryListLoadingException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; -import git4idea.DialogManager; import git4idea.remote.GitRepositoryHostingService; import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.github.api.GithubApiTaskExecutor; import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.data.GithubRepo; -import org.jetbrains.plugins.github.ui.GithubLoginDialog; -import org.jetbrains.plugins.github.util.*; +import org.jetbrains.plugins.github.authentication.GithubAuthenticationManager; +import org.jetbrains.plugins.github.authentication.accounts.GithubAccount; +import org.jetbrains.plugins.github.util.GithubGitHelper; +import org.jetbrains.plugins.github.util.GithubUtil; +import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class GithubRepositoryHostingService extends GitRepositoryHostingService { + @NotNull private final GithubAuthenticationManager myAuthenticationManager; + @NotNull private final GithubGitHelper myGitHelper; + + public GithubRepositoryHostingService(@NotNull GithubAuthenticationManager manager, + @NotNull GithubGitHelper gitHelper) { + myAuthenticationManager = manager; + myGitHelper = gitHelper; + } + @NotNull @Override public String getServiceDisplayName() { - return "GitHub"; + return GithubUtil.SERVICE_DISPLAY_NAME; } @Override @NotNull public RepositoryListLoader getRepositoryListLoader(@NotNull Project project) { return new RepositoryListLoader() { - @NotNull private final GithubAuthDataHolder myAuthDataHolder = GithubAuthDataHolder.createFromSettings(); - @Override public boolean isEnabled() { - return AuthLevel.LOGGED.accepts(myAuthDataHolder.getAuthData()); + return myAuthenticationManager.hasAccounts(); } @Override public boolean enable() { - GithubAuthData currentAuthData = myAuthDataHolder.getAuthData(); - myAuthDataHolder.runTransaction(currentAuthData, () -> { - GithubLoginDialog dialog = new GithubLoginDialog(project, currentAuthData, AuthLevel.LOGGED); - DialogManager.show(dialog); - if (dialog.isOK()) { - GithubAuthData authData = dialog.getAuthData(); - GithubSettings.getInstance().setAuthData(authData, dialog.isSavePasswordSelected()); - return authData; - } - return currentAuthData; - }); - return isEnabled(); + return myAuthenticationManager.requestNewAccount(project) != null; } @NotNull @Override public List getAvailableRepositories(@NotNull ProgressIndicator progressIndicator) throws RepositoryListLoadingException { try { - return GithubUtil.runTask(project, myAuthDataHolder, progressIndicator, connection -> GithubApiUtil.getAvailableRepos(connection)) - .stream() - .sorted(Comparator.comparing(GithubRepo::getUserName).thenComparing(GithubRepo::getName)) - .map(repo -> GithubUrlUtil - .getCloneUrl(GithubUrlUtil.getGitHostWithoutProtocol(myAuthDataHolder.getAuthData().getHost()), - repo.getUserName(), - repo.getName())) - .collect(Collectors.toList()); + List urls = new ArrayList<>(); + for (GithubAccount account : myAuthenticationManager.getAccounts()) { + urls.addAll( + GithubApiTaskExecutor.getInstance().execute(progressIndicator, account, + connection -> GithubApiUtil.getAvailableRepos(connection)) + .stream() + .sorted(Comparator.comparing(GithubRepo::getUserName).thenComparing(GithubRepo::getName)) + .map(repo -> myGitHelper.getRemoteUrl(account.getServer(), + repo.getUserName(), + repo.getName())) + .collect(Collectors.toList()) + ); + } + return urls; } catch (Exception e) { throw new RepositoryListLoadingException("Error connecting to Github", e); diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubGitHelper.kt b/plugins/github/src/org/jetbrains/plugins/github/util/GithubGitHelper.kt new file mode 100644 index 000000000000..70e2267a9c0c --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubGitHelper.kt @@ -0,0 +1,19 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.github.util + +import org.jetbrains.plugins.github.api.GithubServerPath + +/** + * Utilities for Github-Git interactions + */ +class GithubGitHelper(private val githubSettings: GithubSettings) { + + fun getRemoteUrl(server: GithubServerPath, user: String, repo: String): String { + return if (githubSettings.isCloneGitUsingSsh) { + "git@${server.host}:${server.suffix?.substring(1).orEmpty()}/$user/$repo.git" + } + else { + "https://${server.host}${server.suffix.orEmpty()}/$user/$repo.git" + } + } +} \ No newline at end of file