diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d04420..71d9df7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,4 +55,12 @@ All Notable changes to `Open in Git host` will be documented in this file ## 2.0.1 - 2017-09-30 -- Fixed encoding issue when URL contains non-ASCII characters. #40 \ No newline at end of file +- Fixed encoding issue when URL contains non-ASCII characters. #40 + +## 2.1.0 - 2017-11-05 + +- Code refactor +- Separated shortcuts for opening in the browser and copying to the clipboard #47 +- Rename plugin to GitLink #46 +- Make default branch customisable #45 +- Add custom URL factory #44 \ No newline at end of file diff --git a/README.md b/README.md index bc99234..e5c883a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,20 @@ -# Open in Git host - -[![Build Status](https://travis-ci.org/ben-gibson/jetbrains-open-in-git-host.svg?branch=master)](https://travis-ci.org/ben-gibson/jetbrains-open-in-git-host) -[![Join the chat at https://gitter.im/jetbrains-open-in-git-host/Lobby](https://badges.gitter.im/jetbrains-open-in-git-host/Lobby.svg)](https://gitter.im/jetbrains-open-in-git-host/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -A Jetbrains plugin that opens a local file under Git version control in its remote host using the default browser. -It can also optionally copy the URL to the clipboard. +

+ GitLink +
+

+ +

+ A Jetbrains plugin that provides shortcuts to open a file or commit in Stash, GitHub, BitBucket or GitLab using the default browser or copy the link to the clipboard. +

+ +

+ + Gitter + + +

