diff options
author | Thomas Wolf | 2020-10-02 23:11:50 +0000 |
---|---|---|
committer | Thomas Wolf | 2020-10-04 14:31:36 +0000 |
commit | 23dd27bc5a66f47054903fdb5d0e9b06330227af (patch) | |
tree | 95b1e2716106274cf2bd8c20ff383f8cd4890248 | |
parent | 3f95acdae6802f13977954230fb62b97eadc72d9 (diff) | |
download | egit-github-23dd27bc5a66f47054903fdb5d0e9b06330227af.tar.gz egit-github-23dd27bc5a66f47054903fdb5d0e9b06330227af.tar.xz egit-github-23dd27bc5a66f47054903fdb5d0e9b06330227af.zip |
Support token-based authentication
Change the repository wizard pages such that the user can enter a
token instead of username/password. The token is stored in the normal
password property; we add an extra property that records that it
is a token. Then use token-based authentication instead of basic
authentication for all http/https requests.
In files touched also modernize the code a little. Minimum version of
Mylyn supported in 3.20, so several internal accesses can be replaced
by proper API.
Bug: 567557
Change-Id: I566439e44a9000f313e2801890b1e3b5c4c1903f
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
14 files changed, 442 insertions, 335 deletions
diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java index 2dbc55de..dfb44606 100644 --- a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java +++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/GitHub.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 Red Hat and others. + * Copyright (c) 2011, 2020 Red Hat and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -57,6 +57,14 @@ public class GitHub { public static final String REPOSITORY_SEGMENTS = "/user/repository"; //$NON-NLS-1$ /** + * Key for a repository property storing a stringified boolean ("true" or + * "false") telling whether to use token authentication for a Mylyn task + * repository. + */ + public static final String PROPERTY_USE_TOKEN = GitHub.class.getPackage() + .getName() + ".REPO_USE_TOKEN"; //$NON-NLS-1$ + + /** * Configure client with standard configuration * * @param client @@ -77,9 +85,15 @@ public class GitHub { TaskRepository repository) { AuthenticationCredentials credentials = repository .getCredentials(AuthenticationType.REPOSITORY); - if (credentials != null) - client.setCredentials(credentials.getUserName(), - credentials.getPassword()); + if (credentials != null) { + if (Boolean + .parseBoolean(repository.getProperty(PROPERTY_USE_TOKEN))) { + client.setOAuth2Token(credentials.getPassword()); + } else { + client.setCredentials(credentials.getUserName(), + credentials.getPassword()); + } + } return client; } diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java index 9f5c9824..c665ecb6 100644 --- a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java +++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/gist/GistTaskDataHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -168,35 +168,40 @@ public class GistTaskDataHandler extends GitHubTaskDataHandler { private String generateSummary(int files, long size, String description) { StringBuilder summaryText = new StringBuilder(); - if (description != null && description.length() > 0) { - description = description.trim(); - int firstLine = description.indexOf('\n'); - if (firstLine != -1) - description = description.substring(0, firstLine).trim(); - if (description.length() > SUMMARY_LENGTH) { + if (description != null && !description.isEmpty()) { + String desc = description.trim(); + int firstLine = desc.indexOf('\n'); + if (firstLine != -1) { + desc = desc.substring(0, firstLine).trim(); + } + if (desc.length() > SUMMARY_LENGTH) { // Break on last whitespace if maximum length is in the middle // of a word - if (!Character.isWhitespace(description.charAt(SUMMARY_LENGTH)) - && !Character.isWhitespace(description + if (!Character.isWhitespace(desc.charAt(SUMMARY_LENGTH)) + && !Character.isWhitespace(desc .charAt(SUMMARY_LENGTH - 1))) { - int lastWhitespace = description.lastIndexOf(' '); - if (lastWhitespace > 0) - description = description.substring(0, lastWhitespace); - else - description = description.substring(0, SUMMARY_LENGTH); - } else - description = description.substring(0, SUMMARY_LENGTH); - description = description.trim(); + int lastWhitespace = desc.lastIndexOf(' '); + if (lastWhitespace > 0) { + desc = desc.substring(0, lastWhitespace); + } else { + desc = desc.substring(0, SUMMARY_LENGTH); + } + } else { + desc = desc.substring(0, SUMMARY_LENGTH); + } + desc = desc.trim(); } - if (description.length() > 0) + if (!desc.isEmpty()) { summaryText.append(description).append(' '); + } } - if (files != 1) + if (files != 1) { summaryText.append(MessageFormat.format( Messages.GistTaskDataHandler_FilesMultiple, Integer.valueOf(files))); - else + } else { summaryText.append(Messages.GistTaskDataHandler_FilesSingle); + } summaryText.append(',').append(' ').append(formatSize(size)); return summaryText.toString(); } @@ -234,8 +239,13 @@ public class GistTaskDataHandler extends GitHubTaskDataHandler { AuthenticationCredentials credentials = repository .getCredentials(AuthenticationType.REPOSITORY); if (credentials != null) { - client.setCredentials(credentials.getUserName(), - credentials.getPassword()); + if (Boolean.parseBoolean( + repository.getProperty(GitHub.PROPERTY_USE_TOKEN))) { + client.setOAuth2Token(credentials.getPassword()); + } else { + client.setCredentials(credentials.getUserName(), + credentials.getPassword()); + } gist.setOwner(new User().setLogin(credentials.getUserName())); } diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java index e93e3ced..b7e7f1bb 100644 --- a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java +++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/issue/IssueConnector.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 Red Hat and others. + * Copyright (c) 2011, 2020 Red Hat and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -48,7 +48,6 @@ import org.eclipse.mylyn.commons.net.Policy; import org.eclipse.mylyn.internal.github.core.GitHub; import org.eclipse.mylyn.internal.github.core.QueryUtils; import org.eclipse.mylyn.internal.github.core.RepositoryConnector; -import org.eclipse.mylyn.internal.tasks.core.IRepositoryConstants; import org.eclipse.mylyn.tasks.core.IRepositoryQuery; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; @@ -59,7 +58,6 @@ import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession; /** * GitHub issue repository connector. */ -@SuppressWarnings("restriction") public class IssueConnector extends RepositoryConnector { /** @@ -78,25 +76,35 @@ public class IssueConnector extends RepositoryConnector { } /** - * Create issue task repository + * Creates an issue task repository. * * @param repo + * internal model to create the task repository from * @param username + * for authentication * @param password - * @return task repository + * for authentication + * @param isToken + * whether the password is a token + * @return the {@link TaskRepository} */ public static TaskRepository createTaskRepository(Repository repo, - String username, String password) { + String username, String password, boolean isToken) { String url = GitHub.createGitHubUrl(repo.getOwner().getLogin(), repo.getName()); TaskRepository repository = new TaskRepository(KIND, url); - repository.setProperty(IRepositoryConstants.PROPERTY_LABEL, - getRepositoryLabel(repo)); - if (username != null && password != null) + repository.setRepositoryLabel(getRepositoryLabel(repo)); + String loginName = username; + if (loginName == null && isToken) { + loginName = ""; //$NON-NLS-1$ + } + if (loginName != null && password != null) { repository.setCredentials(AuthenticationType.REPOSITORY, - new AuthenticationCredentials(username, password), true); - repository.setProperty(IRepositoryConstants.PROPERTY_CATEGORY, - TaskRepository.CATEGORY_BUGS); + new AuthenticationCredentials(loginName, password), true); + } + repository.setCategory(TaskRepository.CATEGORY_BUGS); + repository.setProperty(GitHub.PROPERTY_USE_TOKEN, + Boolean.toString(isToken)); return repository; } @@ -405,13 +413,13 @@ public class IssueConnector extends RepositoryConnector { @Override public void updateRepositoryConfiguration(TaskRepository taskRepository, IProgressMonitor monitor) throws CoreException { - monitor = Policy.monitorFor(monitor); - monitor.beginTask("", 2); //$NON-NLS-1$ - monitor.setTaskName(Messages.IssueConnector_TaskUpdatingLabels); + IProgressMonitor m = Policy.monitorFor(monitor); + m.beginTask("", 2); //$NON-NLS-1$ + m.setTaskName(Messages.IssueConnector_TaskUpdatingLabels); refreshLabels(taskRepository); - monitor.worked(1); - monitor.setTaskName(Messages.IssueConnector_TaskUpdatingMilestones); + m.worked(1); + m.setTaskName(Messages.IssueConnector_TaskUpdatingMilestones); refreshMilestones(taskRepository); - monitor.done(); + m.done(); } } diff --git a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/pr/PullRequestConnector.java b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/pr/PullRequestConnector.java index 7aecec05..27254cc0 100644 --- a/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/pr/PullRequestConnector.java +++ b/org.eclipse.mylyn.github.core/src/org/eclipse/mylyn/internal/github/core/pr/PullRequestConnector.java @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -35,7 +35,6 @@ import org.eclipse.mylyn.internal.github.core.GitHub; import org.eclipse.mylyn.internal.github.core.QueryUtils; import org.eclipse.mylyn.internal.github.core.RepositoryConnector; import org.eclipse.mylyn.internal.github.core.issue.IssueConnector; -import org.eclipse.mylyn.internal.tasks.core.IRepositoryConstants; import org.eclipse.mylyn.tasks.core.IRepositoryQuery; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; @@ -46,7 +45,6 @@ import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession; /** * GitHub pull request connector. */ -@SuppressWarnings("restriction") public class PullRequestConnector extends RepositoryConnector { /** @@ -71,25 +69,34 @@ public class PullRequestConnector extends RepositoryConnector { } /** - * Create pull request task repository + * Creates a pull request task repository. * * @param repo + * internal model to create the task repository from * @param username + * for authentication * @param password - * @return task repository + * for authentication + * @param isToken + * whether the password is a token + * @return the {@link TaskRepository} */ public static TaskRepository createTaskRepository(Repository repo, - String username, String password) { + String username, String password, boolean isToken) { String url = PullRequestConnector.appendPulls(GitHub.createGitHubUrl( repo.getOwner().getLogin(), repo.getName())); TaskRepository repository = new TaskRepository(KIND, url); - repository.setProperty(IRepositoryConstants.PROPERTY_LABEL, - getRepositoryLabel(repo)); - if (username != null && password != null) + repository.setRepositoryLabel(getRepositoryLabel(repo)); + String loginName = username; + if (loginName == null && isToken) { + loginName = ""; //$NON-NLS-1$ + } + if (loginName != null && password != null) repository.setCredentials(AuthenticationType.REPOSITORY, - new AuthenticationCredentials(username, password), true); - repository.setProperty(IRepositoryConstants.PROPERTY_CATEGORY, - TaskRepository.CATEGORY_REVIEW); + new AuthenticationCredentials(loginName, password), true); + repository.setCategory(TaskRepository.CATEGORY_REVIEW); + repository.setProperty(GitHub.PROPERTY_USE_TOKEN, + Boolean.toString(isToken)); return repository; } @@ -110,9 +117,10 @@ public class PullRequestConnector extends RepositoryConnector { * @return stripped string */ public static String stripPulls(String repoUrl) { - if (repoUrl.endsWith(IGitHubConstants.SEGMENT_PULLS)) - repoUrl = repoUrl.substring(0, repoUrl.length() + if (repoUrl.endsWith(IGitHubConstants.SEGMENT_PULLS)) { + return repoUrl.substring(0, repoUrl.length() - IGitHubConstants.SEGMENT_PULLS.length()); + } return repoUrl; } diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/CredentialsWizardPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/CredentialsWizardPage.java index 8167c579..3e09c2fb 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/CredentialsWizardPage.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/CredentialsWizardPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -16,8 +16,9 @@ import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; @@ -33,6 +34,8 @@ public class CredentialsWizardPage extends WizardPage { private Text passwordText; + private Button useToken; + /** * Create credentials wizard page */ @@ -53,26 +56,42 @@ public class CredentialsWizardPage extends WizardPage { new Label(displayArea, SWT.NONE).setText(Messages.CredentialsWizardPage_LabelUser); userText = new Text(displayArea, SWT.BORDER | SWT.SINGLE); - userText.addModifyListener(new ModifyListener() { - - @Override - public void modifyText(ModifyEvent e) { - validatePage(); - } - }); + userText.addModifyListener(e -> validatePage()); GridDataFactory.fillDefaults().grab(true, false).applyTo(userText); - new Label(displayArea, SWT.NONE).setText(Messages.CredentialsWizardPage_LabelPassword); + Label passwordLabel = new Label(displayArea, SWT.NONE); + passwordLabel.setText(Messages.CredentialsWizardPage_LabelPassword); passwordText = new Text(displayArea, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); - passwordText.addModifyListener(new ModifyListener() { + passwordText.addModifyListener(e -> validatePage()); + GridDataFactory.fillDefaults().grab(true, false).applyTo(passwordText); + useToken = new Button(displayArea, SWT.CHECK); + useToken.setText(Messages.HttpRepositorySettingsPage_LabelUseToken); + useToken.setToolTipText( + Messages.HttpRepositorySettingsPage_TooltipUseToken); + useToken.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean isChecked = useToken.getSelection(); + // Don't disable the userText; if the user want to create a + // Gists Mylyn repository, we need a user name even with token + // auth. + if (isChecked) { + passwordLabel.setText( + Messages.HttpRepositorySettingsPage_LabelToken); + } else { + passwordLabel.setText( + Messages.CredentialsWizardPage_LabelPassword); + } + passwordLabel.requestLayout(); + } @Override - public void modifyText(ModifyEvent e) { - validatePage(); + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); } }); - GridDataFactory.fillDefaults().grab(true, false).applyTo(passwordText); + setControl(displayArea); setPageComplete(false); @@ -80,10 +99,14 @@ public class CredentialsWizardPage extends WizardPage { private void validatePage() { String message = null; - if (userText.getText().trim().isEmpty()) { + if (!useToken.getSelection() && userText.getText().trim().isEmpty()) { message = Messages.CredentialsWizardPage_ErrorUser; } else if (passwordText.getText().trim().isEmpty()) { - message = Messages.CredentialsWizardPage_ErrorPassword; + if (useToken.getSelection()) { + message = Messages.HttpRepositorySettingsPage_EnterToken; + } else { + message = Messages.CredentialsWizardPage_ErrorPassword; + } } setErrorMessage(message); @@ -92,21 +115,29 @@ public class CredentialsWizardPage extends WizardPage { } /** - * Get user name + * Retrieves the user name. * - * @return user name + * @return the user name */ public String getUserName() { - return this.userText.getText(); + return userText.getText(); } /** - * Get password + * Retrieves the password. * - * @return password + * @return the password */ public String getPassword() { - return this.passwordText.getText(); + return passwordText.getText(); } + /** + * Tells whether the {@link #getPassword() password} is a token. + * + * @return {@code true} if the password is a token; {@code false} otherwise + */ + public boolean isToken() { + return useToken.getSelection(); + } } diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/HttpRepositorySettingsPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/HttpRepositorySettingsPage.java index 4ada1930..1525a60c 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/HttpRepositorySettingsPage.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/HttpRepositorySettingsPage.java @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -14,11 +14,19 @@ package org.eclipse.mylyn.internal.github.ui; import java.io.IOException; import java.net.URL; +import java.util.function.Function; +import org.eclipse.egit.github.core.RepositoryId; import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.mylyn.internal.github.core.GitHub; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Button; /** * Base HTTP-based task repository settings page @@ -26,6 +34,14 @@ import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage; public abstract class HttpRepositorySettingsPage extends AbstractRepositorySettingsPage { + private boolean syncLabel = true; + + private boolean editingUrl = false; + + private boolean needsUser = true; + + private Button useToken; + /** * Create repository settings page * @@ -47,22 +63,179 @@ public abstract class HttpRepositorySettingsPage extends @SuppressWarnings("unused") @Override protected boolean isValidUrl(final String url) { - if (url.startsWith("http://") || url.startsWith("https://")) //$NON-NLS-1$ //$NON-NLS-2$ + if (url.startsWith("http://") || url.startsWith("https://")) { //$NON-NLS-1$ //$NON-NLS-2$ try { new URL(url); return GitHub.getRepository(url) != null; } catch (IOException e) { return false; } + } return false; } - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#canValidate() - */ @Override public boolean canValidate() { return isPageComplete() && (getMessage() == null || getMessageType() != IMessageProvider.ERROR); } + + private void syncRepositoryLabel( + Function<RepositoryId, String> labelProvider) { + if (syncLabel) { + String url = serverUrlCombo.getText(); + RepositoryId repo = GitHub.getRepository(url); + if (repo != null) { + repositoryLabelEditor.setStringValue(labelProvider.apply(repo)); + } + } + } + + /** + * Set up the {@link #serverUrlCombo} to have the initial Github URL as + * content and to sync with the {@link #repositoryLabelEditor}. + * + * @param labelProvider + * to provide a repository label + */ + protected void setInitialUrl(Function<RepositoryId, String> labelProvider) { + String fullUrlText = GitHub.HTTP_GITHUB_COM + + GitHub.REPOSITORY_SEGMENTS; + serverUrlCombo.setText(fullUrlText); + serverUrlCombo.setFocus(); + // select the user/project part of the URL so that the user can just + // start typing to replace the text. + serverUrlCombo.setSelection(new Point( + GitHub.HTTP_GITHUB_COM.length() + 1, fullUrlText.length())); + + syncRepositoryLabel(labelProvider); + + serverUrlCombo.addModifyListener(e -> { + editingUrl = true; + try { + syncRepositoryLabel(labelProvider); + } finally { + editingUrl = false; + } + }); + + repositoryLabelEditor.getTextControl(compositeContainer) + .addModifyListener(e -> { + if (!editingUrl) { + syncLabel = false; + } + }); + } + + /** + * Inserts a checkbox into the page where the user can specify that token + * authentication shall be used for the task repository. + * + * @param userOptional + * whether or not a user name is optional + */ + protected void addTokenCheckbox(boolean userOptional) { + needsUser = !userOptional; + useToken = new Button(compositeContainer, SWT.CHECK); + useToken.setText(Messages.HttpRepositorySettingsPage_LabelUseToken); + useToken.setToolTipText( + Messages.HttpRepositorySettingsPage_TooltipUseToken); + useToken.moveBelow(savePasswordButton); + GridDataFactory.defaultsFor(useToken).span(3, 1).applyTo(useToken); + String savePasswordText = savePasswordButton.getText(); + boolean[] allowAnon = { isAnonymousAccess() }; + useToken.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + boolean isChecked = useToken.getSelection(); + if (isChecked) { + repositoryPasswordEditor.setLabelText( + Messages.HttpRepositorySettingsPage_LabelToken); + savePasswordButton.setText( + Messages.HttpRepositorySettingsPage_LabelSaveToken); + if (anonymousButton != null) { + allowAnon[0] = isAnonymousAccess(); + setAnonymous(false); + anonymousButton.setEnabled(false); + } + } else { + repositoryPasswordEditor.setLabelText(LABEL_PASSWORD); + savePasswordButton.setText(savePasswordText); + if (anonymousButton != null) { + anonymousButton.setEnabled(true); + setAnonymous(allowAnon[0]); + } + } + if (userOptional) { + repositoryUserNameEditor.getTextControl(compositeContainer) + .setEnabled(!isChecked); + repositoryUserNameEditor.setEmptyStringAllowed(isChecked); + } + repositoryPasswordEditor.getLabelControl(compositeContainer) + .requestLayout(); + // Trigger page validation if needed + if (userOptional && getWizard() != null) { + getWizard().getContainer().updateButtons(); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + }); + TaskRepository taskRepository = getRepository(); + if (taskRepository != null) { + useToken.setSelection(Boolean.parseBoolean( + taskRepository.getProperty(GitHub.PROPERTY_USE_TOKEN))); + } + } + + /** + * Tells whether the task repository uses token authentication. + * + * @return {@code true} if token authentication shall be used; {@code false} + * otherwise + */ + protected boolean useTokenAuth() { + return useToken != null && useToken.getSelection(); + } + + @Override + protected boolean isMissingCredentials() { + if (!needsUser && useTokenAuth()) { + return repositoryPasswordEditor.getStringValue().trim().isEmpty(); + } else { + return super.isMissingCredentials(); + } + } + + @SuppressWarnings("restriction") + @Override + public void setMessage(String newMessage, int newType) { + // This is a bit hacky since it relies on an internal message and the + // way it is used in the super class. But it beats re-implementing + // isPageComplete(). + if (useTokenAuth() + && org.eclipse.mylyn.internal.tasks.ui.wizards.Messages.AbstractRepositorySettingsPage_Enter_a_user_id_Message0 + .equals(newMessage)) { + if (needsUser) { + super.setMessage( + Messages.HttpRepositorySettingsPage_EnterUserAndToken, + newType); + } else { + super.setMessage(Messages.HttpRepositorySettingsPage_EnterToken, + newType); + } + } else { + super.setMessage(newMessage, newType); + } + } + + @Override + public void applyTo(TaskRepository taskRepository) { + taskRepository.setProperty(GitHub.PROPERTY_USE_TOKEN, + Boolean.toString(useToken != null && useToken.getSelection())); + super.applyTo(taskRepository); + } } diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/Messages.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/Messages.java index 0963f9a5..8b915d6d 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/Messages.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -37,6 +37,24 @@ public class Messages extends NLS { public static String CredentialsWizardPage_LabelUser; /** */ + public static String HttpRepositorySettingsPage_EnterToken; + + /** */ + public static String HttpRepositorySettingsPage_EnterUserAndToken; + + /** */ + public static String HttpRepositorySettingsPage_LabelSaveToken; + + /** */ + public static String HttpRepositorySettingsPage_LabelToken; + + /** */ + public static String HttpRepositorySettingsPage_LabelUseToken; + + /** */ + public static String HttpRepositorySettingsPage_TooltipUseToken; + + /** */ public static String CredentialsWizardPage_Title; /** */ diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/RepositorySelectionWizardPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/RepositorySelectionWizardPage.java index bea5b4ad..0a31e909 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/RepositorySelectionWizardPage.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/RepositorySelectionWizardPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -207,6 +207,8 @@ public class RepositorySelectionWizardPage extends WizardPage { private String user; private String password; + private boolean isToken; + /** * Create repository selection wizard page */ @@ -226,7 +228,17 @@ public class RepositorySelectionWizardPage extends WizardPage { this.password = password; } - /** @return true to create giste repository, false otherwise */ + /** + * Sets whether the {@link #setPassword(String) password} is a token. + * + * @param isToken + * whether the password is a token + */ + public void setIsToken(boolean isToken) { + this.isToken = isToken; + } + + /** @return true to create gists repository, false otherwise */ public boolean createGistRepository() { return this.addGistRepoButton.getSelection() && this.addGistRepoButton.isVisible(); @@ -261,7 +273,7 @@ public class RepositorySelectionWizardPage extends WizardPage { viewer.setComparator(new ViewerComparator() { @Override - public int compare(Viewer viewer, Object e1, Object e2) { + public int compare(Viewer v, Object e1, Object e2) { if (e1 instanceof OrganizationAdapter) if (e2 instanceof OrganizationAdapter) return ((OrganizationAdapter) e1) @@ -277,7 +289,7 @@ public class RepositorySelectionWizardPage extends WizardPage { ((RepositoryAdapter) e2).getLabel(e2)); else if (e2 instanceof OrganizationAdapter) return -1; - return super.compare(viewer, e1, e2); + return super.compare(v, e1, e2); } }); @@ -393,10 +405,13 @@ public class RepositorySelectionWizardPage extends WizardPage { @Override public void setVisible(boolean visible) { super.setVisible(visible); - if (!visible) + if (!visible) { return; - addGistRepoButton.setVisible(TasksUi.getRepositoryManager() - .getRepositories(GistConnector.KIND).isEmpty()); + } + // For gists a user name is needed. + addGistRepoButton.setVisible(user != null && !user.isEmpty() + && TasksUi.getRepositoryManager() + .getRepositories(GistConnector.KIND).isEmpty()); try { getContainer().run(true, true, new IRunnableWithProgress() { @@ -405,7 +420,11 @@ public class RepositorySelectionWizardPage extends WizardPage { throws InvocationTargetException, InterruptedException { GitHubClient client = GitHub .configureClient(new GitHubClient()); - client.setCredentials(user, password); + if (isToken) { + client.setOAuth2Token(password); + } else { + client.setCredentials(user, password); + } RepositoryService service = new RepositoryService(client); OrganizationService orgs = new OrganizationService(client); repoCount = 0; diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/TaskRepositoryImportWizard.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/TaskRepositoryImportWizard.java index 40616f43..37554529 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/TaskRepositoryImportWizard.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/TaskRepositoryImportWizard.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -18,12 +18,12 @@ import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.Wizard; import org.eclipse.mylyn.commons.net.AuthenticationCredentials; import org.eclipse.mylyn.commons.net.AuthenticationType; +import org.eclipse.mylyn.internal.github.core.GitHub; import org.eclipse.mylyn.internal.github.core.gist.GistConnector; import org.eclipse.mylyn.internal.github.core.issue.IssueConnector; import org.eclipse.mylyn.internal.github.core.pr.PullRequestConnector; import org.eclipse.mylyn.internal.github.ui.gist.GistRepositorySettingsPage; import org.eclipse.mylyn.internal.github.ui.gist.Messages; -import org.eclipse.mylyn.internal.tasks.core.IRepositoryConstants; import org.eclipse.mylyn.tasks.core.IRepositoryManager; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.ui.TasksUi; @@ -74,6 +74,7 @@ public class TaskRepositoryImportWizard extends Wizard implements IImportWizard if (next == reposPage) { reposPage.setUser(credentialsPage.getUserName()); reposPage.setPassword(credentialsPage.getPassword()); + reposPage.setIsToken(credentialsPage.isToken()); } return next; } @@ -94,24 +95,26 @@ public class TaskRepositoryImportWizard extends Wizard implements IImportWizard public boolean performFinish() { String user = credentialsPage.getUserName(); String password = credentialsPage.getPassword(); + boolean isToken = credentialsPage.isToken(); final IRepositoryManager manager = TasksUi.getRepositoryManager(); for (Repository repo : reposPage.getRepositories()) { manager.addRepository(IssueConnector.createTaskRepository(repo, - user, password)); + user, password, isToken)); manager.addRepository(PullRequestConnector.createTaskRepository( - repo, user, password)); + repo, user, password, isToken)); } if (reposPage.createGistRepository()) { AuthenticationCredentials credentials = new AuthenticationCredentials( user, password); TaskRepository repository = new TaskRepository(GistConnector.KIND, GistRepositorySettingsPage.URL); - repository.setProperty(IRepositoryConstants.PROPERTY_LABEL, + repository.setRepositoryLabel( Messages.GistRepositorySettingsPage_RepositoryLabelDefault); repository.setCredentials(AuthenticationType.REPOSITORY, credentials, true); - repository.setProperty(IRepositoryConstants.PROPERTY_CATEGORY, - TaskRepository.CATEGORY_REVIEW); + repository.setCategory(TaskRepository.CATEGORY_REVIEW); + repository.setProperty(GitHub.PROPERTY_USE_TOKEN, + Boolean.toString(isToken)); manager.addRepository(repository); } return true; diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/gist/GistRepositorySettingsPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/gist/GistRepositorySettingsPage.java index c8eb95ee..91d9f525 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/gist/GistRepositorySettingsPage.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/gist/GistRepositorySettingsPage.java @@ -1,5 +1,6 @@ /******************************************************************************* - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others + * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -13,7 +14,6 @@ package org.eclipse.mylyn.internal.github.ui.gist; import java.io.IOException; -import java.net.URL; import java.text.MessageFormat; import org.eclipse.core.runtime.CoreException; @@ -22,27 +22,20 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.egit.github.core.client.GitHubClient; import org.eclipse.egit.github.core.service.GistService; -import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.mylyn.commons.net.AuthenticationType; import org.eclipse.mylyn.internal.github.core.GitHubException; import org.eclipse.mylyn.internal.github.core.gist.GistConnector; import org.eclipse.mylyn.internal.github.ui.GitHubUi; -import org.eclipse.mylyn.internal.tasks.core.IRepositoryConstants; +import org.eclipse.mylyn.internal.github.ui.HttpRepositorySettingsPage; import org.eclipse.mylyn.tasks.core.TaskRepository; -import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage; import org.eclipse.swt.widgets.Composite; /** - * Gist repository settings page class. - * - * @author Kevin Sawicki (kevin@github.com) + * Gist repository settings. */ -@SuppressWarnings("restriction") -public class GistRepositorySettingsPage extends AbstractRepositorySettingsPage { +public class GistRepositorySettingsPage extends HttpRepositorySettingsPage { - /** - * URL - */ + /** URL for gists. */ public static final String URL = "https://gist.github.com"; //$NON-NLS-1$ /** @@ -54,17 +47,11 @@ public class GistRepositorySettingsPage extends AbstractRepositorySettingsPage { setNeedsAnonymousLogin(false); } - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#getConnectorKind() - */ @Override public String getConnectorKind() { return GistConnector.KIND; } - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#createAdditionalControls(org.eclipse.swt.widgets.Composite) - */ @Override protected void createAdditionalControls(Composite parent) { if (repository == null) { @@ -72,30 +59,12 @@ public class GistRepositorySettingsPage extends AbstractRepositorySettingsPage { repositoryLabelEditor .setStringValue(Messages.GistRepositorySettingsPage_RepositoryLabelDefault); } + // For gists we still need a user name. + addTokenCheckbox(false); } - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#isValidUrl(java.lang.String) - */ - @SuppressWarnings("unused") - @Override - protected boolean isValidUrl(String url) { - if (url.startsWith("http://") || url.startsWith("https://")) //$NON-NLS-1$ //$NON-NLS-2$ - try { - new URL(url); - return true; - } catch (IOException e) { - return false; - } - return false; - - } - - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#getValidator(org.eclipse.mylyn.tasks.core.TaskRepository) - */ @Override - protected Validator getValidator(final TaskRepository repository) { + protected Validator getValidator(final TaskRepository taskRepository) { return new Validator() { @Override @@ -106,9 +75,9 @@ public class GistRepositorySettingsPage extends AbstractRepositorySettingsPage { monitor.subTask(Messages.GistRepositorySettingsPage_TaskContacting); try { GitHubClient client = GistConnector - .createClient(repository); + .createClient(taskRepository); GistService service = new GistService(client); - String user = repository.getCredentials( + String user = taskRepository.getCredentials( AuthenticationType.REPOSITORY).getUserName(); monitor.worked(20); service.getGists(user); @@ -131,23 +100,10 @@ public class GistRepositorySettingsPage extends AbstractRepositorySettingsPage { }; } - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#applyTo(org.eclipse.mylyn.tasks.core.TaskRepository) - */ - @Override - public void applyTo(TaskRepository repository) { - repository.setProperty(IRepositoryConstants.PROPERTY_CATEGORY, - TaskRepository.CATEGORY_REVIEW); - super.applyTo(repository); - } - - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#canValidate() - */ @Override - public boolean canValidate() { - return isPageComplete() - && (getMessage() == null || getMessageType() != IMessageProvider.ERROR); + public void applyTo(TaskRepository taskRepository) { + taskRepository.setCategory(TaskRepository.CATEGORY_REVIEW); + super.applyTo(taskRepository); } } diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueRepositorySettingsPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueRepositorySettingsPage.java index 805fa210..75d1a4e6 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueRepositorySettingsPage.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueRepositorySettingsPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 Red Hat and others. + * Copyright (c) 2011, 2020 Red Hat and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -14,8 +14,6 @@ *******************************************************************************/ package org.eclipse.mylyn.internal.github.ui.issue; -import java.io.IOException; -import java.net.URL; import java.text.MessageFormat; import org.eclipse.core.runtime.CoreException; @@ -26,27 +24,18 @@ import org.eclipse.egit.github.core.RepositoryId; import org.eclipse.egit.github.core.client.GitHubClient; import org.eclipse.egit.github.core.client.NoSuchPageException; import org.eclipse.egit.github.core.service.IssueService; -import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.mylyn.internal.github.core.GitHub; import org.eclipse.mylyn.internal.github.core.GitHubException; import org.eclipse.mylyn.internal.github.core.issue.IssueConnector; import org.eclipse.mylyn.internal.github.ui.GitHubUi; -import org.eclipse.mylyn.internal.tasks.core.IRepositoryConstants; +import org.eclipse.mylyn.internal.github.ui.HttpRepositorySettingsPage; import org.eclipse.mylyn.tasks.core.TaskRepository; -import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; /** * GitHub connector specific extensions. */ -@SuppressWarnings("restriction") -public class IssueRepositorySettingsPage extends AbstractRepositorySettingsPage { - - private boolean syncLabel = true; - private boolean editingUrl = false; +public class IssueRepositorySettingsPage extends HttpRepositorySettingsPage { /** * Populate taskRepository with repository settings. @@ -58,11 +47,6 @@ public class IssueRepositorySettingsPage extends AbstractRepositorySettingsPage super(Messages.IssueRepositorySettingsPage_Title, Messages.IssueRepositorySettingsPage_Description, taskRepository); - setHttpAuth(false); - setNeedsAdvanced(false); - setNeedsAnonymousLogin(true); - setNeedsTimeZone(false); - setNeedsHttpAuth(false); } @Override @@ -70,65 +54,20 @@ public class IssueRepositorySettingsPage extends AbstractRepositorySettingsPage return GitHub.CONNECTOR_KIND; } - /** - * Sync server url combo with repository label editor base on default label - * format - */ - protected void syncRepositoryLabel() { - if (syncLabel) { - String url = serverUrlCombo.getText(); - RepositoryId repo = GitHub.getRepository(url); - if (repo != null) - repositoryLabelEditor.setStringValue(IssueConnector - .getRepositoryLabel(repo)); - } - } - @Override protected void createAdditionalControls(Composite parent) { - // Set the URL now, because serverURL is definitely instantiated . - if (serverUrlCombo.getText().length() == 0) { - String fullUrlText = GitHub.HTTP_GITHUB_COM - + GitHub.REPOSITORY_SEGMENTS; - serverUrlCombo.setText(fullUrlText); - serverUrlCombo.setFocus(); - // select the user/project part of the URL so that the user can just - // start typing to replace the text. - serverUrlCombo.setSelection(new Point(GitHub.HTTP_GITHUB_COM - .length() + 1, fullUrlText.length())); - - syncRepositoryLabel(); - - serverUrlCombo.addModifyListener(new ModifyListener() { - - @Override - public void modifyText(ModifyEvent e) { - editingUrl = true; - try { - syncRepositoryLabel(); - } finally { - editingUrl = false; - } - } - }); - - repositoryLabelEditor.getTextControl(compositeContainer) - .addModifyListener(new ModifyListener() { - - @Override - public void modifyText(ModifyEvent e) { - if (!editingUrl) - syncLabel = false; - } - }); - } - - if (getRepository() == null) + if (getRepository() == null) { setAnonymous(false); + } + addTokenCheckbox(true); + // Set the URL now, because serverURL is definitely instantiated. + if (serverUrlCombo.getText().isEmpty()) { + setInitialUrl(IssueConnector::getRepositoryLabel); + } } @Override - protected Validator getValidator(final TaskRepository repository) { + protected Validator getValidator(final TaskRepository taskRepository) { Validator validator = new Validator() { @Override public void run(IProgressMonitor monitor) throws CoreException { @@ -139,9 +78,9 @@ public class IssueRepositorySettingsPage extends AbstractRepositorySettingsPage monitor.subTask(Messages.IssueRepositorySettingsPage_TaskContactingServer); try { GitHubClient client = IssueConnector - .createClient(repository); + .createClient(taskRepository); IssueService service = new IssueService(client); - RepositoryId repo = GitHub.getRepository(repository + RepositoryId repo = GitHub.getRepository(taskRepository .getRepositoryUrl()); monitor.worked(50); service.pageIssues(repo.getOwner(), repo.getName(), @@ -167,36 +106,10 @@ public class IssueRepositorySettingsPage extends AbstractRepositorySettingsPage return validator; } - @SuppressWarnings("unused") - @Override - protected boolean isValidUrl(final String url) { - if (url.startsWith("http://") || url.startsWith("https://")) //$NON-NLS-1$ //$NON-NLS-2$ - try { - new URL(url); - return GitHub.getRepository(url) != null; - } catch (IOException e) { - return false; - } - return false; - } - - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#applyTo(org.eclipse.mylyn.tasks.core.TaskRepository) - */ - @Override - public void applyTo(TaskRepository repository) { - repository.setProperty(IRepositoryConstants.PROPERTY_CATEGORY, - TaskRepository.CATEGORY_BUGS); - super.applyTo(repository); - } - - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#canValidate() - */ @Override - public boolean canValidate() { - return isPageComplete() - && (getMessage() == null || getMessageType() != IMessageProvider.ERROR); + public void applyTo(TaskRepository taskRepository) { + taskRepository.setCategory(TaskRepository.CATEGORY_BUGS); + super.applyTo(taskRepository); } } diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueTaskEditorPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueTaskEditorPage.java index d4833f3d..4cf81ded 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueTaskEditorPage.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/issue/IssueTaskEditorPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 Red Hat and others. + * Copyright (c) 2011, 2020 Red Hat and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -103,7 +103,11 @@ public class IssueTaskEditorPage extends AbstractTaskEditorPage { private boolean checkCanSubmit(final int type) { final TaskRepository taskRepository = getModel().getTaskRepository(); AuthenticationCredentials cred = taskRepository.getCredentials(AuthenticationType.REPOSITORY); - if (cred == null || cred.getUserName() == null || cred.getUserName().equals("")) { //$NON-NLS-1$ + boolean isToken = Boolean.parseBoolean( + taskRepository.getProperty(GitHub.PROPERTY_USE_TOKEN)); + boolean noUser = !isToken + && (cred.getUserName() == null || cred.getUserName().isEmpty()); + if (cred == null || noUser) { PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/messages.properties b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/messages.properties index be839ef5..15db5471 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/messages.properties +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/messages.properties @@ -1,9 +1,15 @@ -CredentialsWizardPage_Description=Enter GitHub user name and password +CredentialsWizardPage_Description=Enter GitHub log-in credentials CredentialsWizardPage_ErrorPassword=Enter GitHub password CredentialsWizardPage_ErrorUser=Enter GitHub login name CredentialsWizardPage_LabelPassword=Password: CredentialsWizardPage_LabelUser=User ID: CredentialsWizardPage_Title=GitHub Credentials +HttpRepositorySettingsPage_EnterToken=Enter a valid GitHub access token. +HttpRepositorySettingsPage_EnterUserAndToken=Enter a valid user ID and GitHub access token. +HttpRepositorySettingsPage_LabelSaveToken=Save Token +HttpRepositorySettingsPage_LabelToken=Token: +HttpRepositorySettingsPage_LabelUseToken=Use access token authentication +HttpRepositorySettingsPage_TooltipUseToken=If checked the password is assumed to be a GitHub personal access token, and GitHub token authentication is used instead of username/password (HTTP Basic) authentication. RepositoryImportWizard_Cloning=Cloning {0} RepositoryImportWizard_CloningRepositories=Cloning {0,choice,1#1 repository|1<{0} repositories} from GitHub RepositoryImportWizard_CloningRepository=Cloning repository from GitHub diff --git a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/pr/PullRequestRepositorySettingsPage.java b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/pr/PullRequestRepositorySettingsPage.java index 0b8ea9ca..f19f0555 100644 --- a/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/pr/PullRequestRepositorySettingsPage.java +++ b/org.eclipse.mylyn.github.ui/src/org/eclipse/mylyn/internal/github/ui/pr/PullRequestRepositorySettingsPage.java @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2011 GitHub Inc. + * Copyright (c) 2011, 2020 GitHub Inc. and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at @@ -29,23 +29,15 @@ import org.eclipse.mylyn.internal.github.core.issue.IssueConnector; import org.eclipse.mylyn.internal.github.core.pr.PullRequestConnector; import org.eclipse.mylyn.internal.github.ui.GitHubUi; import org.eclipse.mylyn.internal.github.ui.HttpRepositorySettingsPage; -import org.eclipse.mylyn.internal.tasks.core.IRepositoryConstants; import org.eclipse.mylyn.tasks.core.TaskRepository; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; /** * Pull request task repository settings page. */ -@SuppressWarnings("restriction") public class PullRequestRepositorySettingsPage extends HttpRepositorySettingsPage { - private boolean syncLabel = true; - private boolean editingUrl = false; - /** * Create pull request repository settings page * @@ -62,67 +54,23 @@ public class PullRequestRepositorySettingsPage extends return PullRequestConnector.KIND; } - /** - * Sync server URL combo with repository label editor based on default label - * format - */ - protected void syncRepositoryLabel() { - if (syncLabel) { - String url = serverUrlCombo.getText(); - RepositoryId repo = GitHub.getRepository(url); - if (repo != null) - repositoryLabelEditor.setStringValue(PullRequestConnector - .getRepositoryLabel(repo)); - } - } - @Override protected void createAdditionalControls(Composite parent) { // Set the URL now, because serverURL is definitely instantiated . if (serverUrlCombo.getText().length() == 0) { - String fullUrlText = GitHub.HTTP_GITHUB_COM - + GitHub.REPOSITORY_SEGMENTS; - serverUrlCombo.setText(fullUrlText); - serverUrlCombo.setFocus(); - // select the user/project part of the URL so that the user can just - // start typing to replace the text. - serverUrlCombo.setSelection(new Point(GitHub.HTTP_GITHUB_COM - .length() + 1, fullUrlText.length())); - - syncRepositoryLabel(); - - serverUrlCombo.addModifyListener(new ModifyListener() { - - @Override - public void modifyText(ModifyEvent e) { - editingUrl = true; - try { - syncRepositoryLabel(); - } finally { - editingUrl = false; - } - } - }); - - repositoryLabelEditor.getTextControl(compositeContainer) - .addModifyListener(new ModifyListener() { - - @Override - public void modifyText(ModifyEvent e) { - if (!editingUrl) - syncLabel = false; - } - }); - } else + setInitialUrl(PullRequestConnector::getRepositoryLabel); + } else { serverUrlCombo.setText(PullRequestConnector.stripPulls(repository .getRepositoryUrl())); - - if (getRepository() == null) + } + if (getRepository() == null) { setAnonymous(false); + } + addTokenCheckbox(true); } @Override - protected Validator getValidator(final TaskRepository repository) { + protected Validator getValidator(final TaskRepository taskRepository) { Validator validator = new Validator() { @Override public void run(IProgressMonitor monitor) throws CoreException { @@ -132,9 +80,9 @@ public class PullRequestRepositorySettingsPage extends monitor.subTask(Messages.PullRequestRepositorySettingsPage_TaskContacting); try { GitHubClient client = IssueConnector - .createClient(repository); + .createClient(taskRepository); PullRequestService service = new PullRequestService(client); - RepositoryId repo = GitHub.getRepository(repository + RepositoryId repo = GitHub.getRepository(taskRepository .getRepositoryUrl()); monitor.worked(50); service.pagePullRequests(repo, IssueService.STATE_OPEN, 1) @@ -159,14 +107,10 @@ public class PullRequestRepositorySettingsPage extends return validator; } - /** - * @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage#applyTo(org.eclipse.mylyn.tasks.core.TaskRepository) - */ @Override - public void applyTo(TaskRepository repository) { - repository.setProperty(IRepositoryConstants.PROPERTY_CATEGORY, - TaskRepository.CATEGORY_REVIEW); - super.applyTo(repository); + public void applyTo(TaskRepository taskRepository) { + taskRepository.setCategory(TaskRepository.CATEGORY_REVIEW); + super.applyTo(taskRepository); } @Override |