mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Github: share project on github refactoring: split into more functions
This commit is contained in:
@@ -37,7 +37,6 @@ import com.intellij.util.containers.HashSet;
|
||||
import git4idea.DialogManager;
|
||||
import git4idea.GitLocalBranch;
|
||||
import git4idea.GitUtil;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.actions.BasicAction;
|
||||
import git4idea.actions.GitInit;
|
||||
import git4idea.commands.*;
|
||||
@@ -48,6 +47,7 @@ import git4idea.util.GitFileUtils;
|
||||
import git4idea.util.GitUIUtil;
|
||||
import icons.GithubIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.github.ui.GithubShareDialog;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -78,24 +78,27 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
|
||||
// get gitRepository
|
||||
// check for existing git repo
|
||||
// check available repos (net)
|
||||
// check privateRepo access (net)
|
||||
// check available repos and privateRepo access (net)
|
||||
// Show dialog (window)
|
||||
// create GitHub repo (net)
|
||||
// create local git repo
|
||||
// create local git repo (if not exist)
|
||||
// add GitHub as a remote host
|
||||
// make first commit
|
||||
// push everything (net)
|
||||
@Override
|
||||
public void actionPerformed(final AnActionEvent e) {
|
||||
// get gitRepository
|
||||
final Project project = e.getData(PlatformDataKeys.PROJECT);
|
||||
if (project == null || !GithubUtil.testGitExecutable(project)) {
|
||||
return;
|
||||
}
|
||||
|
||||
shareProjectOnGithub(project);
|
||||
}
|
||||
|
||||
public static void shareProjectOnGithub(@NotNull final Project project) {
|
||||
BasicAction.saveAll();
|
||||
|
||||
// get gitRepository
|
||||
final VirtualFile root = project.getBaseDir();
|
||||
final GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
|
||||
final GitRepository gitRepository = manager.getRepositoryForFile(root);
|
||||
@@ -109,15 +112,85 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
GithubNotifications.showInfoURL(project, "Project is already on GitHub", "GitHub", githubRemote);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
externalRemoteDetected = !gitRepository.getRemotes().isEmpty();
|
||||
}
|
||||
externalRemoteDetected = !gitRepository.getRemotes().isEmpty();
|
||||
}
|
||||
|
||||
// get available GitHub repos with modal progress
|
||||
final Ref<HashSet<String>> repoNamesRef = new Ref<HashSet<String>>();
|
||||
final Ref<GithubUser> userInfoRef = new Ref<GithubUser>();
|
||||
final Ref<GithubAuthData> authRef = new Ref<GithubAuthData>();
|
||||
final GithubInfo githubInfo = loadGithubInfoWithModal(project);
|
||||
if (githubInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show dialog (window)
|
||||
final GithubShareDialog shareDialog =
|
||||
new GithubShareDialog(project, githubInfo.getRepositoryNames(), githubInfo.getUser().canCreatePrivateRepo());
|
||||
//shareDialog.show();
|
||||
DialogManager.show(shareDialog);
|
||||
if (!shareDialog.isOK()) {
|
||||
return;
|
||||
}
|
||||
final boolean isPrivate = shareDialog.isPrivate();
|
||||
final String name = shareDialog.getRepositoryName();
|
||||
final String description = shareDialog.getDescription();
|
||||
|
||||
// finish the job in background
|
||||
final boolean finalExternalRemoteDetected = externalRemoteDetected;
|
||||
new Task.Backgroundable(project, "Sharing project on GitHub") {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
// create GitHub repo (network)
|
||||
LOG.info("Creating GitHub repository");
|
||||
indicator.setText("Creating GitHub repository");
|
||||
final String url = createGithubRepository(project, githubInfo.getAuthData(), name, description, isPrivate);
|
||||
if (url == null) {
|
||||
return;
|
||||
}
|
||||
LOG.info("Successfully created GitHub repository");
|
||||
|
||||
// creating empty git repo if git is not initialized
|
||||
LOG.info("Binding local project with GitHub");
|
||||
if (!gitDetected) {
|
||||
LOG.info("No git detected, creating empty git repo");
|
||||
indicator.setText("Creating empty git repo");
|
||||
if (!createEmptyGitRepository(project, root, indicator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GitRepositoryManager repositoryManager = ServiceManager.getService(project, GitRepositoryManager.class);
|
||||
final GitRepository repository = repositoryManager.getRepositoryForRoot(root);
|
||||
LOG.assertTrue(repository != null, "GitRepository is null for root " + root);
|
||||
|
||||
final String remoteUrl = GithubApiUtil.getGitHost() + "/" + githubInfo.getUser().getLogin() + "/" + name + ".git";
|
||||
final String remoteName = finalExternalRemoteDetected ? "github" : "origin";
|
||||
|
||||
//git remote add origin git@github.com:login/name.git
|
||||
LOG.info("Adding GitHub as a remote host");
|
||||
indicator.setText("Adding GitHub as a remote host");
|
||||
if (!addGithubRemote(project, root, remoteName, remoteUrl, repository)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create sample commit for binding project
|
||||
if (!performFirstCommitIfRequired(project, root, repository, indicator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//git push origin master
|
||||
LOG.info("Pushing to github master");
|
||||
indicator.setText("Pushing to github master");
|
||||
if (!pushCurrentBranch(project, repository, remoteName, remoteUrl, name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GithubNotifications.showInfoURL(project, "Successfully created project on GitHub", name, url);
|
||||
}
|
||||
}.queue();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static GithubInfo loadGithubInfoWithModal(@NotNull final Project project) {
|
||||
final Ref<GithubInfo> githubInfoRef = new Ref<GithubInfo>();
|
||||
final Ref<IOException> exceptionRef = new Ref<IOException>();
|
||||
ProgressManager.getInstance().run(new Task.Modal(project, "Access to GitHub", true) {
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
@@ -138,12 +211,13 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
for (RepositoryInfo info : availableReposRef.get()) {
|
||||
names.add(info.getName());
|
||||
}
|
||||
repoNamesRef.set(names);
|
||||
|
||||
// check access to private repos (network)
|
||||
final GithubUser userInfo = GithubUtil.getCurrentUserInfo(auth);
|
||||
userInfoRef.set(userInfo);
|
||||
authRef.set(auth);
|
||||
if (userInfo == null) {
|
||||
return;
|
||||
}
|
||||
githubInfoRef.set(new GithubInfo(auth, userInfo, names));
|
||||
}
|
||||
catch (IOException e) {
|
||||
exceptionRef.set(e);
|
||||
@@ -152,138 +226,58 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
});
|
||||
if (!exceptionRef.isNull()) {
|
||||
GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", exceptionRef.get().getMessage());
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (repoNamesRef.isNull() || userInfoRef.isNull()) {
|
||||
if (githubInfoRef.isNull()) {
|
||||
GithubNotifications.showErrorDialog(project, "Failed to connect to GitHub", "Failed to gather user information");
|
||||
return;
|
||||
}
|
||||
|
||||
// Show dialog (window)
|
||||
final GithubShareDialog shareDialog =
|
||||
new GithubShareDialog(project, repoNamesRef.get(), userInfoRef.get().getMaxPrivateRepos() > userInfoRef.get().getPrivateRepos());
|
||||
//shareDialog.show();
|
||||
DialogManager.show(shareDialog);
|
||||
if (!shareDialog.isOK()) {
|
||||
return;
|
||||
}
|
||||
final boolean isPrivate = shareDialog.isPrivate();
|
||||
final String name = shareDialog.getRepositoryName();
|
||||
final String description = shareDialog.getDescription();
|
||||
|
||||
// finish the job in background
|
||||
final boolean finalExternalRemoteDetected = externalRemoteDetected;
|
||||
new Task.Backgroundable(project, "Sharing project on GitHub") {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
try {
|
||||
// create GitHub repo (network)
|
||||
LOG.info("Creating GitHub repository");
|
||||
indicator.setText("Creating GitHub repository");
|
||||
if (createGithubRepository(authRef.get(), name, description, isPrivate)) {
|
||||
LOG.info("Successfully created GitHub repository");
|
||||
}
|
||||
else {
|
||||
GithubNotifications.showError(project, "Creating GitHub Repository", "Failed to create new GitHub repository");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("Binding local project with GitHub");
|
||||
// creating empty git repo if git is not initialized
|
||||
if (!gitDetected) {
|
||||
if (!createEmptyGitRepository(project, root, indicator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GitRepositoryManager repositoryManager = ServiceManager.getService(project, GitRepositoryManager.class);
|
||||
final GitRepository repository = repositoryManager.getRepositoryForRoot(root);
|
||||
LOG.assertTrue(repository != null, "GitRepository is null for root " + root);
|
||||
|
||||
//git remote add origin git@github.com:login/name.git
|
||||
LOG.info("Adding GitHub as a remote host");
|
||||
indicator.setText("Adding GitHub as a remote host");
|
||||
final GitSimpleHandler addRemoteHandler = new GitSimpleHandler(project, root, GitCommand.REMOTE);
|
||||
addRemoteHandler.setSilent(true);
|
||||
final String remoteUrl = GithubApiUtil.getGitHost() + "/" + userInfoRef.get().getLogin() + "/" + name + ".git";
|
||||
final String remoteName = finalExternalRemoteDetected ? "github" : "origin";
|
||||
addRemoteHandler.addParameters("add", remoteName, remoteUrl);
|
||||
try {
|
||||
addRemoteHandler.run();
|
||||
repository.update();
|
||||
if (addRemoteHandler.getExitCode() != 0) {
|
||||
GithubNotifications
|
||||
.showError(project, "Failed to add GitHub repository as remote", "Failed to add GitHub repository as remote");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
GithubNotifications.showError(project, "Failed to add GitHub repository as remote", e.getMessage());
|
||||
LOG.info("Failed to add GitHub as remote: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// In this case we should create sample commit for binding project
|
||||
if (!performFirstCommitIfRequired(project, root, indicator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//git push origin master
|
||||
LOG.info("Pushing to github master");
|
||||
indicator.setText("Pushing to github master");
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
|
||||
GitLocalBranch currentBranch = repository.getCurrentBranch();
|
||||
if (currentBranch == null) {
|
||||
GithubNotifications.showError(project, "Can't finish GitHub sharing process", "Successfully created project '" +
|
||||
name +
|
||||
"' on GitHub, but initial push failed: " +
|
||||
"no current branch");
|
||||
return;
|
||||
}
|
||||
GitCommandResult result = git.push(repository, remoteName, remoteUrl, currentBranch.getName());
|
||||
if (result.success()) {
|
||||
GithubNotifications.showInfo(project, "Success", "Successfully created project '" + name + "' on GitHub");
|
||||
}
|
||||
else {
|
||||
GithubNotifications.showError(project, "Can't finish GitHub sharing process", "Successfully created project '" +
|
||||
name +
|
||||
"' on GitHub, but initial push failed:<br/>" +
|
||||
result.getErrorOutputAsHtmlString());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
exceptionRef.set(e);
|
||||
}
|
||||
}
|
||||
}.queue();
|
||||
if (!exceptionRef.isNull()) {
|
||||
GithubNotifications.showError(project, "Failed to create new GitHub repository", exceptionRef.get());
|
||||
return null;
|
||||
}
|
||||
return githubInfoRef.get();
|
||||
}
|
||||
|
||||
private static boolean createGithubRepository(@NotNull GithubAuthData auth,
|
||||
@NotNull String name,
|
||||
@NotNull String description,
|
||||
boolean aPrivate) throws IOException {
|
||||
@Nullable
|
||||
private static String createGithubRepository(@NotNull Project project,
|
||||
@NotNull GithubAuthData auth,
|
||||
@NotNull String name,
|
||||
@NotNull String description,
|
||||
boolean isPrivate) {
|
||||
String path = "/user/repos";
|
||||
String requestBody = prepareRequest(name, description, aPrivate);
|
||||
JsonElement result = GithubApiUtil.postRequest(auth, path, requestBody);
|
||||
String requestBody = prepareRequest(name, description, isPrivate);
|
||||
JsonElement result;
|
||||
try {
|
||||
result = GithubApiUtil.postRequest(auth, path, requestBody);
|
||||
}
|
||||
catch (IOException e) {
|
||||
GithubNotifications.showError(project, "Creating GitHub Repository", e);
|
||||
return null;
|
||||
}
|
||||
if (result == null) {
|
||||
return false;
|
||||
GithubNotifications.showError(project, "Creating GitHub Repository", "Failed to create new GitHub repository");
|
||||
return null;
|
||||
}
|
||||
if (!result.isJsonObject()) {
|
||||
LOG.error(String.format("Unexpected JSON result format: %s", result));
|
||||
return false;
|
||||
GithubNotifications.showError(project, "Creating GitHub Repository", "Failed to create new GitHub repository");
|
||||
return null;
|
||||
}
|
||||
return result.getAsJsonObject().has("url");
|
||||
if (!result.getAsJsonObject().has("html_url")) {
|
||||
GithubNotifications.showError(project, "Creating GitHub Repository", "Failed to create new GitHub repository");
|
||||
return null;
|
||||
}
|
||||
return result.getAsJsonObject().get("html_url").getAsString();
|
||||
}
|
||||
|
||||
private static String prepareRequest(String name, String description, boolean isPrivate) {
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("name", name);
|
||||
json.addProperty("description", description);
|
||||
json.addProperty("public", Boolean.toString(!isPrivate));
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
private static boolean createEmptyGitRepository(@NotNull Project project,
|
||||
@NotNull VirtualFile root,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
LOG.info("No git detected, creating empty git repo");
|
||||
indicator.setText("Creating empty git repo");
|
||||
final GitLineHandler h = new GitLineHandler(project, root, GitCommand.INIT);
|
||||
GitHandlerUtil.runInCurrentThread(h, indicator, true, GitBundle.getString("initializing.title"));
|
||||
if (!h.errors().isEmpty()) {
|
||||
@@ -295,49 +289,45 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String prepareRequest(String name, String description, boolean isPrivate) {
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("name", name);
|
||||
json.addProperty("description", description);
|
||||
json.addProperty("public", Boolean.toString(!isPrivate));
|
||||
return json.toString();
|
||||
|
||||
private static boolean addGithubRemote(@NotNull Project project,
|
||||
@NotNull VirtualFile root,
|
||||
@NotNull String remoteName,
|
||||
@NotNull String remoteUrl,
|
||||
@NotNull GitRepository repository) {
|
||||
final GitSimpleHandler addRemoteHandler = new GitSimpleHandler(project, root, GitCommand.REMOTE);
|
||||
addRemoteHandler.setSilent(true);
|
||||
addRemoteHandler.addParameters("add", remoteName, remoteUrl);
|
||||
try {
|
||||
addRemoteHandler.run();
|
||||
repository.update();
|
||||
if (addRemoteHandler.getExitCode() != 0) {
|
||||
GithubNotifications.showError(project, "Failed to add GitHub repository as remote", "Failed to add GitHub repository as remote");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
GithubNotifications.showError(project, "Failed to add GitHub repository as remote", e.getMessage());
|
||||
LOG.info("Failed to add GitHub as remote: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if there is no commits
|
||||
// ask for files to add
|
||||
// commit
|
||||
private static boolean performFirstCommitIfRequired(@NotNull Project project,
|
||||
@NotNull final VirtualFile root,
|
||||
@NotNull VirtualFile root,
|
||||
@NotNull GitRepository repository,
|
||||
@NotNull ProgressIndicator indicator) {
|
||||
// get repository
|
||||
final GitVcs gitVcs = GitVcs.getInstance(project);
|
||||
if (gitVcs == null) {
|
||||
GithubNotifications.showError(project, "Failed to perform initial commit", "Cannot find git initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
GitRepositoryManager repositoryManager = ServiceManager.getService(project, GitRepositoryManager.class);
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
if (repositoryManager == null || git == null) {
|
||||
return false;
|
||||
}
|
||||
GitRepository repository = repositoryManager.getRepositoryForRoot(root);
|
||||
if (repository == null) {
|
||||
GithubNotifications.showError(project, "Failed to perform initial commit", "Cannot find git repository for root " + root);
|
||||
return false;
|
||||
}
|
||||
// check if there is no commits
|
||||
if (!repository.isFresh()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// commit
|
||||
LOG.info("Trying to commit");
|
||||
indicator.setText("Trying to commit");
|
||||
try {
|
||||
LOG.info("Adding files for commit");
|
||||
indicator.setText("Adding files to git");
|
||||
|
||||
// ask for files to add
|
||||
List<VirtualFile> untrackedFiles = new ArrayList<VirtualFile>(repository.getUntrackedFilesHolder().retrieveUntrackedFiles());
|
||||
final GithubUntrackedFilesDialog dialog = new GithubUntrackedFilesDialog(project, untrackedFiles);
|
||||
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
|
||||
@@ -353,6 +343,7 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
}
|
||||
GitFileUtils.addFiles(project, root, files2add);
|
||||
|
||||
// commit
|
||||
LOG.info("Performing commit");
|
||||
indicator.setText("Performing commit");
|
||||
GitSimpleHandler handler = new GitSimpleHandler(project, root, GitCommand.COMMIT);
|
||||
@@ -365,14 +356,68 @@ public class GithubShareAction extends DumbAwareAction {
|
||||
GithubNotifications.showError(project, "Failed to commit file during post activities", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
LOG.info("Successfully created initial commit");
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class GithubUntrackedFilesDialog extends SelectFilesDialog {
|
||||
private static boolean pushCurrentBranch(@NotNull Project project,
|
||||
@NotNull GitRepository repository,
|
||||
@NotNull String remoteName,
|
||||
@NotNull String remoteUrl,
|
||||
@NotNull String name) {
|
||||
Git git = ServiceManager.getService(Git.class);
|
||||
|
||||
GitLocalBranch currentBranch = repository.getCurrentBranch();
|
||||
if (currentBranch == null) {
|
||||
GithubNotifications.showError(project, "Can't finish GitHub sharing process", "Successfully created project '" +
|
||||
name +
|
||||
"' on GitHub, but initial push failed: " +
|
||||
"no current branch");
|
||||
return false;
|
||||
}
|
||||
GitCommandResult result = git.push(repository, remoteName, remoteUrl, currentBranch.getName());
|
||||
if (!result.success()) {
|
||||
GithubNotifications.showError(project, "Can't finish GitHub sharing process", "Successfully created project '" +
|
||||
name +
|
||||
"' on GitHub, but initial push failed:<br/>" +
|
||||
result.getErrorOutputAsHtmlString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class GithubUntrackedFilesDialog extends SelectFilesDialog {
|
||||
|
||||
public GithubUntrackedFilesDialog(@NotNull Project project, @NotNull List<VirtualFile> untrackedFiles) {
|
||||
super(project, untrackedFiles, "Add files to Git", VcsShowConfirmationOption.STATIC_SHOW_CONFIRMATION, true, false, false);
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
private static class GithubInfo {
|
||||
@NotNull private final GithubUser myUser;
|
||||
@NotNull private final GithubAuthData myAuthData;
|
||||
@NotNull private final HashSet<String> myRepositoryNames;
|
||||
|
||||
GithubInfo(@NotNull GithubAuthData auth, @NotNull GithubUser user, @NotNull HashSet<String> repositoryNames) {
|
||||
myUser = user;
|
||||
myAuthData = auth;
|
||||
myRepositoryNames = repositoryNames;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GithubUser getUser() {
|
||||
return myUser;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GithubAuthData getAuthData() {
|
||||
return myAuthData;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public HashSet<String> getRepositoryNames() {
|
||||
return myRepositoryNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,16 +35,12 @@ class GithubUser {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
String getLogin() {
|
||||
public String getLogin() {
|
||||
return myLogin;
|
||||
}
|
||||
|
||||
int getMaxPrivateRepos() {
|
||||
return myMaxPrivateRepos;
|
||||
}
|
||||
|
||||
int getPrivateRepos() {
|
||||
return myPrivateRepos;
|
||||
public boolean canCreatePrivateRepo() {
|
||||
return myMaxPrivateRepos > myPrivateRepos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user