+
Installation ------------------------------------------------------------------------------- @@ -12,14 +22,14 @@ Installation This plugin is published on the [JetBrains Plugin Repository](https://plugins.jetbrains.com/plugin/8183): - Preferences → Plugins → Browse Repositories → Search for "Open in Git host" + Preferences → Plugins → Browse Repositories → Search for "GitLink" ### From Source Clone this repository: - $ git clone https://github.com/ben-gibson/jetbrains-open-in-git-host - $ cd jetbrains-open-in-git-host + $ git clone https://github.com/ben-gibson/GitLink + $ cd GitLink Update the permissions: @@ -29,7 +39,7 @@ Build the plugin zip file: $ ./gradlew buildPlugin -Install the plugin from `./build/distributions/RemoteRepositoryMapper.zip`: +Install the plugin from `./build/distributions/GitLink-2.*.zip`: Preferences → Plugins → Install plugin from disk @@ -44,7 +54,7 @@ Update the permissions: Execute an IntelliJ IDEA instance with the plugin you're developing installed: $ ./gradlew runIdea - + Run the tests: $ ./gradlew test @@ -52,21 +62,24 @@ Run the tests: Usage ------------------------------------------------------------------------------- -After installing the plugin set your remote host in the preferences: +After installing the plugin set your remote host (GitHub, GitLab, BitBucket, Stash) and enabled extensions in the preferences: - Preferences → Other Settings → Open in Git host + Preferences → Other Settings → GitLink Make sure you have registered your projects root under the version control preferences: Preferences → Version Control (see unregistered roots) -Open a project file that is under Git version control in the editor: +To open the current file in the default browser: + + View → Open in (your selected host) or + Select in... → Browser (GitLink) + +To copy the link to you clipboard: - View → Open in Git host or - Select in... → Open in Git host + View → Copy (your selected host) link to clipboard -The current branch is used unless it does not exist in the remote host in which case it defaults to using the master branch. -The resulting link can be copied to the clipboard depending on your plugin preferences. +The current branch is used unless it does not exist on the remote in which case it defaults to your preferred branch as defined in the plugin settings. Change log ------------------------------------------------------------------------------- diff --git a/build.gradle b/build.gradle index eb1a51d..66fd3cb 100644 --- a/build.gradle +++ b/build.gradle @@ -36,10 +36,10 @@ sourceSets { intellij { plugins 'git4idea' - pluginName 'Open in Git host' + pluginName 'GitLink' updateSinceUntilBuild false sameSinceUntilBuild false } group 'org.jetbrains' -version '2.0.1' \ No newline at end of file +version '2.1.0' \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8775aea..4ade5ba 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Aug 22 17:18:30 BST 2017 +#Sat Sep 30 01:29:20 BST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip diff --git a/resources/Icons/Custom/Custom.png b/resources/Icons/Custom/Custom.png new file mode 100644 index 0000000..aa5aecd Binary files /dev/null and b/resources/Icons/Custom/Custom.png differ diff --git a/resources/Icons/Custom/Custom@2x.png b/resources/Icons/Custom/Custom@2x.png new file mode 100644 index 0000000..c8ae6fb Binary files /dev/null and b/resources/Icons/Custom/Custom@2x.png differ diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 02be7ea..edea675 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -1,32 +1,33 @@ - + uk.co.ben-gibson.remote.repository.mapper - Open in Git host - 2.0.1 - Ben Gibson + GitLink + 2.1.0 + Ben Gibson
- After installing select your remote host and the extensions you want enabled in Settings → Other Settings → Open in Git host - (currently supports the hosts GitHub, Stash, BitBucket and GitLab). Make sure you have registered your project's root under the version control settings. + After installing select your remote host in Settings → Other Settings → GitLink + (currently supports GitHub, Stash, BitBucket and GitLab). Make sure you have registered your project's root under the version control settings. Preferences → Version Control (see unregistered roots)

- To use, open a file that is under Git version control in the editor and select View → Open in Git host. You can + To open a file in the default browser select View → Open in (your selected host). You can also access this action through the Select target menu under Navigate → Select in. If you want to view a specific commit, you can do this by right clicking the commit from the VCS log tool window and selecting - Open in Git host. + Open in (your selected host).

- Note: The current branch is used unless it does not exist in your remote host in which case it defaults to the - master branch. + Note: The current branch is used unless it does not exist on the remote in which case your preferred default, + defined in the settings, is used. ]]>
-
  • - Fixed encoding issue when URL contains non-ASCII characters. #40 -
  • +
  • Code refactor
  • +
  • Separate shortcuts for opening in the browser and copying to the clipboard #47.
  • +
  • Rename project to GitLink #46.
  • +
  • Make default branch customisable #45.
  • +
  • Add custom URL factory #44.
  • ]]>
    @@ -44,31 +45,51 @@ - - - + + + - + + + + + + + + + + + + + + + - + diff --git a/src/uk/co/ben_gibson/git/link/Container.java b/src/uk/co/ben_gibson/git/link/Container.java new file mode 100644 index 0000000..a900308 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Container.java @@ -0,0 +1,190 @@ +package uk.co.ben_gibson.git.link; + +import com.intellij.ide.browsers.BrowserLauncher; +import com.intellij.ide.plugins.PluginManager; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.project.Project; +import uk.co.ben_gibson.git.link.Git.RepositoryFactory; +import uk.co.ben_gibson.git.link.Logger.Handlers.DiagnosticLogHandler; +import uk.co.ben_gibson.git.link.Logger.Logger; +import uk.co.ben_gibson.git.link.Url.Modifier.HttpsUrlModifier; +import uk.co.ben_gibson.git.link.Url.Modifier.UrlModifier; +import uk.co.ben_gibson.git.link.Url.Factory.*; +import uk.co.ben_gibson.git.link.Logger.Handlers.EventLogHandler; +import uk.co.ben_gibson.git.link.Url.Handler.CopyToClipboardHandler; +import uk.co.ben_gibson.git.link.Url.Handler.OpenInBrowserHandler; +import java.awt.*; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +/** + * Dependency container. + * + * There doesn't seem to be much documentation around Intellij's service manager. Services seem to be + * registered through the plugin.xml but there isn't any information about handling services that have complex dependencies. + * This acts as a simple alternative. + */ +public class Container +{ + private Hashtable applicationServices; + private Hashtable> projectServices; + + public Container() + { + this.applicationServices = new Hashtable<>(); + this.projectServices = new Hashtable<>(); + } + + /** + * If the plugins project configuration changes we need to flush the lazy load cache. + */ + public void flushProjectCache(Project project) + { + this.projectServices.remove(project); + } + + public Plugin plugin() + { + if (!this.hasApplicationService(Plugin.class)) { + this.registerApplicationService( + new Plugin(PluginManager.getPlugin(PluginId.getId("uk.co.ben-gibson.remote.repository.mapper"))) + ); + } + + return (Plugin)this.applicationService(Plugin.class); + } + + public Preferences preferences(Project project) + { + return ServiceManager.getService(project, Preferences.class); + } + + public UrlFactoryProvider urlFactoryProvider(Project project) + { + if (!this.hasProjectService(project, UrlFactoryProvider.class)) { + + Preferences preferences = this.preferences(project); + + UrlFactoryProvider provider = new UrlFactoryProvider(); + + provider.registerFactory(new GitHubUrlFactory()); + provider.registerFactory(new BitBucketUrlFactory()); + provider.registerFactory(new StashUrlFactory()); + provider.registerFactory( + new CustomUrlFactory(preferences.getCustomFileUrlTemplate(), preferences.getCustomCommitUrlTemplate()) + ); + + this.registerProjectService(project, provider); + } + + return (UrlFactoryProvider)this.projectService(project, UrlFactoryProvider.class); + } + + public OpenInBrowserHandler openInBrowserHandler() + { + if (!this.hasApplicationService(OpenInBrowserHandler.class)) { + this.registerApplicationService(new OpenInBrowserHandler(BrowserLauncher.getInstance())); + } + + return (OpenInBrowserHandler)this.applicationService(OpenInBrowserHandler.class); + } + + public CopyToClipboardHandler copyToClipboardHandler() + { + if (!this.hasApplicationService(CopyToClipboardHandler.class)) { + this.registerApplicationService(new CopyToClipboardHandler(Toolkit.getDefaultToolkit())); + } + + return (CopyToClipboardHandler)this.applicationService(CopyToClipboardHandler.class); + } + + public Logger logger(Project project) + { + if (!this.hasProjectService(project, Logger.class)) { + + Logger logger = new Logger(); + + logger.registerHandler(new EventLogHandler(this.plugin(), this.preferences(project).getEnableVerboseEventLog())); + + logger.registerHandler( + new DiagnosticLogHandler(com.intellij.openapi.diagnostic.Logger.getInstance(this.plugin().displayName())) + ); + + this.registerProjectService(project, logger); + } + + return (Logger)this.projectService(project, Logger.class); + } + + public List urlModifiers() + { + if (!this.hasApplicationService(UrlModifier.class)) { + + List modifiers = new ArrayList<>(); + + modifiers.add(new HttpsUrlModifier()); + + this.applicationServices.put(UrlModifier.class, modifiers); + } + + return (List)this.applicationService(UrlModifier.class); + } + + public Runner runner() + { + if (!this.hasApplicationService(Runner.class)) { + this.registerApplicationService(new Runner()); + } + + return (Runner)this.applicationService(Runner.class); + } + + public RepositoryFactory repositoryFactory() + { + if (!this.hasApplicationService(RepositoryFactory.class)) { + this.registerApplicationService(new RepositoryFactory()); + } + + return (RepositoryFactory)this.applicationService(RepositoryFactory.class); + } + + private void registerApplicationService(Object service) + { + this.applicationServices.put(service.getClass(), service); + } + + private Object applicationService(Class serviceClass) + { + return this.applicationServices.get(serviceClass); + } + + private Boolean hasApplicationService(Class serviceClass) + { + return this.applicationServices.containsKey(serviceClass); + } + + private void registerProjectService(Project project, Object service) + { + if (!this.projectServices.containsKey(project)) { + this.projectServices.put(project, new Hashtable<>()); + } + + this.projectServices.get(project).put(service.getClass(), service); + } + + private Object projectService(Project project, Class serviceClass) + { + if (!this.projectServices.containsKey(project)) { + return null; + } + + return this.projectServices.get(project).get(serviceClass); + } + + private Boolean hasProjectService(Project project, Class serviceClass) + { + return this.projectServices.containsKey(project) && this.projectServices.get(project).containsKey(serviceClass); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Exception/GitLinkException.java b/src/uk/co/ben_gibson/git/link/Exception/GitLinkException.java new file mode 100644 index 0000000..3fa50e0 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Exception/GitLinkException.java @@ -0,0 +1,12 @@ +package uk.co.ben_gibson.git.link.Exception; + +/** + * A base exception from which all exceptions from this plugin should extend! + */ +public abstract class GitLinkException extends Exception +{ + public GitLinkException(String message) + { + super(message); + } +} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/Branch.java b/src/uk/co/ben_gibson/git/link/Git/Branch.java similarity index 64% rename from src/uk/co/ben_gibson/open/in/git/host/Git/Branch.java rename to src/uk/co/ben_gibson/git/link/Git/Branch.java index d3fc615..19b55c9 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/Branch.java +++ b/src/uk/co/ben_gibson/git/link/Git/Branch.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host.Git; +package uk.co.ben_gibson.git.link.Git; public class Branch { @@ -18,4 +18,9 @@ public String toString() { return this.name; } + + public Boolean equals(Branch branch) + { + return this.toString().equals(branch.toString()); + } } diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/Commit.java b/src/uk/co/ben_gibson/git/link/Git/Commit.java similarity index 87% rename from src/uk/co/ben_gibson/open/in/git/host/Git/Commit.java rename to src/uk/co/ben_gibson/git/link/Git/Commit.java index 96d6e3a..9cd72b1 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/Commit.java +++ b/src/uk/co/ben_gibson/git/link/Git/Commit.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host.Git; +package uk.co.ben_gibson.git.link.Git; import com.intellij.vcs.log.VcsFullCommitDetails; diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/Exception/BranchException.java b/src/uk/co/ben_gibson/git/link/Git/Exception/BranchException.java similarity index 61% rename from src/uk/co/ben_gibson/open/in/git/host/Git/Exception/BranchException.java rename to src/uk/co/ben_gibson/git/link/Git/Exception/BranchException.java index 336b14a..371a32a 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/Exception/BranchException.java +++ b/src/uk/co/ben_gibson/git/link/Git/Exception/BranchException.java @@ -1,8 +1,8 @@ -package uk.co.ben_gibson.open.in.git.host.Git.Exception; +package uk.co.ben_gibson.git.link.Git.Exception; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; +import uk.co.ben_gibson.git.link.Exception.GitLinkException; -public class BranchException extends OpenInGitHostException +public class BranchException extends GitLinkException { private BranchException(String message) { diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/Exception/RemoteException.java b/src/uk/co/ben_gibson/git/link/Git/Exception/RemoteException.java similarity index 65% rename from src/uk/co/ben_gibson/open/in/git/host/Git/Exception/RemoteException.java rename to src/uk/co/ben_gibson/git/link/Git/Exception/RemoteException.java index ab394df..e8dcdf9 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/Exception/RemoteException.java +++ b/src/uk/co/ben_gibson/git/link/Git/Exception/RemoteException.java @@ -1,12 +1,12 @@ -package uk.co.ben_gibson.open.in.git.host.Git.Exception; +package uk.co.ben_gibson.git.link.Git.Exception; -import uk.co.ben_gibson.open.in.git.host.Git.Remote; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; +import uk.co.ben_gibson.git.link.Git.Remote; +import uk.co.ben_gibson.git.link.Exception.GitLinkException; /** * Thrown when a remote could not be found. */ -public class RemoteException extends OpenInGitHostException +public class RemoteException extends GitLinkException { private RemoteException(String message) { diff --git a/src/uk/co/ben_gibson/git/link/Git/Exception/RepositoryNotFoundException.java b/src/uk/co/ben_gibson/git/link/Git/Exception/RepositoryNotFoundException.java new file mode 100644 index 0000000..dc8e29d --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Git/Exception/RepositoryNotFoundException.java @@ -0,0 +1,14 @@ +package uk.co.ben_gibson.git.link.Git.Exception; + +import uk.co.ben_gibson.git.link.Exception.GitLinkException; + +/** + * Thrown when the repository could not be found. + */ +public class RepositoryNotFoundException extends GitLinkException +{ + public RepositoryNotFoundException() + { + super("Git repository not found!"); + } +} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/File.java b/src/uk/co/ben_gibson/git/link/Git/File.java similarity index 67% rename from src/uk/co/ben_gibson/open/in/git/host/Git/File.java rename to src/uk/co/ben_gibson/git/link/Git/File.java index 83a6d05..d4efc2b 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/File.java +++ b/src/uk/co/ben_gibson/git/link/Git/File.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host.Git; +package uk.co.ben_gibson.git.link.Git; import com.intellij.openapi.vfs.VirtualFile; @@ -7,7 +7,7 @@ */ public class File { - private String path; // A path from the root of the repository. + private String path; // A pathWithName from the root of the repository. private VirtualFile file; // The underlying file. public File(String path, VirtualFile file) @@ -21,6 +21,11 @@ public File(String path, VirtualFile file) } public String path() + { + return this.path.substring(0, (this.path.length() - this.name().length())); + } + + public String pathWithName() { return this.path; } diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/Remote.java b/src/uk/co/ben_gibson/git/link/Git/Remote.java similarity index 91% rename from src/uk/co/ben_gibson/open/in/git/host/Git/Remote.java rename to src/uk/co/ben_gibson/git/link/Git/Remote.java index f47adbe..21f1ab9 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/Remote.java +++ b/src/uk/co/ben_gibson/git/link/Git/Remote.java @@ -1,12 +1,13 @@ -package uk.co.ben_gibson.open.in.git.host.Git; +package uk.co.ben_gibson.git.link.Git; import com.intellij.openapi.util.text.StringUtil; import git4idea.GitLocalBranch; import git4idea.commands.Git; import git4idea.commands.GitCommandResult; import git4idea.repo.GitRemote; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.BranchException; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Exception.BranchException; + import java.net.MalformedURLException; import java.net.URL; diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/RemoteHost.java b/src/uk/co/ben_gibson/git/link/Git/RemoteHost.java similarity index 81% rename from src/uk/co/ben_gibson/open/in/git/host/Git/RemoteHost.java rename to src/uk/co/ben_gibson/git/link/Git/RemoteHost.java index bd8924d..06b9f46 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/RemoteHost.java +++ b/src/uk/co/ben_gibson/git/link/Git/RemoteHost.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host.Git; +package uk.co.ben_gibson.git.link.Git; import com.intellij.openapi.util.IconLoader; import javax.swing.*; @@ -11,7 +11,8 @@ public enum RemoteHost GIT_HUB("GitHub", "/Icons/GitHub/GitHub.png"), STASH("Stash", "/Icons/Bitbucket/Bitbucket.png"), BITBUCKET("Bitbucket", "/Icons/Bitbucket/Bitbucket.png"), - GITLAB("GitLab", "/Icons/GitLab/GitLab.png"); + GITLAB("GitLab", "/Icons/GitLab/GitLab.png"), + CUSTOM("Custom", "/Icons/Custom/Custom.png"); private final String name; private final String icon; @@ -27,6 +28,11 @@ public String toString() return this.name; } + public boolean custom() + { + return (this == CUSTOM); + } + public boolean gitHub() { return (this == GIT_HUB); diff --git a/src/uk/co/ben_gibson/open/in/git/host/Git/Repository.java b/src/uk/co/ben_gibson/git/link/Git/Repository.java similarity index 92% rename from src/uk/co/ben_gibson/open/in/git/host/Git/Repository.java rename to src/uk/co/ben_gibson/git/link/Git/Repository.java index 3792ab4..5a6837b 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Git/Repository.java +++ b/src/uk/co/ben_gibson/git/link/Git/Repository.java @@ -1,14 +1,13 @@ -package uk.co.ben_gibson.open.in.git.host.Git; +package uk.co.ben_gibson.git.link.Git; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitLocalBranch; import git4idea.GitRemoteBranch; import git4idea.commands.Git; -import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.BranchException; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Exception.BranchException; /** * Represents a git repository. diff --git a/src/uk/co/ben_gibson/git/link/Git/RepositoryFactory.java b/src/uk/co/ben_gibson/git/link/Git/RepositoryFactory.java new file mode 100644 index 0000000..d3138f0 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Git/RepositoryFactory.java @@ -0,0 +1,34 @@ +package uk.co.ben_gibson.git.link.Git; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcs.log.VcsFullCommitDetails; +import git4idea.GitUtil; +import git4idea.commands.GitImpl; +import git4idea.repo.GitRepository; +import uk.co.ben_gibson.git.link.Git.Exception.RepositoryNotFoundException; + +public class RepositoryFactory +{ + public Repository create(Project project, VirtualFile file, Branch defaultBranch) throws RepositoryNotFoundException + { + GitRepository repository = GitUtil.getRepositoryManager(project).getRepositoryForFile(file); + + if (repository == null) { + throw new RepositoryNotFoundException(); + } + + return new Repository(new GitImpl(), repository, defaultBranch); + } + + public Repository create(Project project, VcsFullCommitDetails commitDetails, Branch defaultBranch) throws RepositoryNotFoundException + { + GitRepository repository = GitUtil.getRepositoryManager(project).getRepositoryForRoot(commitDetails.getRoot()); + + if (repository == null) { + throw new RepositoryNotFoundException(); + } + + return new Repository(new GitImpl(), repository, defaultBranch); + } +} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/DiagnosticLogHandler.java b/src/uk/co/ben_gibson/git/link/Logger/Handlers/DiagnosticLogHandler.java similarity index 84% rename from src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/DiagnosticLogHandler.java rename to src/uk/co/ben_gibson/git/link/Logger/Handlers/DiagnosticLogHandler.java index 6066695..430caf6 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/DiagnosticLogHandler.java +++ b/src/uk/co/ben_gibson/git/link/Logger/Handlers/DiagnosticLogHandler.java @@ -1,7 +1,7 @@ -package uk.co.ben_gibson.open.in.git.host.Logger.Handlers; +package uk.co.ben_gibson.git.link.Logger.Handlers; import com.intellij.openapi.diagnostic.Logger; -import uk.co.ben_gibson.open.in.git.host.Logger.LogMessage; +import uk.co.ben_gibson.git.link.Logger.LogMessage; /** * Decorates the intellij diagnostic logger. diff --git a/src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/EventLogHandler.java b/src/uk/co/ben_gibson/git/link/Logger/Handlers/EventLogHandler.java similarity index 87% rename from src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/EventLogHandler.java rename to src/uk/co/ben_gibson/git/link/Logger/Handlers/EventLogHandler.java index 4f12a3e..b4b47f3 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/EventLogHandler.java +++ b/src/uk/co/ben_gibson/git/link/Logger/Handlers/EventLogHandler.java @@ -1,10 +1,10 @@ -package uk.co.ben_gibson.open.in.git.host.Logger.Handlers; +package uk.co.ben_gibson.git.link.Logger.Handlers; import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; -import uk.co.ben_gibson.open.in.git.host.Logger.LogMessage; -import uk.co.ben_gibson.open.in.git.host.Plugin; +import uk.co.ben_gibson.git.link.Logger.LogMessage; +import uk.co.ben_gibson.git.link.Plugin; /** * Logs messages to the event log window. diff --git a/src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/LogHandler.java b/src/uk/co/ben_gibson/git/link/Logger/Handlers/LogHandler.java similarity index 63% rename from src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/LogHandler.java rename to src/uk/co/ben_gibson/git/link/Logger/Handlers/LogHandler.java index a7d46d1..80a90a0 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Logger/Handlers/LogHandler.java +++ b/src/uk/co/ben_gibson/git/link/Logger/Handlers/LogHandler.java @@ -1,6 +1,6 @@ -package uk.co.ben_gibson.open.in.git.host.Logger.Handlers; +package uk.co.ben_gibson.git.link.Logger.Handlers; -import uk.co.ben_gibson.open.in.git.host.Logger.LogMessage; +import uk.co.ben_gibson.git.link.Logger.LogMessage; /** * Handles a log message in some way. diff --git a/src/uk/co/ben_gibson/open/in/git/host/Logger/LogMessage.java b/src/uk/co/ben_gibson/git/link/Logger/LogMessage.java similarity index 95% rename from src/uk/co/ben_gibson/open/in/git/host/Logger/LogMessage.java rename to src/uk/co/ben_gibson/git/link/Logger/LogMessage.java index 8b6e81d..1fd5e2a 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Logger/LogMessage.java +++ b/src/uk/co/ben_gibson/git/link/Logger/LogMessage.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host.Logger; +package uk.co.ben_gibson.git.link.Logger; /** * Represents a log message. diff --git a/src/uk/co/ben_gibson/open/in/git/host/Logger/Logger.java b/src/uk/co/ben_gibson/git/link/Logger/Logger.java similarity index 66% rename from src/uk/co/ben_gibson/open/in/git/host/Logger/Logger.java rename to src/uk/co/ben_gibson/git/link/Logger/Logger.java index ecf3cf7..a5080c2 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Logger/Logger.java +++ b/src/uk/co/ben_gibson/git/link/Logger/Logger.java @@ -1,8 +1,6 @@ -package uk.co.ben_gibson.open.in.git.host.Logger; - -import uk.co.ben_gibson.open.in.git.host.Exception.InvalidConfigurationException; -import uk.co.ben_gibson.open.in.git.host.Logger.Handlers.LogHandler; +package uk.co.ben_gibson.git.link.Logger; +import uk.co.ben_gibson.git.link.Logger.Handlers.LogHandler; import java.util.ArrayList; import java.util.List; @@ -30,11 +28,7 @@ public void error(String message) public void exception(Exception exception) { - if (exception instanceof InvalidConfigurationException) { - this.log(LogMessage.warning(exception.getMessage())); - } else { - this.log(LogMessage.error(exception.getMessage())); - } + this.log(LogMessage.error(exception.getMessage())); } public void registerHandler(LogHandler handler) diff --git a/src/uk/co/ben_gibson/open/in/git/host/Plugin.java b/src/uk/co/ben_gibson/git/link/Plugin.java similarity index 53% rename from src/uk/co/ben_gibson/open/in/git/host/Plugin.java rename to src/uk/co/ben_gibson/git/link/Plugin.java index 744a572..30b742a 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/Plugin.java +++ b/src/uk/co/ben_gibson/git/link/Plugin.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host; +package uk.co.ben_gibson.git.link; import com.intellij.ide.plugins.IdeaPluginDescriptor; @@ -7,18 +7,11 @@ */ public class Plugin { - private String name; - private String version; - - public Plugin(String name, String version) - { - this.name = name; - this.version = version; - } + private IdeaPluginDescriptor pluginDescriptor; public Plugin(IdeaPluginDescriptor pluginDescriptor) { - this(pluginDescriptor.getName(), pluginDescriptor.getVersion()); + this.pluginDescriptor = pluginDescriptor; } public String toString() { @@ -27,11 +20,16 @@ public String toString() { public String displayName() { - return name; + return this.pluginDescriptor.getName(); } public String version() { - return version; + return this.pluginDescriptor.getVersion(); + } + + public String issueTracker() + { + return this.pluginDescriptor.getVendorUrl().concat("/issues"); } } diff --git a/src/uk/co/ben_gibson/git/link/Preferences.java b/src/uk/co/ben_gibson/git/link/Preferences.java new file mode 100644 index 0000000..c40e3b7 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Preferences.java @@ -0,0 +1,113 @@ +package uk.co.ben_gibson.git.link; + +import uk.co.ben_gibson.git.link.Git.Branch; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.util.xmlb.XmlSerializerUtil; +import uk.co.ben_gibson.git.link.Url.Modifier.UrlModifier; +import java.util.ArrayList; +import java.util.List; + +@State(name = "Preferences", + storages = {@Storage("GitLinkConfig.xml")} +) + +/* + * Plugin preferences - Getters and Setters required by PersistentStateComponent + */ +public class Preferences implements PersistentStateComponent +{ + private RemoteHost remoteHost = RemoteHost.GIT_HUB; + private boolean enableVerboseEventLog = false; + private List enabledModifiers = new ArrayList<>(); + private Branch defaultBranch = new Branch("master"); + private String customFileUrlTemplate = ""; + private String customCommitUrlTemplate = ""; + + public boolean isModifierEnabled(UrlModifier modifier) + { + return this.enabledModifiers.contains(modifier.getClass().getName()); + } + + public List getEnabledModifiers() + { + return this.enabledModifiers; + } + + public void setEnabledModifiers(List enabledModifiers) + { + this.enabledModifiers = enabledModifiers; + } + + public void enableModifier(UrlModifier modifier) + { + this.enabledModifiers.add(modifier.getClass().getName()); + } + + public void disableModifier(UrlModifier modifier) + { + this.enabledModifiers.remove(modifier.getClass().getName()); + } + + public boolean getEnableVerboseEventLog() + { + return this.enableVerboseEventLog; + } + + public void setEnableVerboseEventLog(boolean enableVerboseEventLog) + { + this.enableVerboseEventLog = enableVerboseEventLog; + } + + public void setRemoteHost(RemoteHost remoteHost) + { + this.remoteHost = remoteHost; + } + + public RemoteHost getRemoteHost() + { + return this.remoteHost; + } + + public void loadState(Preferences state) + { + XmlSerializerUtil.copyBean(state, this); + } + + public Branch getDefaultBranch() + { + return this.defaultBranch; + } + + public void setDefaultBranch(Branch defaultBranch) + { + this.defaultBranch = defaultBranch; + } + + public String getCustomFileUrlTemplate() + { + return customFileUrlTemplate; + } + + public void setCustomFileUrlTemplate(String customFileUrlTemplate) + { + this.customFileUrlTemplate = customFileUrlTemplate; + } + + public String getCustomCommitUrlTemplate() + { + return customCommitUrlTemplate; + } + + public void setCustomCommitUrlTemplate(String customCommitUrlTemplate) + { + this.customCommitUrlTemplate = customCommitUrlTemplate; + } + + public Preferences getState() + { + return this; + } +} diff --git a/src/uk/co/ben_gibson/git/link/RemoteUrlGenerator.java b/src/uk/co/ben_gibson/git/link/RemoteUrlGenerator.java new file mode 100644 index 0000000..899f788 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/RemoteUrlGenerator.java @@ -0,0 +1,10 @@ +package uk.co.ben_gibson.git.link; + +import uk.co.ben_gibson.git.link.Exception.GitLinkException; + +import java.net.URL; + +public interface RemoteUrlGenerator +{ + URL generateRemoteURL() throws GitLinkException; +} diff --git a/src/uk/co/ben_gibson/git/link/Runner.java b/src/uk/co/ben_gibson/git/link/Runner.java new file mode 100644 index 0000000..ee1d291 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Runner.java @@ -0,0 +1,120 @@ +package uk.co.ben_gibson.git.link; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcs.log.VcsFullCommitDetails; +import org.jetbrains.annotations.NotNull; +import uk.co.ben_gibson.git.link.Exception.GitLinkException; +import uk.co.ben_gibson.git.link.Git.Commit; +import uk.co.ben_gibson.git.link.Git.Exception.RepositoryNotFoundException; +import uk.co.ben_gibson.git.link.Git.Repository; +import uk.co.ben_gibson.git.link.Logger.Logger; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.UrlFactory; +import uk.co.ben_gibson.git.link.Url.Modifier.UrlModifier; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; +import java.net.URL; + +/** + * Acts as a facade for the plugin. + */ +public class Runner +{ + public void runForFile(Project project, VirtualFile file, UrlHandler handler) + { + Container container = this.container(); + Preferences preferences = container.preferences(project); + Repository repository; + + try { + repository = container.repositoryFactory().create(project, file, preferences.getDefaultBranch()); + } catch (RepositoryNotFoundException e) { + container.logger(project).warning("Git repository not found, make sure you have registered your version control root: Preferences → Version Control"); + return; + } + + Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); + + Integer caretPosition = (editor != null) ? editor.getCaretModel().getLogicalPosition().line + 1 : null; + + this.run(project, handler, () -> { + + UrlFactory remoteUrlFactory = container.urlFactoryProvider(project).urlFactory(preferences.getRemoteHost()); + + return remoteUrlFactory.createUrl( + new FileDescription( + repository.origin(), + repository.currentBranch(), + repository.fileFromVirtualFile(file), + caretPosition + ) + ); + }); + } + + public void runForCommit(Project project, VcsFullCommitDetails commitDetails, UrlHandler handler) + { + Container container = this.container(); + Preferences preferences = container.preferences(project); + Repository repository; + + try { + repository = container.repositoryFactory().create(project, commitDetails, preferences.getDefaultBranch()); + } catch (RepositoryNotFoundException e) { + container.logger(project).warning("Git repository not found, make sure you have registered your version control root: Preferences → Version Control"); + return; + } + + this.run(project, handler, () -> { + UrlFactory remoteUrlFactory = container.urlFactoryProvider(project).urlFactory(preferences.getRemoteHost()); + + return remoteUrlFactory.createUrl(new CommitDescription(repository.origin(), new Commit(commitDetails))); + }); + } + + private void run(Project project, UrlHandler handler, RemoteUrlGenerator generator) + { + Container container = this.container(); + Preferences preferences = container.preferences(project); + Logger logger = container.logger(project); + + Task.Backgroundable task = new Task.Backgroundable(project, "GitLink - Processing") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + try { + + URL remoteUrl = generator.generateRemoteURL(); + + logger.notice(String.format("Generated URL '%s'", remoteUrl.toString())); + + for (UrlModifier urlModifier: container.urlModifiers()) { + if (preferences.isModifierEnabled(urlModifier)) { + remoteUrl = urlModifier.modify(remoteUrl); + logger.notice(String.format("Applied modifier '%s' - '%s'", urlModifier.name(), remoteUrl.toString())); + } + } + + logger.notice(String.format("Running URL handler '%s'", handler.name())); + + handler.handle(generator.generateRemoteURL()); + + } catch (GitLinkException e) { + logger.exception(e); + } + } + }; + + task.queue(); + } + + protected Container container() + { + return ServiceManager.getService(Container.class); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Action/Action.java b/src/uk/co/ben_gibson/git/link/UI/Action/Action.java new file mode 100644 index 0000000..e8e878f --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Action/Action.java @@ -0,0 +1,60 @@ +package uk.co.ben_gibson.git.link.UI.Action; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Container; +import uk.co.ben_gibson.git.link.Logger.Logger; +import uk.co.ben_gibson.git.link.Preferences; + +public abstract class Action extends AnAction +{ + protected abstract boolean shouldActionBeEnabled(AnActionEvent event); + protected abstract String displayName(RemoteHost remoteHost); + + public abstract void actionPerformed(Project project, AnActionEvent event); + + public void actionPerformed(AnActionEvent event) + { + Project project = event.getProject(); + + Container container = this.container(); + Preferences settings = container.preferences(project); + Logger logger = container().logger(project); + + if (project == null) { + return; + } + + logger.notice(String.format("Running '%s' action.", this.displayName(settings.getRemoteHost()))); + + this.actionPerformed(project, event); + } + + public void update(AnActionEvent event) + { + super.update(event); + + if (event.getProject() == null) { + event.getPresentation().setEnabled(false); + return; + } + + RemoteHost remoteHost = this.container().preferences(event.getProject()).getRemoteHost(); + + Presentation presentation = event.getPresentation(); + + presentation.setText(this.displayName(remoteHost)); + presentation.setIcon(remoteHost.icon()); + + presentation.setEnabledAndVisible(this.shouldActionBeEnabled(event)); + } + + protected Container container() + { + return ServiceManager.getService(Container.class); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Action/Menu/BrowserMenuAction.java b/src/uk/co/ben_gibson/git/link/UI/Action/Menu/BrowserMenuAction.java new file mode 100644 index 0000000..a28ff4e --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Action/Menu/BrowserMenuAction.java @@ -0,0 +1,17 @@ +package uk.co.ben_gibson.git.link.UI.Action.Menu; + +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; + +public class BrowserMenuAction extends MenuAction +{ + protected String displayName(RemoteHost remoteHost) + { + return String.format("Open in %s", remoteHost.toString()); + } + + UrlHandler remoteUrlHandler() + { + return container().openInBrowserHandler(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Action/Menu/ClipboardMenuAction.java b/src/uk/co/ben_gibson/git/link/UI/Action/Menu/ClipboardMenuAction.java new file mode 100644 index 0000000..0ed26a7 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Action/Menu/ClipboardMenuAction.java @@ -0,0 +1,17 @@ +package uk.co.ben_gibson.git.link.UI.Action.Menu; + +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; + +public class ClipboardMenuAction extends MenuAction +{ + protected String displayName(RemoteHost remoteHost) + { + return String.format("Copy %s link to clipboard", remoteHost.toString()); + } + + UrlHandler remoteUrlHandler() + { + return container().copyToClipboardHandler(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Action/Menu/MenuAction.java b/src/uk/co/ben_gibson/git/link/UI/Action/Menu/MenuAction.java new file mode 100644 index 0000000..2b80d4c --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Action/Menu/MenuAction.java @@ -0,0 +1,32 @@ +package uk.co.ben_gibson.git.link.UI.Action.Menu; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; +import uk.co.ben_gibson.git.link.UI.Action.Action; + +/** + * An action triggered from the view or right click menu. + */ +abstract class MenuAction extends Action +{ + abstract UrlHandler remoteUrlHandler(); + + public void actionPerformed(Project project, AnActionEvent event) + { + VirtualFile file = event.getData(CommonDataKeys.VIRTUAL_FILE); + + if (file == null || project == null) { + return; + } + + this.container().runner().runForFile(project, file, this.remoteUrlHandler()); + } + + protected boolean shouldActionBeEnabled(AnActionEvent event) + { + return (event.getData(CommonDataKeys.VIRTUAL_FILE) != null); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/BrowserVcsAction.java b/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/BrowserVcsAction.java new file mode 100644 index 0000000..e552ff9 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/BrowserVcsAction.java @@ -0,0 +1,17 @@ +package uk.co.ben_gibson.git.link.UI.Action.Vcs; + +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; + +public class BrowserVcsAction extends VcsLogAction +{ + protected String displayName(RemoteHost remoteHost) + { + return String.format("Open commit in %s", remoteHost.toString()); + } + + UrlHandler remoteUrlHandler() + { + return container().openInBrowserHandler(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/ClipboardVcsAction.java b/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/ClipboardVcsAction.java new file mode 100644 index 0000000..53c578c --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/ClipboardVcsAction.java @@ -0,0 +1,17 @@ +package uk.co.ben_gibson.git.link.UI.Action.Vcs; + +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; + +public class ClipboardVcsAction extends VcsLogAction +{ + protected String displayName(RemoteHost remoteHost) + { + return String.format("Copy %s commit link to clipboard", remoteHost.toString()); + } + + UrlHandler remoteUrlHandler() + { + return container().copyToClipboardHandler(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/VcsLogAction.java b/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/VcsLogAction.java new file mode 100644 index 0000000..b4a0c1f --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Action/Vcs/VcsLogAction.java @@ -0,0 +1,44 @@ +package uk.co.ben_gibson.git.link.UI.Action.Vcs; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.Project; +import com.intellij.vcs.log.VcsFullCommitDetails; +import com.intellij.vcs.log.VcsLog; +import com.intellij.vcs.log.VcsLogDataKeys; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; +import uk.co.ben_gibson.git.link.UI.Action.Action; +import java.util.List; + +/** + * An action triggered from an VCS log toolbar. + */ +abstract class VcsLogAction extends Action +{ + abstract UrlHandler remoteUrlHandler(); + + public void actionPerformed(Project project, AnActionEvent event) + { + VcsLog vcsLog = event.getData(VcsLogDataKeys.VCS_LOG); + + if (vcsLog == null) { + return; + } + + VcsFullCommitDetails commit = vcsLog.getSelectedDetails().get(0); + + this.container().runner().runForCommit(project, commit, this.remoteUrlHandler()); + } + + protected boolean shouldActionBeEnabled(AnActionEvent event) + { + VcsLog log = event.getData(VcsLogDataKeys.VCS_LOG); + + if (log == null) { + return false; + } + + List commits = log.getSelectedDetails(); + + return commits.size() == 1; + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Settings/ConfigurableSettings.java b/src/uk/co/ben_gibson/git/link/UI/Settings/ConfigurableSettings.java new file mode 100644 index 0000000..1c252c5 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Settings/ConfigurableSettings.java @@ -0,0 +1,66 @@ +package uk.co.ben_gibson.git.link.UI.Settings; + +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import uk.co.ben_gibson.git.link.Container; +import javax.swing.*; + +public class ConfigurableSettings implements Configurable +{ + private final Container container; + private final Project project; + private uk.co.ben_gibson.git.link.UI.Settings.Settings ui; + + public ConfigurableSettings(Project project, Container container) + { + this.container = container; + this.project = project; + } + + public JComponent createComponent() + { + this.ui = new uk.co.ben_gibson.git.link.UI.Settings.Settings( + this.container.preferences(this.project), + this.container.urlModifiers(), + this.container.plugin() + ); + + return ui.getRootPanel(); + } + + @Override + public void disposeUIResources() + { + this.ui = null; + } + + public String getHelpTopic() + { + return this.container.plugin().displayName(); + } + + public String getDisplayName() + { + return this.container.plugin().displayName(); + } + + public boolean isModified() + { + return this.ui.isModified(); + } + + public void apply() throws ConfigurationException + { + this.ui.apply(); + + // We need to flush the container when the plugins configuration has changed as many project level services + // are constructed with values derived from the settings. + this.container.flushProjectCache(this.project); + } + + public void reset() + { + this.ui.reset(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Settings/Settings.form b/src/uk/co/ben_gibson/git/link/UI/Settings/Settings.form new file mode 100644 index 0000000..9847e68 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Settings/Settings.form @@ -0,0 +1,243 @@ + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/uk/co/ben_gibson/git/link/UI/Settings/Settings.java b/src/uk/co/ben_gibson/git/link/UI/Settings/Settings.java new file mode 100644 index 0000000..8bbd693 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Settings/Settings.java @@ -0,0 +1,249 @@ +package uk.co.ben_gibson.git.link.UI.Settings; + +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.ui.EnumComboBoxModel; +import com.intellij.ui.Gray; +import com.intellij.ui.components.JBCheckBox; +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import com.intellij.uiDesigner.core.Spacer; +import com.jgoodies.forms.layout.CellConstraints; +import com.jgoodies.forms.layout.FormLayout; +import uk.co.ben_gibson.git.link.Git.Branch; +import uk.co.ben_gibson.git.link.Plugin; +import uk.co.ben_gibson.git.link.Preferences; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Modifier.UrlModifier; +import javax.swing.*; +import java.awt.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Settings +{ + private JPanel rootPanel; + private JComboBox hostSelect; + private JTextField defaultBranchTextField; + private JTextField customFileUrlTemplateTextField; + private JTextField customCommitUrlTemplateTextField; + private JPanel customURLPanel; + private JCheckBox verboseLoggingCheckBox; + private JLabel customFileUrlLabel; + private JLabel customCommitUrlLabel; + private JLabel projectSettingsLabel; + private JLabel customUrlLabel; + private JPanel urlModifierCheckBoxPanel; + private JLabel featureRequestLabel; + private JLabel pluginDetailsLabel; + private Preferences preferences; + private Map urlModifierCheckBoxes = new HashMap<>(); + + public Settings(Preferences preferences, List urlModifiers, Plugin plugin) + { + this.preferences = preferences; + + $$$setupUI$$$(); + this.hostSelect.setModel(new EnumComboBoxModel<>(RemoteHost.class)); + this.defaultBranchTextField.setText(this.preferences.getDefaultBranch().toString()); + this.customURLPanel.setVisible(this.preferences.getRemoteHost().custom()); + + this.applyLabelHelpTextStlye(this.customFileUrlLabel); + this.applyLabelHelpTextStlye(this.customCommitUrlLabel); + this.applyLabelHeadingStlye(this.projectSettingsLabel); + this.applyLabelHeadingStlye(this.customUrlLabel); + + this.hostSelect.addActionListener(e -> { + RemoteHost host = (((RemoteHost) hostSelect.getSelectedItem())); + Settings.this.customURLPanel.setVisible((host != null && host.custom())); + }); + + for (UrlModifier modifier : urlModifiers) { + JBCheckBox checkBox = new JBCheckBox(modifier.name()); + this.urlModifierCheckBoxes.put(modifier, checkBox); + this.urlModifierCheckBoxPanel.add(checkBox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + } + + this.pluginDetailsLabel.setText(plugin.toString()); + this.featureRequestLabel.setText(String.format("Submit feature requests and bug reports to %s", plugin.issueTracker())); + this.applyLabelHelpTextStlye(this.pluginDetailsLabel); + this.applyLabelHelpTextStlye(this.featureRequestLabel); + + } + + public JPanel getRootPanel() + { + return rootPanel; + } + + public boolean isModified() + { + for (Map.Entry entry : this.urlModifierCheckBoxes.entrySet()) { + if (entry.getValue().isSelected() != this.preferences.isModifierEnabled(entry.getKey())) { + return true; + } + } + + return + this.verboseLoggingCheckBox.isSelected() != this.preferences.getEnableVerboseEventLog() || + this.hostSelect.getSelectedItem() != this.preferences.getRemoteHost() || + !this.preferences.getDefaultBranch().equals(new Branch(this.defaultBranchTextField.getText())) || + !this.preferences.getCustomFileUrlTemplate().equals(this.customFileUrlTemplateTextField.getText()) || + !this.preferences.getCustomCommitUrlTemplate().equals(this.customCommitUrlTemplateTextField.getText()); + } + + public void apply() throws ConfigurationException + { + RemoteHost remoteHost = (RemoteHost) this.hostSelect.getSelectedItem(); + + if (remoteHost != null && remoteHost.custom()) { + + try { + URL url = new URL(this.customFileUrlTemplateTextField.getText()); + this.preferences.setCustomFileUrlTemplate(url.toString()); + } catch (MalformedURLException exception) { + throw new ConfigurationException("Invalid URL provided for the custom file URL"); + } + + try { + URL url = new URL(this.customCommitUrlTemplateTextField.getText()); + this.preferences.setCustomCommitUrlTemplate(url.toString()); + } catch (MalformedURLException exception) { + throw new ConfigurationException("Invalid URL provided for the custom commit URL"); + } + } + + if (this.defaultBranchTextField.getText().isEmpty()) { + throw new ConfigurationException("Default branch is required"); + } + + this.preferences.setDefaultBranch(new Branch(this.defaultBranchTextField.getText())); + this.preferences.setEnableVerboseEventLog(this.verboseLoggingCheckBox.isSelected()); + this.preferences.setRemoteHost(remoteHost); + + for (Map.Entry entry : this.urlModifierCheckBoxes.entrySet()) { + if (entry.getValue().isSelected()) { + this.preferences.enableModifier(entry.getKey()); + } else { + this.preferences.disableModifier(entry.getKey()); + } + } + } + + public void reset() + { + this.defaultBranchTextField.setText(this.preferences.getDefaultBranch().toString()); + this.verboseLoggingCheckBox.setSelected(this.preferences.getEnableVerboseEventLog()); + this.hostSelect.setSelectedItem(this.preferences.getRemoteHost()); + this.customFileUrlTemplateTextField.setText(this.preferences.getCustomFileUrlTemplate()); + this.customCommitUrlTemplateTextField.setText(this.preferences.getCustomCommitUrlTemplate()); + + for (Map.Entry entry : this.urlModifierCheckBoxes.entrySet()) { + entry.getValue().setSelected(this.preferences.isModifierEnabled(entry.getKey())); + } + } + + private void applyLabelHeadingStlye(JLabel label) + { + label.setFont(new Font(null, Font.PLAIN, 12)); + label.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Gray._200)); + } + + private void applyLabelHelpTextStlye(JLabel label) + { + label.setFont(new Font(null, Font.ITALIC, 11)); + } + + private void createUIComponents() + { + this.urlModifierCheckBoxPanel = new JPanel(); + this.urlModifierCheckBoxPanel.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), -1, -1)); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() + { + createUIComponents(); + rootPanel = new JPanel(); + rootPanel.setLayout(new FormLayout("fill:d:grow", "center:max(d;4px):noGrow,top:3dlu:noGrow,center:d:noGrow,top:3dlu:noGrow,center:max(d;4px):noGrow,top:3dlu:noGrow,center:max(d;4px):noGrow,top:3dlu:noGrow,center:max(d;4px):noGrow,top:3dlu:noGrow,center:max(d;4px):noGrow,top:3dlu:noGrow,center:d:grow")); + final JPanel panel1 = new JPanel(); + panel1.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); + CellConstraints cc = new CellConstraints(); + rootPanel.add(panel1, cc.xy(1, 3)); + final JLabel label1 = new JLabel(); + label1.setText("Hosts"); + panel1.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(100, -1), null, null, 0, false)); + hostSelect = new JComboBox(); + panel1.add(hostSelect, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + customURLPanel = new JPanel(); + customURLPanel.setLayout(new GridLayoutManager(6, 2, new Insets(0, 0, 0, 0), -1, -1)); + customURLPanel.setVisible(true); + rootPanel.add(customURLPanel, cc.xy(1, 11)); + final JLabel label2 = new JLabel(); + label2.setText("File"); + customURLPanel.add(label2, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(100, -1), null, null, 0, false)); + customFileUrlTemplateTextField = new JTextField(); + customURLPanel.add(customFileUrlTemplateTextField, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + customFileUrlLabel = new JLabel(); + customFileUrlLabel.setHorizontalAlignment(10); + customFileUrlLabel.setHorizontalTextPosition(11); + customFileUrlLabel.setText("e.g. https://example.com/{repository}/blob/{branch}#{line} "); + customFileUrlLabel.setVerticalTextPosition(0); + customFileUrlLabel.setVisible(true); + customURLPanel.add(customFileUrlLabel, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_NORTHEAST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JLabel label3 = new JLabel(); + label3.setText("Commit"); + customURLPanel.add(label3, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + customCommitUrlTemplateTextField = new JTextField(); + customURLPanel.add(customCommitUrlTemplateTextField, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + customCommitUrlLabel = new JLabel(); + customCommitUrlLabel.setText("e.g. https://example.com/{repository}/{commit}#{line} "); + customURLPanel.add(customCommitUrlLabel, new GridConstraints(5, 1, 1, 1, GridConstraints.ANCHOR_NORTHEAST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer1 = new Spacer(); + customURLPanel.add(spacer1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, new Dimension(-1, 10), null, null, 0, false)); + customUrlLabel = new JLabel(); + customUrlLabel.setText("Custom URL"); + customURLPanel.add(customUrlLabel, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final JPanel panel2 = new JPanel(); + panel2.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); + rootPanel.add(panel2, cc.xy(1, 5)); + final JLabel label4 = new JLabel(); + label4.setText("Default Branch"); + panel2.add(label4, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, new Dimension(100, -1), null, null, 0, false)); + defaultBranchTextField = new JTextField(); + panel2.add(defaultBranchTextField, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + final JPanel panel3 = new JPanel(); + panel3.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), -1, -1)); + rootPanel.add(panel3, cc.xy(1, 7)); + verboseLoggingCheckBox = new JCheckBox(); + verboseLoggingCheckBox.setText("Enable verbose logging"); + panel3.add(verboseLoggingCheckBox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + final Spacer spacer2 = new Spacer(); + panel3.add(spacer2, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); + final Spacer spacer3 = new Spacer(); + panel3.add(spacer3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, new Dimension(-1, 10), null, null, 0, false)); + final Spacer spacer4 = new Spacer(); + rootPanel.add(spacer4, cc.xy(1, 13, CellConstraints.DEFAULT, CellConstraints.FILL)); + projectSettingsLabel = new JLabel(); + projectSettingsLabel.setText("Project Settings"); + projectSettingsLabel.setVerticalAlignment(0); + rootPanel.add(projectSettingsLabel, cc.xy(1, 1, CellConstraints.DEFAULT, CellConstraints.CENTER)); + rootPanel.add(urlModifierCheckBoxPanel, cc.xy(1, 9)); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() + { + return rootPanel; + } +} diff --git a/src/uk/co/ben_gibson/git/link/UI/Target/BrowserSelectInTarget.java b/src/uk/co/ben_gibson/git/link/UI/Target/BrowserSelectInTarget.java new file mode 100644 index 0000000..842895e --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/UI/Target/BrowserSelectInTarget.java @@ -0,0 +1,49 @@ +package uk.co.ben_gibson.git.link.UI.Target; + +import com.intellij.ide.SelectInContext; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import uk.co.ben_gibson.git.link.Container; + +public class BrowserSelectInTarget implements com.intellij.ide.SelectInTarget +{ + public boolean canSelect(SelectInContext context) + { + return true; + } + + public void selectIn(SelectInContext context, boolean requestFocus) + { + Container container = this.container(); + Project project = context.getProject(); + VirtualFile file = context.getVirtualFile(); + + container.runner().runForFile(project, file, this.container().openInBrowserHandler()); + } + + protected Container container() + { + return ServiceManager.getService(Container.class); + } + + public String getToolWindowId() + { + return null; + } + + public String getMinorViewId() + { + return null; + } + + public float getWeight() + { + return 0; + } + + public String toString() + { + return "Browser (GitLink)"; + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/AbstractUrlFactory.java b/src/uk/co/ben_gibson/git/link/Url/Factory/AbstractUrlFactory.java new file mode 100644 index 0000000..09c5546 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/AbstractUrlFactory.java @@ -0,0 +1,40 @@ +package uk.co.ben_gibson.git.link.Url.Factory; + +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Remote; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +abstract class AbstractUrlFactory implements UrlFactory +{ + URL buildURL(Remote remote, String path, String query, String fragment) throws UrlFactoryException, RemoteException + { + URL host = remote.url(); + + try { + + URI uri = new URI(host.getProtocol(), host.getHost(), path, query, fragment); + + return uri.toURL(); + + } catch (URISyntaxException | MalformedURLException e) { + throw UrlFactoryException.cannotCreateUrl(e.getMessage()); + } + } + + String cleanPath(String path) + { + if (path.startsWith("/")) { + path = path.substring(1); + } + + if (path.endsWith("/")) { + path = path.substring(0, (path.length() - 1)); + } + + return path; + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/BitBucketUrlFactory.java b/src/uk/co/ben_gibson/git/link/Url/Factory/BitBucketUrlFactory.java new file mode 100644 index 0000000..c14a55c --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/BitBucketUrlFactory.java @@ -0,0 +1,42 @@ +package uk.co.ben_gibson.git.link.Url.Factory; + +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.File; +import uk.co.ben_gibson.git.link.Git.Remote; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import java.net.URL; + +public class BitBucketUrlFactory extends AbstractUrlFactory +{ + public URL createUrl(CommitDescription description) throws UrlFactoryException, RemoteException + { + Remote remote = description.remote(); + + String path = String.format("/%s/commits/%s", this.cleanPath(remote.url().getPath()), description.commitHash()); + + return this.buildURL(remote, path, null, null); + } + + public URL createUrl(FileDescription description) throws UrlFactoryException, RemoteException + { + Remote remote = description.remote(); + File file = description.file(); + String path = String.format("/%s/src/HEAD/%s", this.cleanPath(remote.url().getPath()), this.cleanPath(file.pathWithName())); + String query = String.format("at=%s", description.branch()); + String fragment = null; + + if (description.hasLineNumber()) { + fragment = String.format("%s-%s", file.name(), description.lineNumber()); + } + + return this.buildURL(remote, path, query, fragment); + } + + public boolean supports(RemoteHost host) + { + return host.bitbucket(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/CustomUrlFactory.java b/src/uk/co/ben_gibson/git/link/Url/Factory/CustomUrlFactory.java new file mode 100644 index 0000000..c1e9500 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/CustomUrlFactory.java @@ -0,0 +1,51 @@ +package uk.co.ben_gibson.git.link.Url.Factory; + +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import java.net.MalformedURLException; +import java.net.URL; + +public class CustomUrlFactory extends AbstractUrlFactory +{ + private String fileUrlTemplate; + private String commitUrlTemplate; + + public CustomUrlFactory(String fileUrlTemplate, String commitUrlTemplate) + { + this.fileUrlTemplate = fileUrlTemplate; + this.commitUrlTemplate = commitUrlTemplate; + } + + public URL createUrl(CommitDescription description) throws UrlFactoryException, RemoteException + { + String url = this.commitUrlTemplate.replace("{commit}", description.commitHash()); + + try { + return new URL(url); + } catch (MalformedURLException e) { + throw UrlFactoryException.cannotCreateUrl(String.format("Custom url '%s' is invalid.", url)); + } + } + + public URL createUrl(FileDescription description) throws UrlFactoryException, RemoteException + { + String url = this.fileUrlTemplate.replace("{branch}", description.branch().toString()); + url = url.replace("{filePath}", this.cleanPath(description.file().path())); + url = url.replace("{fileName}", description.file().name()); + url = url.replace("{line}", description.hasLineNumber() ? description.lineNumber().toString() : ""); + + try { + return new URL(url); + } catch (MalformedURLException e) { + throw UrlFactoryException.cannotCreateUrl(String.format("Custom url '%s' is invalid.", url)); + } + } + + public boolean supports(RemoteHost host) + { + return host.custom(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/Description/CommitDescription.java b/src/uk/co/ben_gibson/git/link/Url/Factory/Description/CommitDescription.java new file mode 100644 index 0000000..6d271f9 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/Description/CommitDescription.java @@ -0,0 +1,24 @@ +package uk.co.ben_gibson.git.link.Url.Factory.Description; + +import uk.co.ben_gibson.git.link.Git.Commit; +import uk.co.ben_gibson.git.link.Git.Remote; + +/** + * Describes a commit that can be used to create a URL. + */ +public class CommitDescription extends GitDescription +{ + private Commit commit; + + public CommitDescription(Remote remote, Commit commit) + { + super(remote); + + this.commit = commit; + } + + public String commitHash() + { + return this.commit.hash(); + } +} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteFileDescription.java b/src/uk/co/ben_gibson/git/link/Url/Factory/Description/FileDescription.java similarity index 54% rename from src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteFileDescription.java rename to src/uk/co/ben_gibson/git/link/Url/Factory/Description/FileDescription.java index fb9adc0..c07f5e7 100644 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteFileDescription.java +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/Description/FileDescription.java @@ -1,19 +1,19 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description; +package uk.co.ben_gibson.git.link.Url.Factory.Description; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; -import uk.co.ben_gibson.open.in.git.host.Git.File; -import uk.co.ben_gibson.open.in.git.host.Git.Remote; +import uk.co.ben_gibson.git.link.Git.Branch; +import uk.co.ben_gibson.git.link.Git.Remote; +import uk.co.ben_gibson.git.link.Git.File; /** - * Describes a remote file that a URL can be created to. + * Describes a file that can be used to create a URL. */ -public class RemoteFileDescription extends RemoteDescription +public class FileDescription extends GitDescription { private Branch branch; private File file; private Integer lineNumber; - public RemoteFileDescription(Remote remote, Branch branch, File file, Integer lineNumber) + public FileDescription(Remote remote, Branch branch, File file, Integer lineNumber) { super(remote); @@ -22,7 +22,6 @@ public RemoteFileDescription(Remote remote, Branch branch, File file, Integer li this.lineNumber = lineNumber; } - public Branch branch() { return this.branch; diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/Description/GitDescription.java b/src/uk/co/ben_gibson/git/link/Url/Factory/Description/GitDescription.java new file mode 100644 index 0000000..47bee36 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/Description/GitDescription.java @@ -0,0 +1,18 @@ +package uk.co.ben_gibson.git.link.Url.Factory.Description; + +import uk.co.ben_gibson.git.link.Git.Remote; + +abstract public class GitDescription +{ + private Remote remote; + + GitDescription(Remote remote) + { + this.remote = remote; + } + + public Remote remote() + { + return remote; + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/Exception/UrlFactoryException.java b/src/uk/co/ben_gibson/git/link/Url/Factory/Exception/UrlFactoryException.java new file mode 100644 index 0000000..4069905 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/Exception/UrlFactoryException.java @@ -0,0 +1,22 @@ +package uk.co.ben_gibson.git.link.Url.Factory.Exception; + +import uk.co.ben_gibson.git.link.Exception.GitLinkException; +import uk.co.ben_gibson.git.link.Git.RemoteHost; + +public class UrlFactoryException extends GitLinkException +{ + private UrlFactoryException(String message) + { + super(message); + } + + public static UrlFactoryException unsupportedRemoteHost(RemoteHost host) + { + return new UrlFactoryException(String.format("The remote host '%s' is not supported", host.name())); + } + + public static UrlFactoryException cannotCreateUrl(String reason) + { + return new UrlFactoryException(String.format("Cannot create url (%s)", reason)); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/GitHubUrlFactory.java b/src/uk/co/ben_gibson/git/link/Url/Factory/GitHubUrlFactory.java new file mode 100644 index 0000000..7b45018 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/GitHubUrlFactory.java @@ -0,0 +1,40 @@ +package uk.co.ben_gibson.git.link.Url.Factory; + +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Remote; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import java.net.URL; + +public class GitHubUrlFactory extends AbstractUrlFactory +{ + public URL createUrl(CommitDescription description) throws UrlFactoryException, RemoteException + { + Remote remote = description.remote(); + + String path = String.format("/%s/commit/%s", this.cleanPath(remote.url().getPath()), description.commitHash()); + + return this.buildURL(remote, path, null, null); + } + + public URL createUrl(FileDescription description) throws UrlFactoryException, RemoteException + { + Remote remote = description.remote(); + + String path = String.format("/%s/blob/%s/%s", this.cleanPath(remote.url().getPath()), description.branch(), this.cleanPath(description.file().pathWithName())); + String fragment = null; + + if (description.hasLineNumber()) { + fragment = String.format("L%d", description.lineNumber()); + } + + return this.buildURL(remote, path, null, fragment); + } + + public boolean supports(RemoteHost host) + { + return host.gitHub() || host.gitLab(); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/StashUrlFactory.java b/src/uk/co/ben_gibson/git/link/Url/Factory/StashUrlFactory.java new file mode 100644 index 0000000..7de189e --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/StashUrlFactory.java @@ -0,0 +1,62 @@ +package uk.co.ben_gibson.git.link.Url.Factory; + +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Remote; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import java.net.URL; + +public class StashUrlFactory extends AbstractUrlFactory +{ + public URL createUrl(CommitDescription description) throws UrlFactoryException, RemoteException + { + Remote remote = description.remote(); + + String[] parts = this.getParts(remote.url()); + + String project = parts[1]; + String repository = parts[2]; + + String path = String.format("/projects/%s/repos/%s/commits/%s", project, repository, description.commitHash()); + + return this.buildURL(remote, path, null, null); + } + + public URL createUrl(FileDescription description) throws UrlFactoryException, RemoteException + { + String[] parts = this.getParts(description.remote().url()); + + String project = parts[1]; + String repository = parts[2]; + + String path = String.format("/projects/%s/repos/%s/browse/%s", project, repository, description.file().pathWithName()); + String query = String.format("at=refs/heads/%s", description.branch()); + String fragment = null; + + if (description.hasLineNumber()) { + fragment = description.lineNumber().toString(); + } + + return this.buildURL(description.remote(), path, query, fragment); + } + + public boolean supports(RemoteHost host) + { + return host.stash(); + } + + private String[] getParts(URL url) throws UrlFactoryException + { + String[] parts = url.getPath().split("/", 3); + + if (parts.length < 3) { + throw UrlFactoryException.cannotCreateUrl( + String.format("Could not determine Stash project or repository from URL '%s'", url) + ); + } + + return parts; + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/UrlFactory.java b/src/uk/co/ben_gibson/git/link/Url/Factory/UrlFactory.java new file mode 100644 index 0000000..478dd01 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/UrlFactory.java @@ -0,0 +1,15 @@ +package uk.co.ben_gibson.git.link.Url.Factory; + +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import java.net.URL; + +public interface UrlFactory +{ + URL createUrl(CommitDescription description) throws UrlFactoryException, RemoteException; + URL createUrl(FileDescription description) throws UrlFactoryException, RemoteException; + boolean supports(RemoteHost host); +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Factory/UrlFactoryProvider.java b/src/uk/co/ben_gibson/git/link/Url/Factory/UrlFactoryProvider.java new file mode 100644 index 0000000..17b2427 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Factory/UrlFactoryProvider.java @@ -0,0 +1,30 @@ +package uk.co.ben_gibson.git.link.Url.Factory; + +import uk.co.ben_gibson.git.link.Git.RemoteHost; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import java.util.ArrayList; +import java.util.List; + +/** + * Provides a URL factory for a given remote git host. + */ +public class UrlFactoryProvider +{ + private List factories = new ArrayList(); + + public void registerFactory(UrlFactory factory) + { + this.factories.add(factory); + } + + public UrlFactory urlFactory(RemoteHost host) throws UrlFactoryException + { + for (UrlFactory factory : this.factories) { + if (factory.supports(host)) { + return factory; + } + } + + throw UrlFactoryException.unsupportedRemoteHost(host); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Handler/CopyToClipboardHandler.java b/src/uk/co/ben_gibson/git/link/Url/Handler/CopyToClipboardHandler.java new file mode 100644 index 0000000..afb5213 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Handler/CopyToClipboardHandler.java @@ -0,0 +1,28 @@ +package uk.co.ben_gibson.git.link.Url.Handler; + +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.net.URL; + +/** + * Copies a URL to the clipboard. + */ +public class CopyToClipboardHandler implements UrlHandler +{ + private Toolkit toolkit; + + public CopyToClipboardHandler(Toolkit toolkit) + { + this.toolkit = toolkit; + } + + public void handle(URL url) + { + this.toolkit.getSystemClipboard().setContents(new StringSelection(url.toString()), null); + } + + public String name() + { + return "Copy to clipboard"; + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Handler/Exception/UrlHandlerException.java b/src/uk/co/ben_gibson/git/link/Url/Handler/Exception/UrlHandlerException.java new file mode 100644 index 0000000..27bbcc6 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Handler/Exception/UrlHandlerException.java @@ -0,0 +1,14 @@ +package uk.co.ben_gibson.git.link.Url.Handler.Exception; + +import uk.co.ben_gibson.git.link.Exception.GitLinkException; + +/** + * Thrown when a handler cannot handle the URL. + */ +public class UrlHandlerException extends GitLinkException +{ + public UrlHandlerException(String message) + { + super(message); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Handler/OpenInBrowserHandler.java b/src/uk/co/ben_gibson/git/link/Url/Handler/OpenInBrowserHandler.java new file mode 100644 index 0000000..484fa61 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Handler/OpenInBrowserHandler.java @@ -0,0 +1,32 @@ +package uk.co.ben_gibson.git.link.Url.Handler; + +import com.intellij.ide.browsers.BrowserLauncher; +import uk.co.ben_gibson.git.link.Url.Handler.Exception.UrlHandlerException; +import java.net.URL; + +/** + * Opens a URL in the default browser. + */ +public class OpenInBrowserHandler implements UrlHandler +{ + private BrowserLauncher browserLauncher; + + public OpenInBrowserHandler(BrowserLauncher browserLauncher) + { + this.browserLauncher = browserLauncher; + } + + public void handle(URL url) throws UrlHandlerException + { + try { + this.browserLauncher.open(url.toURI().toASCIIString()); + } catch (Exception e) { + throw new UrlHandlerException(e.getMessage()); + } + } + + public String name() + { + return "Open in browser"; + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Handler/UrlHandler.java b/src/uk/co/ben_gibson/git/link/Url/Handler/UrlHandler.java new file mode 100644 index 0000000..c41318c --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Handler/UrlHandler.java @@ -0,0 +1,14 @@ +package uk.co.ben_gibson.git.link.Url.Handler; + +import uk.co.ben_gibson.git.link.Url.Handler.Exception.UrlHandlerException; +import java.net.URL; + +/** + * Handles a URL in some way e.g. copies it the clipboard. + */ +public interface UrlHandler +{ + void handle(URL url) throws UrlHandlerException; + + String name(); +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Modifier/Exception/ModifierException.java b/src/uk/co/ben_gibson/git/link/Url/Modifier/Exception/ModifierException.java new file mode 100644 index 0000000..14af051 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Modifier/Exception/ModifierException.java @@ -0,0 +1,11 @@ +package uk.co.ben_gibson.git.link.Url.Modifier.Exception; + +import uk.co.ben_gibson.git.link.Exception.GitLinkException; + +public class ModifierException extends GitLinkException +{ + public ModifierException(String message) + { + super(message); + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Modifier/HttpsUrlModifier.java b/src/uk/co/ben_gibson/git/link/Url/Modifier/HttpsUrlModifier.java new file mode 100644 index 0000000..7c9d6ce --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Modifier/HttpsUrlModifier.java @@ -0,0 +1,38 @@ +package uk.co.ben_gibson.git.link.Url.Modifier; + +import uk.co.ben_gibson.git.link.Url.Modifier.Exception.ModifierException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * Modifies a URL by forcing the protocol to use HTTPS. + */ +public class HttpsUrlModifier implements UrlModifier +{ + public URL modify(URL url) throws ModifierException + { + if (url.getProtocol().equals("https")) { + return url; + } + + try { + + String file = url.getFile(); + + if (url.getRef() != null) { + file = file.concat("#" + url.getRef()); + } + + return new URL("https", url.getHost(), url.getPort(), file); + } catch (MalformedURLException e) { + throw new ModifierException(e.getMessage()); + } + } + + public String name() + { + return "Force HTTPS"; + } +} diff --git a/src/uk/co/ben_gibson/git/link/Url/Modifier/UrlModifier.java b/src/uk/co/ben_gibson/git/link/Url/Modifier/UrlModifier.java new file mode 100644 index 0000000..34498b2 --- /dev/null +++ b/src/uk/co/ben_gibson/git/link/Url/Modifier/UrlModifier.java @@ -0,0 +1,14 @@ +package uk.co.ben_gibson.git.link.Url.Modifier; + +import uk.co.ben_gibson.git.link.Url.Modifier.Exception.ModifierException; +import java.net.URL; + +/** + * Modify a URL in some way. + */ +public interface UrlModifier +{ + URL modify(URL url) throws ModifierException; + + String name(); +} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Configuration.java b/src/uk/co/ben_gibson/open/in/git/host/Configuration.java deleted file mode 100644 index c09df14..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Configuration.java +++ /dev/null @@ -1,167 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host; - -import com.intellij.openapi.options.Configurable; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.ComboBox; -import com.intellij.ui.EnumComboBoxModel; -import com.intellij.ui.components.JBCheckBox; -import com.intellij.ui.components.JBLabel; -import uk.co.ben_gibson.open.in.git.host.Extension.Extension; -import uk.co.ben_gibson.open.in.git.host.Git.RemoteHost; -import com.intellij.openapi.options.ConfigurationException; -import javax.swing.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class Configuration implements Configurable -{ - private static final String LABEL_HOSTS = "Hosts"; - private static final String FORCE_SSL = "Force SSL"; - private static final String EVENT_LOGGING = "Enable verbose event logging"; - private static final String LABEL_EXTENSIONS = "Extensions"; - private static final String LABEL_OPTIONS = "Options"; - - private Settings settings; - - private JBCheckBox enableVerboseEventLogging; - private JBCheckBox forceSSLCheckBox; - private ComboBox hostsComboBox; - private Container container; - - private Map extensionCheckBoxes = new HashMap<>(); - - /** - * Needs cleaning up - dumping ground for preferences UI. - * - * Now idea how to inject the dependencies as this is wired up in the plugin.xml and auto-magically created :( - */ - public Configuration(Project project, Container container) - { - this.container = container; - this.settings = container.settings(project); - - this.enableVerboseEventLogging = new JBCheckBox(EVENT_LOGGING); - this.forceSSLCheckBox = new JBCheckBox(FORCE_SSL); - this.hostsComboBox = new ComboBox(new EnumComboBoxModel<>(RemoteHost.class), 200); - - for (Extension extension: this.container.registeredExtensions()) { - extensionCheckBoxes.put(extension, new JBCheckBox(extension.displayName())); - } - } - - public JComponent createComponent() - { - this.reset(); - - JPanel panel = new JPanel(); - - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - - this.hostsComboBox.setAlignmentX(0.0f); - - this.addToPanel(panel, new JBLabel(LABEL_HOSTS)); - this.addToPanel(panel, this.hostsComboBox); - this.addSpacing(panel); - this.addToPanel(panel, new JBLabel(LABEL_EXTENSIONS)); - - for (JCheckBox extensionCheckBox : this.extensionCheckBoxes.values()) { - this.addToPanel(panel, extensionCheckBox); - } - - this.addSpacing(panel); - - this.addToPanel(panel, new JBLabel(LABEL_OPTIONS)); - this.addToPanel(panel, this.enableVerboseEventLogging); - this.addToPanel(panel, this.forceSSLCheckBox); - - return panel; - } - - public boolean isModified() - { - for (Map.Entry entry : this.extensionCheckBoxes.entrySet()) { - Extension extension = entry.getKey(); - JBCheckBox checkBox = entry.getValue(); - - if (checkBox.isSelected() != this.settings.isExtensionEnabled(extension)) { - return true; - } - } - - return - this.forceSSLCheckBox.isSelected() != this.settings.getForceSSL() || - this.enableVerboseEventLogging.isSelected() != this.settings.getEnableVerboseEventLog() || - this.hostsComboBox.getSelectedItem() != this.settings.getRemoteHost(); - } - - public void apply() throws ConfigurationException - { - this.settings.setForceSSL(this.forceSSLCheckBox.isSelected()); - this.settings.setEnableVerboseEventLog(this.enableVerboseEventLogging.isSelected()); - this.settings.setRemoteHost((RemoteHost) this.hostsComboBox.getSelectedItem()); - - List enabledExtensions = new ArrayList<>(); - - for (Map.Entry entry : this.extensionCheckBoxes.entrySet()) { - Extension extension = entry.getKey(); - JBCheckBox checkBox = entry.getValue(); - - if (checkBox.isSelected()) { - enabledExtensions.add(extension.getClass().getName()); - } - } - - this.settings.setEnabledExtensions(enabledExtensions); - } - - public void reset() - { - this.enableVerboseEventLogging.setSelected(this.settings.getEnableVerboseEventLog()); - this.forceSSLCheckBox.setSelected(this.settings.getForceSSL()); - this.hostsComboBox.setSelectedItem(this.settings.getRemoteHost()); - - for (Map.Entry entry : this.extensionCheckBoxes.entrySet()) { - - Extension extension = entry.getKey(); - JBCheckBox checkBox = entry.getValue(); - - checkBox.setSelected(this.settings.isExtensionEnabled(extension)); - } - } - - public void disposeUIResources() - { - this.enableVerboseEventLogging = null; - this.forceSSLCheckBox = null; - this.hostsComboBox = null; - this.extensionCheckBoxes = null; - } - - public String getHelpTopic() - { - return "Open In Git Host"; - } - - public String getDisplayName() - { - return this.container.plugin().displayName(); - } - - private void addSpacing(JPanel panel) - { - JPanel spacing = new JPanel(); - - spacing.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); - - this.addToPanel(panel, spacing); - } - - private void addToPanel(JPanel panel, JComponent component) - { - component.setMaximumSize(component.getPreferredSize()); - - panel.add(component); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Container.java b/src/uk/co/ben_gibson/open/in/git/host/Container.java deleted file mode 100644 index e3b5889..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Container.java +++ /dev/null @@ -1,119 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host; - -import com.intellij.ide.browsers.BrowserLauncher; -import com.intellij.ide.plugins.PluginManager; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.extensions.PluginId; -import com.intellij.openapi.project.Project; -import uk.co.ben_gibson.open.in.git.host.Extension.CopyToClipboardExtension; -import uk.co.ben_gibson.open.in.git.host.Extension.Extension; -import uk.co.ben_gibson.open.in.git.host.Extension.ExtensionRunner; -import uk.co.ben_gibson.open.in.git.host.Extension.OpenInBrowserExtension; -import uk.co.ben_gibson.open.in.git.host.Git.RemoteHost; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.*; -import uk.co.ben_gibson.open.in.git.host.Logger.Handlers.DiagnosticLogHandler; -import uk.co.ben_gibson.open.in.git.host.Logger.Handlers.EventLogHandler; -import uk.co.ben_gibson.open.in.git.host.Logger.Logger; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -/** - * Dependency container. - * - * There doesn't seem to be much documentation around Intellij's service manager. Services seem to be - * registered through the plugin.xml but there isn't any information about handling services that have complex dependencies. - * This acts as a simple alternative. - */ -public class Container -{ - private Plugin plugin; - private List extensions; - private RemoteUrlFactoryProvider remoteUrlFactoryProvider; - - public Plugin plugin() - { - if (this.plugin == null) { - - PluginId pluginId = PluginId.getId("uk.co.ben-gibson.remote.repository.mapper"); - - this.plugin = new Plugin(PluginManager.getPlugin(pluginId)); - } - - return this.plugin; - } - - public Settings settings(Project project) - { - return ServiceManager.getService(project, Settings.class); - } - - public RemoteUrlFactoryProvider remoteUrlFactoryProvider() - { - if (this.remoteUrlFactoryProvider == null) { - - this.remoteUrlFactoryProvider = new RemoteUrlFactoryProvider(); - - this.remoteUrlFactoryProvider.registerFactory(new GitHubRemoteUrlFactory()); - this.remoteUrlFactoryProvider.registerFactory(new BitBucketRemoteUrlFactory()); - this.remoteUrlFactoryProvider.registerFactory(new StashRemoteUrlFactory()); - } - - return this.remoteUrlFactoryProvider; - } - - public RemoteUrlFactory remoteUrlFactory(Project project) throws RemoteUrlFactoryException - { - return this.remoteUrlFactoryProvider().remoteUrlFactoryForHost(this.remoteHost(project)); - } - - public RemoteHost remoteHost(Project project) - { - return this.settings(project).getRemoteHost(); - } - - public Logger logger(Project project) - { - Logger logger = new Logger(); - - logger.registerHandler(new EventLogHandler(this.plugin(), this.settings(project).getEnableVerboseEventLog())); - - logger.registerHandler( - new DiagnosticLogHandler(com.intellij.openapi.diagnostic.Logger.getInstance(this.plugin().displayName())) - ); - - return logger; - } - - public List registeredExtensions() - { - if (this.extensions == null) { - this.extensions = new ArrayList<>(); - this.extensions.add(new OpenInBrowserExtension(BrowserLauncher.getInstance())); - this.extensions.add(new CopyToClipboardExtension(Toolkit.getDefaultToolkit())); - } - - return this.extensions; - } - - public List enabledExtensions(Project project) - { - Settings settings = this.settings(project); - - List enabledExtensions = new ArrayList<>(); - - for (Extension extension: this.registeredExtensions()) { - if (settings.isExtensionEnabled(extension)) { - enabledExtensions.add(extension); - } - } - - return enabledExtensions; - } - - public ExtensionRunner extensionRunner(Project project) - { - return new ExtensionRunner(this.logger(project), this.enabledExtensions(project)); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Exception/InvalidConfigurationException.java b/src/uk/co/ben_gibson/open/in/git/host/Exception/InvalidConfigurationException.java deleted file mode 100644 index dad6c0f..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Exception/InvalidConfigurationException.java +++ /dev/null @@ -1,8 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.Exception; - -/** - * Thrown when some configuration is invalid for use with the plugin. - */ -public interface InvalidConfigurationException -{ -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Exception/OpenInGitHostException.java b/src/uk/co/ben_gibson/open/in/git/host/Exception/OpenInGitHostException.java deleted file mode 100644 index 14f209b..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Exception/OpenInGitHostException.java +++ /dev/null @@ -1,12 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.Exception; - -/** - * A base exception from which all exceptions from this library should extend! - */ -public abstract class OpenInGitHostException extends Exception -{ - public OpenInGitHostException(String message) - { - super(message); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Extension/CopyToClipboardExtension.java b/src/uk/co/ben_gibson/open/in/git/host/Extension/CopyToClipboardExtension.java deleted file mode 100644 index 0843127..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Extension/CopyToClipboardExtension.java +++ /dev/null @@ -1,28 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.Extension; - -import java.awt.*; -import java.awt.datatransfer.StringSelection; -import java.net.URL; - -/** - * An extension to copy a remote git url to the clipboard. - */ -public class CopyToClipboardExtension implements Extension -{ - private Toolkit toolkit; - - public CopyToClipboardExtension(Toolkit toolkit) - { - this.toolkit = toolkit; - } - - public void run(URL remoteUrl) - { - this.toolkit.getSystemClipboard().setContents(new StringSelection(remoteUrl.toString()), null); - } - - public String displayName() - { - return "Copy to Clipboard"; - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Extension/Exception/ExtensionException.java b/src/uk/co/ben_gibson/open/in/git/host/Extension/Exception/ExtensionException.java deleted file mode 100644 index 91e7ea7..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Extension/Exception/ExtensionException.java +++ /dev/null @@ -1,11 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.Extension.Exception; - -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; - -public class ExtensionException extends OpenInGitHostException -{ - public ExtensionException(String message) - { - super(message); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Extension/Extension.java b/src/uk/co/ben_gibson/open/in/git/host/Extension/Extension.java deleted file mode 100644 index 7df4d41..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Extension/Extension.java +++ /dev/null @@ -1,15 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.Extension; - -import uk.co.ben_gibson.open.in.git.host.Extension.Exception.ExtensionException; - -import java.net.URL; - -/** - * An extension of the plugin. - */ -public interface Extension -{ - void run(URL remoteUrl) throws ExtensionException; - - String displayName(); -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Extension/ExtensionRunner.java b/src/uk/co/ben_gibson/open/in/git/host/Extension/ExtensionRunner.java deleted file mode 100644 index dd12ef4..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Extension/ExtensionRunner.java +++ /dev/null @@ -1,32 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.Extension; - -import uk.co.ben_gibson.open.in.git.host.Extension.Exception.ExtensionException; -import uk.co.ben_gibson.open.in.git.host.Logger.Logger; -import java.net.URL; -import java.util.List; - -public class ExtensionRunner -{ - private Logger logger; - private List extensions; - - public ExtensionRunner(Logger logger, List extensions) - { - this.logger = logger; - this.extensions = extensions; - } - - public void run(URL remoteUrl) throws ExtensionException - { - logger.notice(String.format("Running extensions with url '%s'", remoteUrl.toString())); - - if (this.extensions.isEmpty()) { - logger.warning("You have no extensions enabled, enable some: Preferences → Open in Git host"); - } - - for (Extension extension: this.extensions) { - logger.notice(String.format("Running extension '%s'", extension.displayName())); - extension.run(remoteUrl); - } - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Extension/OpenInBrowserExtension.java b/src/uk/co/ben_gibson/open/in/git/host/Extension/OpenInBrowserExtension.java deleted file mode 100644 index 26b7a60..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Extension/OpenInBrowserExtension.java +++ /dev/null @@ -1,33 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.Extension; - -import com.intellij.ide.browsers.BrowserLauncher; -import uk.co.ben_gibson.open.in.git.host.Extension.Exception.ExtensionException; -import java.net.URL; - -/** - * An extension to open a remote git url in the browser. - */ -public class OpenInBrowserExtension implements Extension -{ - private BrowserLauncher browserLauncher; - - public OpenInBrowserExtension(BrowserLauncher browserLauncher) - { - this.browserLauncher = browserLauncher; - } - - public void run(URL remoteUrl) throws ExtensionException - { - try { - this.browserLauncher.open(remoteUrl.toURI().toASCIIString()); - } catch (Exception e) { - throw new ExtensionException(e.getMessage()); - } - - } - - public String displayName() - { - return "Open in Browser"; - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/AbstractRemoteUrlFactory.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/AbstractRemoteUrlFactory.java deleted file mode 100644 index f16e065..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/AbstractRemoteUrlFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory; - -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.Git.Remote; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; - -abstract class AbstractRemoteUrlFactory implements RemoteUrlFactory -{ - URL buildURL(Remote remote, String path, String query, String fragment, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException - { - URL host = remote.url(); - - String protocol = (forceSSL) ? "https" : host.getProtocol(); - - try { - - URI uri = new URI(protocol, host.getHost(), path, query, fragment); - - return uri.toURL(); - - } catch (URISyntaxException | MalformedURLException e) { - throw RemoteUrlFactoryException.cannotCreateRemoteUrl(e.getMessage()); - } - } - - String cleanPath(String path) - { - if (path.startsWith("/")) { - path = path.substring(1); - } - - if (path.endsWith("/")) { - path = path.substring(0, (path.length() - 1)); - } - - return path; - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/BitBucketRemoteUrlFactory.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/BitBucketRemoteUrlFactory.java deleted file mode 100644 index 5fb2c92..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/BitBucketRemoteUrlFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory; - -import uk.co.ben_gibson.open.in.git.host.Git.*; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; -import java.net.URL; - -public class BitBucketRemoteUrlFactory extends AbstractRemoteUrlFactory -{ - public URL createUrl(RemoteCommitDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException - { - Remote remote = description.remote(); - - String path = String.format("/%s/commits/%s", this.cleanPath(remote.url().getPath()), description.commitHash()); - - return this.buildURL(remote, path, null, null, forceSSL); - } - - public URL createUrl(RemoteFileDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException - { - Remote remote = description.remote(); - File file = description.file(); - String path = String.format("/%s/src/HEAD/%s", this.cleanPath(remote.url().getPath()), this.cleanPath(file.path())); - String query = String.format("at=%s", description.branch()); - String fragment = null; - - if (description.hasLineNumber()) { - fragment = String.format("%s-%s", file.name(), description.lineNumber()); - } - - return this.buildURL(remote, path, query, fragment, forceSSL); - } - - public boolean supports(RemoteHost host) - { - return host.bitbucket(); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteCommitDescription.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteCommitDescription.java deleted file mode 100644 index 0b813db..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteCommitDescription.java +++ /dev/null @@ -1,24 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description; - -import uk.co.ben_gibson.open.in.git.host.Git.Commit; -import uk.co.ben_gibson.open.in.git.host.Git.Remote; - -/** - * Describes a remote commit that a URL can be created to. - */ -public class RemoteCommitDescription extends RemoteDescription -{ - private Commit commit; - - public RemoteCommitDescription(Remote remote, Commit commit) - { - super(remote); - - this.commit = commit; - } - - public String commitHash() - { - return this.commit.hash(); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteDescription.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteDescription.java deleted file mode 100644 index d276293..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Description/RemoteDescription.java +++ /dev/null @@ -1,18 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description; - -import uk.co.ben_gibson.open.in.git.host.Git.Remote; - -abstract public class RemoteDescription -{ - private Remote remote; - - RemoteDescription(Remote remote) - { - this.remote = remote; - } - - public Remote remote() - { - return remote; - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Exception/RemoteUrlFactoryException.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Exception/RemoteUrlFactoryException.java deleted file mode 100644 index daf02a3..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/Exception/RemoteUrlFactoryException.java +++ /dev/null @@ -1,22 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception; - -import uk.co.ben_gibson.open.in.git.host.Git.RemoteHost; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; - -public class RemoteUrlFactoryException extends OpenInGitHostException -{ - private RemoteUrlFactoryException(String message) - { - super(message); - } - - public static RemoteUrlFactoryException unsupportedRemoteHost(RemoteHost host) - { - return new RemoteUrlFactoryException(String.format("The remote host '%s' is not supported", host.name())); - } - - public static RemoteUrlFactoryException cannotCreateRemoteUrl(String reason) - { - return new RemoteUrlFactoryException(String.format("Cannot create remote url (%s)", reason)); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/GitHubRemoteUrlFactory.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/GitHubRemoteUrlFactory.java deleted file mode 100644 index fffecd9..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/GitHubRemoteUrlFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory; - -import uk.co.ben_gibson.open.in.git.host.Git.*; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; -import java.net.URL; - -public class GitHubRemoteUrlFactory extends AbstractRemoteUrlFactory -{ - public URL createUrl(RemoteCommitDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException - { - Remote remote = description.remote(); - - String path = String.format("/%s/commit/%s", this.cleanPath(remote.url().getPath()), description.commitHash()); - - return this.buildURL(remote, path, null, null, forceSSL); - } - - public URL createUrl(RemoteFileDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException - { - Remote remote = description.remote(); - - String path = String.format("/%s/blob/%s/%s", this.cleanPath(remote.url().getPath()), description.branch(), this.cleanPath(description.file().path())); - String fragment = null; - - if (description.hasLineNumber()) { - fragment = String.format("L%d", description.lineNumber()); - } - - return this.buildURL(remote, path, null, fragment, forceSSL); - } - - public boolean supports(RemoteHost host) - { - return host.gitHub() || host.gitLab(); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/RemoteUrlFactory.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/RemoteUrlFactory.java deleted file mode 100644 index 5a5d576..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/RemoteUrlFactory.java +++ /dev/null @@ -1,16 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory; - -import uk.co.ben_gibson.open.in.git.host.Git.*; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; - -import java.net.URL; - -public interface RemoteUrlFactory -{ - URL createUrl(RemoteCommitDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException; - URL createUrl(RemoteFileDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException; - boolean supports(RemoteHost host); -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/RemoteUrlFactoryProvider.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/RemoteUrlFactoryProvider.java deleted file mode 100644 index 5cf2a3c..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/RemoteUrlFactoryProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory; - -import uk.co.ben_gibson.open.in.git.host.Git.RemoteHost; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; -import java.util.ArrayList; -import java.util.List; - -public class RemoteUrlFactoryProvider -{ - private List factories = new ArrayList(); - - public void registerFactory(RemoteUrlFactory factory) - { - this.factories.add(factory); - } - - public RemoteUrlFactory remoteUrlFactoryForHost(RemoteHost host) throws RemoteUrlFactoryException - { - for (RemoteUrlFactory factory : this.factories) { - if (factory.supports(host)) { - return factory; - } - } - - throw RemoteUrlFactoryException.unsupportedRemoteHost(host); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/StashRemoteUrlFactory.java b/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/StashRemoteUrlFactory.java deleted file mode 100644 index 34c36ae..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/RemoteUrlFactory/StashRemoteUrlFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory; - -import uk.co.ben_gibson.open.in.git.host.Git.*; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; -import java.net.URL; - -public class StashRemoteUrlFactory extends AbstractRemoteUrlFactory -{ - public URL createUrl(RemoteCommitDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException - { - Remote remote = description.remote(); - - String[] parts = this.detailsFromRemoteUrl(remote.url()); - - String project = parts[1]; - String repository = parts[2]; - - String path = String.format("/projects/%s/repos/%s/commits/%s", project, repository, description.commitHash()); - - return this.buildURL(remote, path, null, null, forceSSL); - } - - public URL createUrl(RemoteFileDescription description, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException - { - String[] parts = this.detailsFromRemoteUrl(description.remote().url()); - - String project = parts[1]; - String repository = parts[2]; - - String path = String.format("/projects/%s/repos/%s/browse/%s", project, repository, description.file().path()); - String query = String.format("at=refs/heads/%s", description.branch()); - String fragment = null; - - if (description.hasLineNumber()) { - fragment = description.lineNumber().toString(); - } - - return this.buildURL(description.remote(), path, query, fragment, forceSSL); - } - - public boolean supports(RemoteHost host) - { - return host.stash(); - } - - private String[] detailsFromRemoteUrl(URL url) throws RemoteUrlFactoryException - { - String[] parts = url.getPath().split("/", 3); - - if (parts.length < 3) { - throw RemoteUrlFactoryException.cannotCreateRemoteUrl( - String.format("Could not determine Stash project or repository from remote URL '%s'", url) - ); - } - - return parts; - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/Settings.java b/src/uk/co/ben_gibson/open/in/git/host/Settings.java deleted file mode 100644 index 02fefd2..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/Settings.java +++ /dev/null @@ -1,81 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host; - -import uk.co.ben_gibson.open.in.git.host.Extension.Extension; -import uk.co.ben_gibson.open.in.git.host.Git.RemoteHost; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.components.StoragePathMacros; -import com.intellij.util.xmlb.XmlSerializerUtil; -import java.util.ArrayList; -import java.util.List; - -@State(name = "uk.co.ben_gibson.open.in.git.host.Settings", - storages = {@Storage(id = "default", file = StoragePathMacros.PROJECT_CONFIG_DIR + "/settings.xml")} -) - -/* - * Plugin settings - Getters and Setters required by PersistentStateComponent - */ -public class Settings implements PersistentStateComponent -{ - private RemoteHost remoteHost = RemoteHost.GIT_HUB; - private boolean enableVerboseEventLog = false; - private boolean forceSSL = false; - private List enabledExtensions = new ArrayList<>(); - - public boolean isExtensionEnabled(Extension extension) - { - return this.enabledExtensions.contains(extension.getClass().getName()); - } - - public List getEnabledExtensions() - { - return this.enabledExtensions; - } - - public void setEnabledExtensions(List enabledExtensions) - { - this.enabledExtensions = enabledExtensions; - } - - public boolean getForceSSL() - { - return this.forceSSL; - } - - public void setForceSSL(boolean forceSSL) - { - this.forceSSL = forceSSL; - } - - public boolean getEnableVerboseEventLog() - { - return this.enableVerboseEventLog; - } - - public void setEnableVerboseEventLog(boolean enableVerboseEventLog) - { - this.enableVerboseEventLog = enableVerboseEventLog; - } - - public void setRemoteHost(RemoteHost remoteHost) - { - this.remoteHost = remoteHost; - } - - public RemoteHost getRemoteHost() - { - return this.remoteHost; - } - - public void loadState(Settings state) - { - XmlSerializerUtil.copyBean(state, this); - } - - public Settings getState() - { - return this; - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/Action.java b/src/uk/co/ben_gibson/open/in/git/host/UI/Action/Action.java deleted file mode 100644 index 4e52224..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/Action.java +++ /dev/null @@ -1,54 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.UI.Action; - -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.project.Project; -import uk.co.ben_gibson.open.in.git.host.Container; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; -import uk.co.ben_gibson.open.in.git.host.Logger.Logger; - -abstract class Action extends AnAction -{ - protected abstract boolean shouldActionBeEnabled(AnActionEvent event); - - abstract void actionPerformed(Project project, AnActionEvent event) throws OpenInGitHostException; - - public void actionPerformed(AnActionEvent event) - { - Project project = event.getProject(); - - Logger logger = container().logger(project); - - if (project == null) { - return; - } - - try { - this.actionPerformed(project, event); - } catch (OpenInGitHostException exception) { - logger.exception(exception); - } - } - - public void update(AnActionEvent event) - { - super.update(event); - - if (event.getProject() == null) { - event.getPresentation().setEnabled(false); - return; - } - - event.getPresentation().setEnabledAndVisible(this.shouldActionBeEnabled(event)); - - if (event.getPresentation().isEnabled()) { - event.getPresentation().setIcon(this.container().remoteHost(event.getProject()).icon()); - } - } - - Container container() - { - return ServiceManager.getService(Container.class); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/Exception/ActionException.java b/src/uk/co/ben_gibson/open/in/git/host/UI/Action/Exception/ActionException.java deleted file mode 100644 index 9abb16c..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/Exception/ActionException.java +++ /dev/null @@ -1,21 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.UI.Action.Exception; - -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; - -public class ActionException extends OpenInGitHostException -{ - private ActionException(String message) - { - super(message); - } - - public static ActionException fileNotFound() - { - return new ActionException("File not be found from action event"); - } - - public static ActionException vcsLogNotFound() - { - return new ActionException("VCS log not be found from action event"); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/MenuAction.java b/src/uk/co/ben_gibson/open/in/git/host/UI/Action/MenuAction.java deleted file mode 100644 index b1673ac..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/MenuAction.java +++ /dev/null @@ -1,81 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.UI.Action; - -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import git4idea.GitUtil; -import git4idea.commands.GitImpl; -import git4idea.repo.GitRepository; -import org.jetbrains.annotations.NotNull; -import uk.co.ben_gibson.open.in.git.host.Container; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.UI.Exception.RepositoryNotFoundException; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; -import uk.co.ben_gibson.open.in.git.host.Git.Repository; -import uk.co.ben_gibson.open.in.git.host.UI.Action.Exception.ActionException; -import java.net.URL; - -/** - * An action triggered from the view or right click menu. - */ -public class MenuAction extends Action -{ - public void actionPerformed(Project project, AnActionEvent event) throws OpenInGitHostException - { - Container container = this.container(); - VirtualFile file = event.getData(CommonDataKeys.VIRTUAL_FILE); - - if (file == null) { - throw ActionException.fileNotFound(); - } - - Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); - GitRepository repository = GitUtil.getRepositoryManager(project).getRepositoryForFile(file); - - if (repository == null) { - throw new RepositoryNotFoundException(); - } - - Integer caretPosition = (editor != null) ? editor.getCaretModel().getLogicalPosition().line + 1 : null; - - Repository repo = new Repository(new GitImpl(), repository, Branch.master()); - - Task.Backgroundable task = new Task.Backgroundable(null, "Opening File In Git Host") { - @Override - public void run(@NotNull ProgressIndicator indicator) { - try { - - RemoteFileDescription description = new RemoteFileDescription( - repo.origin(), - repo.currentBranch(), - repo.fileFromVirtualFile(file), - caretPosition - ); - - URL remoteUrl = container.remoteUrlFactory(project).createUrl( - description, - container.settings(project).getForceSSL() - ); - - container.extensionRunner(project).run(remoteUrl); - - } catch (OpenInGitHostException e) { - container.logger(project).exception(e); - } - } - }; - - task.queue(); - } - - protected boolean shouldActionBeEnabled(AnActionEvent event) - { - return (event.getData(CommonDataKeys.VIRTUAL_FILE) != null); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/VcsLogAction.java b/src/uk/co/ben_gibson/open/in/git/host/UI/Action/VcsLogAction.java deleted file mode 100644 index 2f594b4..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/UI/Action/VcsLogAction.java +++ /dev/null @@ -1,84 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.UI.Action; - -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; -import com.intellij.openapi.project.Project; -import com.intellij.vcs.log.VcsFullCommitDetails; -import com.intellij.vcs.log.VcsLog; -import com.intellij.vcs.log.VcsLogDataKeys; -import git4idea.GitUtil; -import git4idea.commands.GitImpl; -import git4idea.repo.GitRepository; -import org.jetbrains.annotations.NotNull; -import uk.co.ben_gibson.open.in.git.host.Container; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.UI.Exception.RepositoryNotFoundException; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; -import uk.co.ben_gibson.open.in.git.host.Git.Commit; -import uk.co.ben_gibson.open.in.git.host.Git.Repository; -import uk.co.ben_gibson.open.in.git.host.UI.Action.Exception.ActionException; -import java.net.URL; -import java.util.List; - -/** - * An action triggered from an VCS log toolbar. - */ -public class VcsLogAction extends Action -{ - public void actionPerformed(Project project, AnActionEvent event) throws OpenInGitHostException - { - Container container = this.container(); - VcsLog vcsLog = event.getData(VcsLogDataKeys.VCS_LOG); - - if (vcsLog == null) { - throw ActionException.vcsLogNotFound(); - } - - VcsFullCommitDetails commit = vcsLog.getSelectedDetails().get(0); - - GitRepository repository = GitUtil.getRepositoryManager(project).getRepositoryForRoot(commit.getRoot()); - - if (repository == null) { - throw new RepositoryNotFoundException(); - } - - Repository repo = new Repository(new GitImpl(), repository, Branch.master()); - - Task.Backgroundable task = new Task.Backgroundable(null, "Opening Commit In Git Host") { - @Override - public void run(@NotNull ProgressIndicator indicator) { - try { - - RemoteCommitDescription description = new RemoteCommitDescription(repo.origin(), new Commit(commit)); - - URL remoteUrl = container.remoteUrlFactory(project).createUrl( - description, - container.settings(project).getForceSSL() - ); - - container.extensionRunner(project).run(remoteUrl); - - } catch (OpenInGitHostException e) { - container.logger(project).exception(e); - } - } - }; - - task.queue(); - } - - protected boolean shouldActionBeEnabled(AnActionEvent event) - { - VcsLog log = event.getData(VcsLogDataKeys.VCS_LOG); - - if (log == null) { - return false; - } - - List commits = log.getSelectedDetails(); - - return commits.size() == 1; - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/UI/Exception/RepositoryNotFoundException.java b/src/uk/co/ben_gibson/open/in/git/host/UI/Exception/RepositoryNotFoundException.java deleted file mode 100644 index 29c4819..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/UI/Exception/RepositoryNotFoundException.java +++ /dev/null @@ -1,15 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.UI.Exception; - -import uk.co.ben_gibson.open.in.git.host.Exception.InvalidConfigurationException; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; - -/** - * Thrown when the git repository could not be found. - */ -public class RepositoryNotFoundException extends OpenInGitHostException implements InvalidConfigurationException -{ - public RepositoryNotFoundException() - { - super("Git repository not found, make sure you have registered your version control root: Preferences → Version Control"); - } -} diff --git a/src/uk/co/ben_gibson/open/in/git/host/UI/Target/SelectInTarget.java b/src/uk/co/ben_gibson/open/in/git/host/UI/Target/SelectInTarget.java deleted file mode 100644 index be98984..0000000 --- a/src/uk/co/ben_gibson/open/in/git/host/UI/Target/SelectInTarget.java +++ /dev/null @@ -1,112 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.UI.Target; - -import com.intellij.ide.SelectInContext; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import git4idea.GitUtil; -import git4idea.commands.GitImpl; -import git4idea.repo.GitRepository; -import org.jetbrains.annotations.NotNull; -import uk.co.ben_gibson.open.in.git.host.Container; -import uk.co.ben_gibson.open.in.git.host.Logger.Logger; -import uk.co.ben_gibson.open.in.git.host.UI.Exception.RepositoryNotFoundException; -import uk.co.ben_gibson.open.in.git.host.Exception.OpenInGitHostException; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; -import uk.co.ben_gibson.open.in.git.host.Git.Repository; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import java.net.URL; - -/** - * Extends the select in target menu. - */ -public class SelectInTarget implements com.intellij.ide.SelectInTarget -{ - public boolean canSelect(SelectInContext context) - { - return true; - } - - public void selectIn(SelectInContext context, boolean requestFocus) - { - Container container = this.container(); - Project project = context.getProject(); - VirtualFile file = context.getVirtualFile(); - - GitRepository repository = GitUtil.getRepositoryManager(project).getRepositoryForFile(file); - - Logger logger = container.logger(project); - - try { - - if (repository == null) { - throw new RepositoryNotFoundException(); - } - - Repository repo = new Repository(new GitImpl(), repository, Branch.master()); - - Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); - - Integer caretPosition = (editor != null) ? editor.getCaretModel().getLogicalPosition().line + 1 : null; - - Task.Backgroundable task = new Task.Backgroundable(null, "Opening Target In Git Host") { - @Override - public void run(@NotNull ProgressIndicator indicator) { - try { - - RemoteFileDescription description = new RemoteFileDescription( - repo.origin(), - repo.currentBranch(), - repo.fileFromVirtualFile(file), - caretPosition - ); - - URL remoteUrl = container.remoteUrlFactory(project).createUrl( - description, - container.settings(project).getForceSSL() - ); - - container.extensionRunner(project).run(remoteUrl); - - } catch (OpenInGitHostException e) { - logger.exception(e); - } - } - }; - - task.queue(); - - } catch (OpenInGitHostException exception) { - logger.exception(exception); - } - } - - private Container container() - { - return ServiceManager.getService(Container.class); - } - - public String getToolWindowId() - { - return null; - } - - public String getMinorViewId() - { - return null; - } - - public float getWeight() - { - return 0; - } - - public String toString() - { - return "Open in Git Host"; - } -} diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/BranchTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Git/BranchTest.java similarity index 77% rename from tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/BranchTest.java rename to tests/unit/uk/co/ben_gibson/git/link/test/Git/BranchTest.java index 89c7083..a90a73e 100644 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/BranchTest.java +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Git/BranchTest.java @@ -1,7 +1,7 @@ -package uk.co.ben_gibson.open.in.git.host.test.Git; +package uk.co.ben_gibson.git.link.test.Git; import junit.framework.TestCase; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; +import uk.co.ben_gibson.git.link.Git.Branch; public class BranchTest extends TestCase { diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/CommitTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Git/CommitTest.java similarity index 86% rename from tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/CommitTest.java rename to tests/unit/uk/co/ben_gibson/git/link/test/Git/CommitTest.java index 40e8f4b..6f2ed92 100644 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/CommitTest.java +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Git/CommitTest.java @@ -1,9 +1,9 @@ -package uk.co.ben_gibson.open.in.git.host.test.Git; +package uk.co.ben_gibson.git.link.test.Git; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsFullCommitDetails; import junit.framework.TestCase; -import uk.co.ben_gibson.open.in.git.host.Git.Commit; +import uk.co.ben_gibson.git.link.Git.Commit; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/FileTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Git/FileTest.java similarity index 81% rename from tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/FileTest.java rename to tests/unit/uk/co/ben_gibson/git/link/test/Git/FileTest.java index 551d748..cf6eb98 100644 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/FileTest.java +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Git/FileTest.java @@ -1,8 +1,8 @@ -package uk.co.ben_gibson.open.in.git.host.test.Git; +package uk.co.ben_gibson.git.link.test.Git; import com.intellij.openapi.vfs.VirtualFile; import junit.framework.TestCase; -import uk.co.ben_gibson.open.in.git.host.Git.File; +import uk.co.ben_gibson.git.link.Git.File; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -12,7 +12,7 @@ public void testReturnsPath() { File file = file("foo/bar.java", "bar.java"); - assertSame("foo/bar.java", file.path()); + assertSame("foo/bar.java", file.pathWithName()); } public void testReturnsName() diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/RemoteTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Git/RemoteTest.java similarity index 92% rename from tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/RemoteTest.java rename to tests/unit/uk/co/ben_gibson/git/link/test/Git/RemoteTest.java index 7f0d844..8945d8b 100644 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Git/RemoteTest.java +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Git/RemoteTest.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host.test.Git; +package uk.co.ben_gibson.git.link.test.Git; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; @@ -8,8 +8,8 @@ import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.Git.Remote; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.Remote; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/tests/unit/uk/co/ben_gibson/git/link/test/PluginTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/PluginTest.java new file mode 100644 index 0000000..04100b2 --- /dev/null +++ b/tests/unit/uk/co/ben_gibson/git/link/test/PluginTest.java @@ -0,0 +1,50 @@ +package uk.co.ben_gibson.git.link.test; + +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import junit.framework.TestCase; +import uk.co.ben_gibson.git.link.Plugin; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PluginTest extends TestCase +{ + public void testToString() + { + Plugin plugin = new Plugin(this.mockPluginDescription("foo", "v2.2", "https://example.com")); + + assertEquals(plugin.toString(), "foo(v2.2)"); + } + + public void testReturnsVersion() + { + Plugin plugin = new Plugin(this.mockPluginDescription("foo", "v2.2", "https://example.com")); + + assertEquals(plugin.version(), "v2.2"); + } + + public void testReturnsDisplayName() + { + Plugin plugin = new Plugin(this.mockPluginDescription("foo", "v2.2", "https://example.com")); + + assertEquals(plugin.displayName(), "foo"); + } + + public void testIssueTracker() + { + Plugin plugin = new Plugin(this.mockPluginDescription("foo", "v2.2", "https://example.com")); + + assertEquals(plugin.issueTracker(), "https://example.com/issues"); + } + + private IdeaPluginDescriptor mockPluginDescription(String name, String version, String vendorUrl) + { + IdeaPluginDescriptor pluginDescriptor = mock(IdeaPluginDescriptor.class); + + when(pluginDescriptor.getName()).thenReturn(name); + when(pluginDescriptor.getVersion()).thenReturn(version); + when(pluginDescriptor.getVendorUrl()).thenReturn(vendorUrl); + + return pluginDescriptor; + } +} diff --git a/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/BitBucketUrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/BitBucketUrlFactoryTest.java new file mode 100644 index 0000000..29c0012 --- /dev/null +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/BitBucketUrlFactoryTest.java @@ -0,0 +1,80 @@ +package uk.co.ben_gibson.git.link.test.Url.Factory; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import uk.co.ben_gibson.git.link.Git.Branch; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Url.Factory.BitBucketUrlFactory; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.UrlFactory; +import java.net.MalformedURLException; + +public class BitBucketUrlFactoryTest extends UrlFactoryTest +{ + @DataProvider + public static Object[][] commitProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new CommitDescription( + mockRemote("https://example@bitbucket.org/foo bar/bar"), + mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") + ), + "https://bitbucket.org/foo%20bar/bar/commits/bd7ab0f04151e7409d77caa296617f97352f36d3" + }, + { + new CommitDescription( + mockRemote("https://bitbucket.org/foo bar/bar"), + mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") + ), + "https://bitbucket.org/foo%20bar/bar/commits/bd7ab0f04151e7409d77caa296617f97352f36d3" + }, + { + new CommitDescription( + mockRemote("http://foo-bar.com/foo/bar"), + mockCommit("0df948a98048a3b30911d974414dfe0ef22a1724") + ), + "http://foo-bar.com/foo/bar/commits/0df948a98048a3b30911d974414dfe0ef22a1724" + }, + }; + } + + @DataProvider + public static Object[][] fileProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new FileDescription( + mockRemote("https://bitbucket.org/foo/bar/"), + Branch.master(), + mockFile("src/Bar.java", "Bar.java"), + 10 + ), + "https://bitbucket.org/foo/bar/src/HEAD/src/Bar.java?at=master#Bar.java-10" + }, + { + new FileDescription( + mockRemote("http://example@bitbucket.org/foo/bar/"), + new Branch("dev"), + mockFile("src/Bar.java", "Bar.java"), + null + ), + "http://bitbucket.org/foo/bar/src/HEAD/src/Bar.java?at=dev" + }, + { + new FileDescription( + mockRemote("https://foo-bar.org/foo bar/bar"), + new Branch("dev-wip[2.0.0]"), + mockFile("/src/foo/Foo Bar Baz.java", "Foo Bar Baz.java"), + null + ), + "https://foo-bar.org/foo%20bar/bar/src/HEAD/src/foo/Foo%20Bar%20Baz.java?at=dev-wip[2.0.0]" + }, + }; + } + + public UrlFactory remoteUrlFactory() + { + return new BitBucketUrlFactory(); + } +} diff --git a/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/CustomUrlFactortTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/CustomUrlFactortTest.java new file mode 100644 index 0000000..e2e60db --- /dev/null +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/CustomUrlFactortTest.java @@ -0,0 +1,68 @@ +package uk.co.ben_gibson.git.link.test.Url.Factory; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import uk.co.ben_gibson.git.link.Git.Branch; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Url.Factory.CustomUrlFactory; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.UrlFactory; + +import java.net.MalformedURLException; + +public class CustomUrlFactortTest extends UrlFactoryTest +{ + @DataProvider + public static Object[][] commitProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new CommitDescription( + UrlFactoryTest.mockRemote("https://example.com/foo bar/baz"), + UrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") + ), + "https://custom.host.com/custom-project/commit/bd7ab0f04151e7409d77caa296617f97352f36d3" + }, + { + new CommitDescription( + UrlFactoryTest.mockRemote("http://custom.example.com/foo/bar"), + UrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") + ), + "https://custom.host.com/custom-project/commit/bd7ab0f04151e7409d77caa296617f97352f36d3" + }, + }; + } + + @DataProvider + public static Object[][] fileProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new FileDescription( + UrlFactoryTest.mockRemote("https://example.com/foo/bar"), + Branch.master(), + UrlFactoryTest.mockFile("src/Bar.java", "Bar.java"), + 10 + ), + "https://custom.host.com/custom-project/master/src/Bar.java#10" + }, + { + new FileDescription( + UrlFactoryTest.mockRemote("http://example.com/foo bar/baz"), + new Branch("dev-wip-[2.0.0]"), + UrlFactoryTest.mockFile("src/Foo Bar.java", "Foo Bar.java"), + null + ), + "https://custom.host.com/custom-project/dev-wip-[2.0.0]/src/Foo Bar.java#" + }, + }; + } + + public UrlFactory remoteUrlFactory() + { + return new CustomUrlFactory( + "https://custom.host.com/custom-project/{branch}/{filePath}/{fileName}#{line}", + "https://custom.host.com/custom-project/commit/{commit}" + ); + } +} diff --git a/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/GitHubUrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/GitHubUrlFactoryTest.java new file mode 100644 index 0000000..e17a3d7 --- /dev/null +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/GitHubUrlFactoryTest.java @@ -0,0 +1,90 @@ +package uk.co.ben_gibson.git.link.test.Url.Factory; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import uk.co.ben_gibson.git.link.Git.Branch; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.GitHubUrlFactory; +import uk.co.ben_gibson.git.link.Url.Factory.UrlFactory; + +import java.net.MalformedURLException; + +public class GitHubUrlFactoryTest extends UrlFactoryTest +{ + @DataProvider + public static Object[][] commitProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new CommitDescription( + mockRemote("https://github.com/foo/bar"), + mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") + ), + "https://github.com/foo/bar/commit/bd7ab0f04151e7409d77caa296617f97352f36d3" + }, + { + new CommitDescription( + mockRemote("https://github.com/foo bar/baz"), + mockCommit("40ec791cdd904557793e200c93f3118043ec18af") + ), + "https://github.com/foo%20bar/baz/commit/40ec791cdd904557793e200c93f3118043ec18af" + }, + { + new CommitDescription( + mockRemote("http://github.com/foo/bar"), + mockCommit("0df948a98048a3b30911d974414dfe0ef22a1724") + ), + "http://github.com/foo/bar/commit/0df948a98048a3b30911d974414dfe0ef22a1724" + }, + }; + } + + @DataProvider + public static Object[][] fileProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new FileDescription( + mockRemote("https://github.com/foo/bar"), + Branch.master(), + mockFile("src/Bar.java", "Bar.java"), + 10 + ), + "https://github.com/foo/bar/blob/master/src/Bar.java#L10" + }, + { + new FileDescription( + mockRemote("https://github.com/foo/bar"), + new Branch("feature-foo-[PRO-123]"), + mockFile("/src/Bar Bar/Baz.java", "Baz.java"), + null + ), + "https://github.com/foo/bar/blob/feature-foo-%5BPRO-123%5D/src/Bar%20Bar/Baz.java" + }, + { + new FileDescription( + mockRemote("http://github.com/foo/bar"), + new Branch("dev"), + mockFile("/src/Bar Bar/Baz.java", "Baz.java"), + null + ), + "http://github.com/foo/bar/blob/dev/src/Bar%20Bar/Baz.java" + }, + { + new FileDescription( + mockRemote("https://github.com/foo bar/baz"), + Branch.master(), + mockFile("需求0920-2017/0928.sql", "0928.sql"), + 15 + ), + "https://github.com/foo%20bar/baz/blob/master/需求0920-2017/0928.sql#L15" + }, + }; + } + + public UrlFactory remoteUrlFactory() + { + return new GitHubUrlFactory(); + } +} diff --git a/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/StashUrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/StashUrlFactoryTest.java new file mode 100644 index 0000000..1f016db --- /dev/null +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/StashUrlFactoryTest.java @@ -0,0 +1,64 @@ +package uk.co.ben_gibson.git.link.test.Url.Factory; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import uk.co.ben_gibson.git.link.Git.Branch; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.UrlFactory; +import uk.co.ben_gibson.git.link.Url.Factory.StashUrlFactory; +import java.net.MalformedURLException; + +public class StashUrlFactoryTest extends UrlFactoryTest +{ + @DataProvider + public static Object[][] commitProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new CommitDescription( + UrlFactoryTest.mockRemote("https://stash.example.com/foo bar/baz"), + UrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") + ), + "https://stash.example.com/projects/foo%20bar/repos/baz/commits/bd7ab0f04151e7409d77caa296617f97352f36d3" + }, + { + new CommitDescription( + UrlFactoryTest.mockRemote("http://stash.example.com/foo/bar"), + UrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") + ), + "http://stash.example.com/projects/foo/repos/bar/commits/bd7ab0f04151e7409d77caa296617f97352f36d3" + }, + }; + } + + @DataProvider + public static Object[][] fileProvider() throws MalformedURLException, RemoteException + { + return new Object[][] { + { + new FileDescription( + UrlFactoryTest.mockRemote("https://stash.example.com/foo/bar"), + Branch.master(), + UrlFactoryTest.mockFile("src/Bar.java", "Bar.java"), + 10 + ), + "https://stash.example.com/projects/foo/repos/bar/browse/src/Bar.java?at=refs/heads/master#10", + }, + { + new FileDescription( + UrlFactoryTest.mockRemote("http://stash.example.com/foo bar/baz"), + new Branch("dev-wip-[2.0.0]"), + UrlFactoryTest.mockFile("src/Foo Bar.java", "Foo Bar.java"), + null + ), + "http://stash.example.com/projects/foo%20bar/repos/baz/browse/src/Foo%20Bar.java?at=refs/heads/dev-wip-[2.0.0]" + }, + }; + } + + public UrlFactory remoteUrlFactory() + { + return new StashUrlFactory(); + } +} diff --git a/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/UrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/UrlFactoryTest.java new file mode 100644 index 0000000..4218cba --- /dev/null +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Factory/UrlFactoryTest.java @@ -0,0 +1,76 @@ +package uk.co.ben_gibson.git.link.test.Url.Factory; + +import com.intellij.openapi.vfs.VirtualFile; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; +import uk.co.ben_gibson.git.link.Git.Commit; +import uk.co.ben_gibson.git.link.Git.Exception.RemoteException; +import uk.co.ben_gibson.git.link.Git.File; +import uk.co.ben_gibson.git.link.Git.Remote; +import uk.co.ben_gibson.git.link.Url.Factory.Description.CommitDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Description.FileDescription; +import uk.co.ben_gibson.git.link.Url.Factory.Exception.UrlFactoryException; +import uk.co.ben_gibson.git.link.Url.Factory.UrlFactory; +import java.net.MalformedURLException; +import java.net.URL; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(DataProviderRunner.class) +public abstract class UrlFactoryTest extends TestCase +{ + public abstract UrlFactory remoteUrlFactory(); + + @Test + @UseDataProvider("commitProvider") + public void testCanCreateUrlToCommit(CommitDescription description, String expected) throws UrlFactoryException, RemoteException, MalformedURLException + { + UrlFactory factory = this.remoteUrlFactory(); + + URL url = factory.createUrl(description); + + assertEquals(expected, url.toString()); + } + + @Test + @UseDataProvider("fileProvider") + public void testCanCreateUrlToFile(FileDescription description, String expected) throws UrlFactoryException, RemoteException, MalformedURLException + { + UrlFactory factory = this.remoteUrlFactory(); + + URL url = factory.createUrl(description); + + assertEquals(expected, url.toString()); + } + + static Remote mockRemote(String originUrl) throws MalformedURLException, RemoteException + { + Remote remote = mock(Remote.class); + + when(remote.url()).thenReturn(new URL(originUrl)); + + return remote; + } + + static Commit mockCommit(String hash) + { + Commit commit = mock(Commit.class); + + when(commit.hash()).thenReturn(hash); + + return commit; + } + + static File mockFile(String path, String name) + { + VirtualFile virtualFile = mock(VirtualFile.class); + + when(virtualFile.getName()).thenReturn(name); + when(virtualFile.getPath()).thenReturn(path); + + return new File(path, virtualFile); + } +} diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Extension/CopyToClipboardExtensionTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Handler/CopyToClipboardHandlerTest.java similarity index 56% rename from tests/unit/uk/co/ben_gibson/open/in/git/host/test/Extension/CopyToClipboardExtensionTest.java rename to tests/unit/uk/co/ben_gibson/git/link/test/Url/Handler/CopyToClipboardHandlerTest.java index b9ea4bd..529b512 100644 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Extension/CopyToClipboardExtensionTest.java +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Handler/CopyToClipboardHandlerTest.java @@ -1,19 +1,20 @@ -package uk.co.ben_gibson.open.in.git.host.test.Extension; +package uk.co.ben_gibson.git.link.test.Url.Handler; import junit.framework.TestCase; -import uk.co.ben_gibson.open.in.git.host.Extension.CopyToClipboardExtension; -import uk.co.ben_gibson.open.in.git.host.Extension.Exception.ExtensionException; -import uk.co.ben_gibson.open.in.git.host.Extension.Extension; +import uk.co.ben_gibson.git.link.Url.Handler.Exception.UrlHandlerException; +import uk.co.ben_gibson.git.link.Url.Handler.CopyToClipboardHandler; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; import java.awt.*; import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.net.MalformedURLException; import java.net.URL; import static org.mockito.Mockito.*; -public class CopyToClipboardExtensionTest extends TestCase +public class CopyToClipboardHandlerTest extends TestCase { - public void testCopiesUrlToClipboard() throws MalformedURLException, ExtensionException + public void testCopiesUrlToClipboard() throws MalformedURLException, UrlHandlerException { URL url = new URL("https://example.com"); @@ -22,9 +23,9 @@ public void testCopiesUrlToClipboard() throws MalformedURLException, ExtensionEx when(toolkit.getSystemClipboard()).thenReturn(clipboard); - Extension extension = new CopyToClipboardExtension(toolkit); + UrlHandler handler = new CopyToClipboardHandler(toolkit); - extension.run(url); + handler.handle(url); verify(clipboard, times(1)).setContents(any(StringSelection.class), isNull()); } diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Extension/OpenInBrowserExtensionTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Handler/OpenInBrowserHandlerTest.java similarity index 71% rename from tests/unit/uk/co/ben_gibson/open/in/git/host/test/Extension/OpenInBrowserExtensionTest.java rename to tests/unit/uk/co/ben_gibson/git/link/test/Url/Handler/OpenInBrowserHandlerTest.java index 7ae769e..18100cf 100644 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/Extension/OpenInBrowserExtensionTest.java +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Handler/OpenInBrowserHandlerTest.java @@ -1,4 +1,4 @@ -package uk.co.ben_gibson.open.in.git.host.test.Extension; +package uk.co.ben_gibson.git.link.test.Url.Handler; import com.intellij.ide.browsers.BrowserLauncher; import com.tngtech.java.junit.dataprovider.DataProvider; @@ -7,25 +7,25 @@ import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; -import uk.co.ben_gibson.open.in.git.host.Extension.Exception.ExtensionException; -import uk.co.ben_gibson.open.in.git.host.Extension.Extension; -import uk.co.ben_gibson.open.in.git.host.Extension.OpenInBrowserExtension; +import uk.co.ben_gibson.git.link.Url.Handler.Exception.UrlHandlerException; +import uk.co.ben_gibson.git.link.Url.Handler.UrlHandler; +import uk.co.ben_gibson.git.link.Url.Handler.OpenInBrowserHandler; import static org.mockito.Mockito.*; import java.net.MalformedURLException; import java.net.URL; @RunWith(DataProviderRunner.class) -public class OpenInBrowserExtensionTest extends TestCase +public class OpenInBrowserHandlerTest extends TestCase { @Test @UseDataProvider("urlProvider") - public void testOpensInBrowser(URL url, String expected) throws MalformedURLException, ExtensionException + public void testOpensInBrowser(URL url, String expected) throws MalformedURLException, UrlHandlerException { BrowserLauncher browserLauncher = mock(BrowserLauncher.class); - Extension extension = new OpenInBrowserExtension(browserLauncher); + UrlHandler handler = new OpenInBrowserHandler(browserLauncher); - extension.run(url); + handler.handle(url); verify(browserLauncher, times(1)).open(expected); } diff --git a/tests/unit/uk/co/ben_gibson/git/link/test/Url/Modifier/HttpsUrlModifierTest.java b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Modifier/HttpsUrlModifierTest.java new file mode 100644 index 0000000..221d02f --- /dev/null +++ b/tests/unit/uk/co/ben_gibson/git/link/test/Url/Modifier/HttpsUrlModifierTest.java @@ -0,0 +1,49 @@ +package uk.co.ben_gibson.git.link.test.Url.Modifier; + +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import junit.framework.TestCase; +import org.junit.Test; +import org.junit.runner.RunWith; +import uk.co.ben_gibson.git.link.Url.Modifier.Exception.ModifierException; +import uk.co.ben_gibson.git.link.Url.Modifier.HttpsUrlModifier; +import uk.co.ben_gibson.git.link.Url.Modifier.UrlModifier; +import java.net.MalformedURLException; +import java.net.URL; + +@RunWith(DataProviderRunner.class) +public class HttpsUrlModifierTest extends TestCase +{ + @Test + @UseDataProvider("urlProvider") + public void testForcesHttpsProtocol(URL url, String expected) throws ModifierException + { + UrlModifier modifier = new HttpsUrlModifier(); + + assertEquals(expected, modifier.modify(url).toString()); + } + + @DataProvider + public static Object[][] urlProvider() throws MalformedURLException + { + return new Object[][] { + { + new URL("http://example.com"), + "https://example.com", + }, + { + new URL("https://example.com"), + "https://example.com", + }, + { + new URL("http://github.com/foo%20bar/baz/blob/master/需求0920-2017/0928.sql#L15"), + "https://github.com/foo%20bar/baz/blob/master/需求0920-2017/0928.sql#L15" + }, + { + new URL( "http://stash.example.com/projects/foo/repos/bar/browse/src/Bar.java?at=refs/heads/master#10"), + "https://stash.example.com/projects/foo/repos/bar/browse/src/Bar.java?at=refs/heads/master#10" + }, + }; + } +} diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/PluginTest.java b/tests/unit/uk/co/ben_gibson/open/in/git/host/test/PluginTest.java deleted file mode 100644 index 8b3ce1a..0000000 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/PluginTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.test; - -import com.intellij.ide.plugins.IdeaPluginDescriptor; -import junit.framework.TestCase; -import uk.co.ben_gibson.open.in.git.host.Plugin; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class PluginTest extends TestCase -{ - public void testToString() - { - Plugin plugin = new Plugin("foo", "v2.2"); - - assertEquals(plugin.toString(), "foo(v2.2)"); - } - - public void testReturnsVersion() - { - Plugin plugin = new Plugin("foo", "v2.2"); - - assertEquals(plugin.version(), "v2.2"); - } - - public void testReturnsDisplayName() - { - Plugin plugin = new Plugin("foo", "v2.2"); - - assertEquals(plugin.displayName(), "foo"); - } - - public void testCanBeCreatedFromIdeaPluginDescriptor() - { - - IdeaPluginDescriptor pluginDescriptor = mock(IdeaPluginDescriptor.class); - - when(pluginDescriptor.getName()).thenReturn("bar"); - when(pluginDescriptor.getVersion()).thenReturn("v1.0.2"); - - Plugin plugin = new Plugin(pluginDescriptor); - - assertEquals(plugin.displayName(), "bar"); - assertEquals(plugin.version(), "v1.0.2"); - } -} diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/BitBucketRemoteUrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/BitBucketRemoteUrlFactoryTest.java deleted file mode 100644 index b792956..0000000 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/BitBucketRemoteUrlFactoryTest.java +++ /dev/null @@ -1,95 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.test.RemoteUrlFactory; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.RemoteUrlFactory; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.BitBucketRemoteUrlFactory; - -import java.net.MalformedURLException; - -public class BitBucketRemoteUrlFactoryTest extends RemoteUrlFactoryTest -{ - @DataProvider - public static Object[][] commitProvider() throws MalformedURLException, RemoteException - { - return new Object[][] { - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("https://example@bitbucket.org/foo bar/bar"), - RemoteUrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") - ), - "https://bitbucket.org/foo%20bar/bar/commits/bd7ab0f04151e7409d77caa296617f97352f36d3", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("https://bitbucket.org/foo bar/bar"), - RemoteUrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") - ), - "https://bitbucket.org/foo%20bar/bar/commits/bd7ab0f04151e7409d77caa296617f97352f36d3", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("http://foo-bar.com/foo/bar"), - RemoteUrlFactoryTest.mockCommit("0df948a98048a3b30911d974414dfe0ef22a1724") - ), - "http://foo-bar.com/foo/bar/commits/0df948a98048a3b30911d974414dfe0ef22a1724", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("http://bitbucket.com/foo/bar"), - RemoteUrlFactoryTest.mockCommit("0df948a98048a3b30911d974414dfe0ef22a1724") - ), - "https://bitbucket.com/foo/bar/commits/0df948a98048a3b30911d974414dfe0ef22a1724", - true - }, - }; - } - - @DataProvider - public static Object[][] fileProvider() throws MalformedURLException, RemoteException - { - return new Object[][] { - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("https://bitbucket.org/foo/bar/"), - Branch.master(), - RemoteUrlFactoryTest.mockFile("src/Bar.java", "Bar.java"), - 10 - ), - "https://bitbucket.org/foo/bar/src/HEAD/src/Bar.java?at=master#Bar.java-10", - false - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("http://example@bitbucket.org/foo/bar/"), - new Branch("dev"), - RemoteUrlFactoryTest.mockFile("src/Bar.java", "Bar.java"), - null - ), - "http://bitbucket.org/foo/bar/src/HEAD/src/Bar.java?at=dev", - false - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("http://foo-bar.org/foo bar/bar"), - new Branch("dev-wip[2.0.0]"), - RemoteUrlFactoryTest.mockFile("/src/foo/Foo Bar Baz.java", "Foo Bar Baz.java"), - null - ), - "https://foo-bar.org/foo%20bar/bar/src/HEAD/src/foo/Foo%20Bar%20Baz.java?at=dev-wip[2.0.0]", - true - }, - }; - } - - public RemoteUrlFactory remoteUrlFactory() - { - return new BitBucketRemoteUrlFactory(); - } -} diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/GitHubRemoteUrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/GitHubRemoteUrlFactoryTest.java deleted file mode 100644 index 339435c..0000000 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/GitHubRemoteUrlFactoryTest.java +++ /dev/null @@ -1,115 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.test.RemoteUrlFactory; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.RemoteUrlFactory; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.GitHubRemoteUrlFactory; - -import java.net.MalformedURLException; - -public class GitHubRemoteUrlFactoryTest extends RemoteUrlFactoryTest -{ - @DataProvider - public static Object[][] commitProvider() throws MalformedURLException, RemoteException - { - return new Object[][] { - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("https://github.com/foo/bar"), - RemoteUrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") - ), - "https://github.com/foo/bar/commit/bd7ab0f04151e7409d77caa296617f97352f36d3", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("https://github.com/foo bar/baz"), - RemoteUrlFactoryTest.mockCommit("40ec791cdd904557793e200c93f3118043ec18af") - ), - "https://github.com/foo%20bar/baz/commit/40ec791cdd904557793e200c93f3118043ec18af", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("http://github.com/foo/bar"), - RemoteUrlFactoryTest.mockCommit("0df948a98048a3b30911d974414dfe0ef22a1724") - ), - "http://github.com/foo/bar/commit/0df948a98048a3b30911d974414dfe0ef22a1724", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("http://github.com/foo/bar"), - RemoteUrlFactoryTest.mockCommit("0df948a98048a3b30911d974414dfe0ef22a1724") - ), - "https://github.com/foo/bar/commit/0df948a98048a3b30911d974414dfe0ef22a1724", - true - }, - }; - } - - @DataProvider - public static Object[][] fileProvider() throws MalformedURLException, RemoteException - { - return new Object[][] { - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("https://github.com/foo/bar"), - Branch.master(), - RemoteUrlFactoryTest.mockFile("src/Bar.java", "Bar.java"), - 10 - ), - "https://github.com/foo/bar/blob/master/src/Bar.java#L10", - false - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("https://github.com/foo/bar"), - new Branch("feature-foo-[PRO-123]"), - RemoteUrlFactoryTest.mockFile("/src/Bar Bar/Baz.java", "Baz.java"), - null - ), - "https://github.com/foo/bar/blob/feature-foo-%5BPRO-123%5D/src/Bar%20Bar/Baz.java", - false - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("http://github.com/foo/bar"), - new Branch("dev"), - RemoteUrlFactoryTest.mockFile("/src/Bar Bar/Baz.java", "Baz.java"), - null - ), - "http://github.com/foo/bar/blob/dev/src/Bar%20Bar/Baz.java", - false - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("https://github.com/foo bar/baz"), - Branch.master(), - RemoteUrlFactoryTest.mockFile("resources/Bar Baz.java", "Bar Baz.java"), - null - ), - "https://github.com/foo%20bar/baz/blob/master/resources/Bar%20Baz.java", - true - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("https://github.com/foo bar/baz"), - Branch.master(), - RemoteUrlFactoryTest.mockFile("需求0920-2017/0928.sql", "0928.sql"), - 15 - ), - "https://github.com/foo%20bar/baz/blob/master/需求0920-2017/0928.sql#L15", - true - }, - }; - } - - public RemoteUrlFactory remoteUrlFactory() - { - return new GitHubRemoteUrlFactory(); - } -} diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/RemoteUrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/RemoteUrlFactoryTest.java deleted file mode 100644 index 039e0f0..0000000 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/RemoteUrlFactoryTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.test.RemoteUrlFactory; - -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import junit.framework.TestCase; -import org.junit.Test; -import org.junit.runner.RunWith; -import uk.co.ben_gibson.open.in.git.host.Git.*; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Exception.RemoteUrlFactoryException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.RemoteUrlFactory; -import java.net.MalformedURLException; -import java.net.URL; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@RunWith(DataProviderRunner.class) -public abstract class RemoteUrlFactoryTest extends TestCase -{ - public abstract RemoteUrlFactory remoteUrlFactory(); - - @Test - @UseDataProvider("commitProvider") - public void testCanCreateUrlToCommit(RemoteCommitDescription description, String expected, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException, MalformedURLException - { - RemoteUrlFactory factory = this.remoteUrlFactory(); - - URL url = factory.createUrl(description, forceSSL); - - assertEquals(expected, url.toString()); - } - - @Test - @UseDataProvider("fileProvider") - public void testCanCreateUrlToFile(RemoteFileDescription description, String expected, boolean forceSSL) throws RemoteUrlFactoryException, RemoteException, MalformedURLException - { - RemoteUrlFactory factory = this.remoteUrlFactory(); - - URL url = factory.createUrl(description, forceSSL); - - assertEquals(expected, url.toString()); - } - - static Remote mockRemote(String originUrl) throws MalformedURLException, RemoteException - { - Remote remote = mock(Remote.class); - - when(remote.url()).thenReturn(new URL(originUrl)); - - return remote; - } - - static Commit mockCommit(String hash) - { - Commit commit = mock(Commit.class); - - when(commit.hash()).thenReturn(hash); - - return commit; - } - - static File mockFile(String path, String name) - { - File file = mock(File.class); - - when(file.name()).thenReturn(name); - when(file.path()).thenReturn(path); - - return file; - } -} diff --git a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/StashRemoteUrlFactoryTest.java b/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/StashRemoteUrlFactoryTest.java deleted file mode 100644 index 196eb9d..0000000 --- a/tests/unit/uk/co/ben_gibson/open/in/git/host/test/RemoteUrlFactory/StashRemoteUrlFactoryTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package uk.co.ben_gibson.open.in.git.host.test.RemoteUrlFactory; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import uk.co.ben_gibson.open.in.git.host.Git.Branch; -import uk.co.ben_gibson.open.in.git.host.Git.Exception.RemoteException; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteCommitDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.Description.RemoteFileDescription; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.RemoteUrlFactory; -import uk.co.ben_gibson.open.in.git.host.RemoteUrlFactory.StashRemoteUrlFactory; - -import java.net.MalformedURLException; - -public class StashRemoteUrlFactoryTest extends RemoteUrlFactoryTest -{ - @DataProvider - public static Object[][] commitProvider() throws MalformedURLException, RemoteException - { - return new Object[][] { - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("https://stash.example.com/foo bar/baz"), - RemoteUrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") - ), - "https://stash.example.com/projects/foo%20bar/repos/baz/commits/bd7ab0f04151e7409d77caa296617f97352f36d3", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("http://stash.example.com/foo/bar"), - RemoteUrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") - ), - "http://stash.example.com/projects/foo/repos/bar/commits/bd7ab0f04151e7409d77caa296617f97352f36d3", - false - }, - { - new RemoteCommitDescription( - RemoteUrlFactoryTest.mockRemote("http://stash.example.com/foo/bar"), - RemoteUrlFactoryTest.mockCommit("bd7ab0f04151e7409d77caa296617f97352f36d3") - ), - "https://stash.example.com/projects/foo/repos/bar/commits/bd7ab0f04151e7409d77caa296617f97352f36d3", - true - }, - }; - } - - @DataProvider - public static Object[][] fileProvider() throws MalformedURLException, RemoteException - { - return new Object[][] { - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("https://stash.example.com/foo/bar"), - Branch.master(), - RemoteUrlFactoryTest.mockFile("src/Bar.java", "Bar.java"), - 10 - ), - "https://stash.example.com/projects/foo/repos/bar/browse/src/Bar.java?at=refs/heads/master#10", - false - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("http://stash.example.com/foo bar/baz"), - new Branch("dev-wip-[2.0.0]"), - RemoteUrlFactoryTest.mockFile("src/Foo Bar.java", "Foo Bar.java"), - null - ), - "http://stash.example.com/projects/foo%20bar/repos/baz/browse/src/Foo%20Bar.java?at=refs/heads/dev-wip-[2.0.0]", - false - }, - { - new RemoteFileDescription( - RemoteUrlFactoryTest.mockRemote("http://stash.example.com/foo/bar"), - new Branch("dev"), - RemoteUrlFactoryTest.mockFile("Foo.java", "Foo.java"), - null - ), - "https://stash.example.com/projects/foo/repos/bar/browse/Foo.java?at=refs/heads/dev", - true - }, - }; - } - - public RemoteUrlFactory remoteUrlFactory() - { - return new StashRemoteUrlFactory(); - } -}