Adrian Gonzalez
12 years ago
commit
1f0025c66e
12 changed files with 705 additions and 0 deletions
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT) |
||||
Copyright © 2013 Englishtown <opensource@englishtown.com> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the “Software”), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in |
||||
all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
THE SOFTWARE. |
@ -0,0 +1,14 @@
|
||||
#Stash Repository Hook for Mirroring |
||||
|
||||
The following is a plugin for Atlassian Stash to provide repository mirroring to a remote repository. |
||||
|
||||
|
||||
* atlas-run -- installs this plugin into the product and starts it on localhost |
||||
* atlas-debug -- same as atlas-run, but allows a debugger to attach at port 5005 |
||||
* atlas-cli -- after atlas-run or atlas-debug, opens a Maven command line window: |
||||
- 'pi' reinstalls the plugin into the running product instance |
||||
* atlas-help -- prints description for all commands in the SDK |
||||
|
||||
Full documentation is always available at: |
||||
|
||||
https://developer.atlassian.com/display/DOCS/Introduction+to+the+Atlassian+Plugin+SDK |
@ -0,0 +1,185 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<groupId>com.englishtown</groupId> |
||||
<artifactId>stash-hook-mirror</artifactId> |
||||
<version>1.0.0-SNAPSHOT</version> |
||||
|
||||
<organization> |
||||
<name>Englishtown</name> |
||||
<url>http://www.englishtown.com/</url> |
||||
</organization> |
||||
|
||||
<name>Stash Mirror Plugin</name> |
||||
<description>A stash repository hook for mirroring to a remote repository.</description> |
||||
<packaging>atlassian-plugin</packaging> |
||||
|
||||
<properties> |
||||
<stash.version>2.3.1</stash.version> |
||||
<stash.data.version>2.3.1</stash.data.version> |
||||
<amps.version>4.1.7</amps.version> |
||||
<plugin.testrunner.version>1.1.1</plugin.testrunner.version> |
||||
|
||||
<junit.version>4.10</junit.version> |
||||
<common-lang.version>2.6</common-lang.version> |
||||
<plugin.compiler.version>3.1</plugin.compiler.version> |
||||
<mockito.version>1.8.5</mockito.version> |
||||
<gson.version>2.2.2-atlassian-1</gson.version> |
||||
<jsr311.version>1.1.1</jsr311.version> |
||||
<slf4j.version>1.7.5</slf4j.version> |
||||
</properties> |
||||
|
||||
<dependencyManagement> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.atlassian.stash</groupId> |
||||
<artifactId>stash-parent</artifactId> |
||||
<version>${stash.version}</version> |
||||
<type>pom</type> |
||||
<scope>import</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
</dependencyManagement> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>com.atlassian.stash</groupId> |
||||
<artifactId>stash-scm-git-api</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-api</artifactId> |
||||
<version>${slf4j.version}</version> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.atlassian.stash</groupId> |
||||
<artifactId>stash-scm-git</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.atlassian.stash</groupId> |
||||
<artifactId>stash-api</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.atlassian.stash</groupId> |
||||
<artifactId>stash-spi</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.atlassian.stash</groupId> |
||||
<artifactId>stash-page-objects</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>javax.servlet</groupId> |
||||
<artifactId>servlet-api</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>junit</groupId> |
||||
<artifactId>junit</artifactId> |
||||
<version>${junit.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>commons-lang</groupId> |
||||
<artifactId>commons-lang</artifactId> |
||||
<version>${common-lang.version}</version> |
||||
</dependency> |
||||
<!-- WIRED TEST RUNNER DEPENDENCIES --> |
||||
<dependency> |
||||
<groupId>com.atlassian.plugins</groupId> |
||||
<artifactId>atlassian-plugins-osgi-testrunner</artifactId> |
||||
<version>${plugin.testrunner.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>javax.ws.rs</groupId> |
||||
<artifactId>jsr311-api</artifactId> |
||||
<version>${jsr311.version}</version> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.google.code.gson</groupId> |
||||
<artifactId>gson</artifactId> |
||||
<version>${gson.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.mockito</groupId> |
||||
<artifactId>mockito-all</artifactId> |
||||
<version>${mockito.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-simple</artifactId> |
||||
<version>${slf4j.version}</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>com.atlassian.maven.plugins</groupId> |
||||
<artifactId>maven-stash-plugin</artifactId> |
||||
<version>${amps.version}</version> |
||||
<extensions>true</extensions> |
||||
<configuration> |
||||
<products> |
||||
<product> |
||||
<id>stash</id> |
||||
<instanceId>stash</instanceId> |
||||
<version>${stash.version}</version> |
||||
<dataVersion>${stash.data.version}</dataVersion> |
||||
</product> |
||||
</products> |
||||
</configuration> |
||||
</plugin> |
||||
<plugin> |
||||
<artifactId>maven-compiler-plugin</artifactId> |
||||
<version>${plugin.compiler.version}</version> |
||||
<configuration> |
||||
<source>1.6</source> |
||||
<target>1.6</target> |
||||
</configuration> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
|
||||
<repositories> |
||||
<repository> |
||||
<id>atlassian-public</id> |
||||
<url>https://m2proxy.atlassian.com/repository/public</url> |
||||
<snapshots> |
||||
<enabled>true</enabled> |
||||
<updatePolicy>daily</updatePolicy> |
||||
<checksumPolicy>warn</checksumPolicy> |
||||
</snapshots> |
||||
<releases> |
||||
<enabled>true</enabled> |
||||
<checksumPolicy>warn</checksumPolicy> |
||||
</releases> |
||||
</repository> |
||||
</repositories> |
||||
|
||||
<pluginRepositories> |
||||
<pluginRepository> |
||||
<id>atlassian-public</id> |
||||
<url>https://m2proxy.atlassian.com/repository/public</url> |
||||
<releases> |
||||
<enabled>true</enabled> |
||||
<checksumPolicy>warn</checksumPolicy> |
||||
</releases> |
||||
<snapshots> |
||||
<checksumPolicy>warn</checksumPolicy> |
||||
</snapshots> |
||||
</pluginRepository> |
||||
</pluginRepositories> |
||||
|
||||
</project> |
@ -0,0 +1,151 @@
|
||||
package com.englishtown.stash.hook; |
||||
|
||||
import com.atlassian.stash.hook.repository.AsyncPostReceiveRepositoryHook; |
||||
import com.atlassian.stash.hook.repository.RepositoryHookContext; |
||||
import com.atlassian.stash.i18n.I18nService; |
||||
import com.atlassian.stash.internal.scm.git.GitCommandExitHandler; |
||||
import com.atlassian.stash.repository.RefChange; |
||||
import com.atlassian.stash.repository.Repository; |
||||
import com.atlassian.stash.scm.CommandExitHandler; |
||||
import com.atlassian.stash.scm.git.GitScm; |
||||
import com.atlassian.stash.scm.git.GitScmCommandBuilder; |
||||
import com.atlassian.stash.setting.RepositorySettingsValidator; |
||||
import com.atlassian.stash.setting.Settings; |
||||
import com.atlassian.stash.setting.SettingsValidationErrors; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import javax.annotation.Nonnull; |
||||
import java.net.URI; |
||||
import java.net.URISyntaxException; |
||||
import java.util.Collection; |
||||
|
||||
public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, RepositorySettingsValidator { |
||||
|
||||
static final String SETTING_MIRROR_REPO_URL = "mirrorRepoUrl"; |
||||
static final String SETTING_USERNAME = "username"; |
||||
static final String SETTING_PASSWORD = "password"; |
||||
|
||||
private final GitScm gitScm; |
||||
private final I18nService i18nService; |
||||
private static final Logger logger = LoggerFactory.getLogger(MirrorRepositoryHook.class); |
||||
|
||||
public MirrorRepositoryHook(GitScm gitScm, I18nService i18nService) { |
||||
this.gitScm = gitScm; |
||||
this.i18nService = i18nService; |
||||
} |
||||
|
||||
/** |
||||
* Calls the remote stash instance(s) to push the latest changes |
||||
* <p/> |
||||
* Callback method that is called just after a push is completed (or a pull request accepted). |
||||
* This hook executes <i>after</i> the processing of a push and will not block the user client. |
||||
* <p/> |
||||
* Despite being asynchronous, the user who initiated this change is still available from |
||||
* |
||||
* @param context the context which the hook is being run with |
||||
* @param refChanges the refs that have just been updated |
||||
*/ |
||||
@Override |
||||
public void postReceive( |
||||
@Nonnull RepositoryHookContext context, |
||||
@Nonnull Collection<RefChange> refChanges) { |
||||
|
||||
try { |
||||
logger.debug("MirrorRepositoryHook: postReceive started."); |
||||
|
||||
Settings settings = context.getSettings(); |
||||
String mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL); |
||||
String username = settings.getString(SETTING_USERNAME); |
||||
String password = settings.getString(SETTING_PASSWORD); |
||||
|
||||
URI authenticatedUrl = getAuthenticatedUrl(mirrorRepoUrl, username, password); |
||||
GitScmCommandBuilder builder = gitScm.getCommandBuilderFactory().builder(context.getRepository()); |
||||
CommandExitHandler exitHandler = new GitCommandExitHandler(i18nService, context.getRepository()); |
||||
PasswordHandler passwordHandler = new PasswordHandler(password, exitHandler); |
||||
|
||||
// Call push command with the mirror flag set
|
||||
String result = builder |
||||
.command("push") |
||||
.argument("--mirror") |
||||
.argument(authenticatedUrl.toString()) |
||||
.errorHandler(passwordHandler) |
||||
.exitHandler(passwordHandler) |
||||
.build(passwordHandler) |
||||
.call(); |
||||
|
||||
builder.defaultExitHandler(); |
||||
logger.debug("MirrorRepositoryHook: postReceive completed with result '{}'.", result); |
||||
|
||||
} catch (Exception e) { |
||||
logger.error("MirrorRepositoryHook: Error running mirror hook", e); |
||||
} |
||||
|
||||
} |
||||
|
||||
URI getAuthenticatedUrl(String mirrorRepoUrl, String username, String password) throws URISyntaxException { |
||||
|
||||
URI uri = URI.create(mirrorRepoUrl); |
||||
String userInfo = username + ":" + password; |
||||
|
||||
return new URI(uri.getScheme(), userInfo, uri.getHost(), uri.getPort(), |
||||
uri.getPath(), uri.getQuery(), uri.getFragment()); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Validate the given {@code settings} before they are persisted. |
||||
* |
||||
* @param settings to be validated |
||||
* @param errors callback for reporting validation errors. |
||||
* @param repository the context {@code Repository} the settings will be associated with |
||||
*/ |
||||
@Override |
||||
public void validate( |
||||
@Nonnull Settings settings, |
||||
@Nonnull SettingsValidationErrors errors, |
||||
@Nonnull Repository repository) { |
||||
|
||||
try { |
||||
int count = 0; |
||||
logger.debug("MirrorRepositoryHook: validate started."); |
||||
|
||||
String mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL, ""); |
||||
if (mirrorRepoUrl.isEmpty()) { |
||||
count++; |
||||
errors.addFieldError(SETTING_MIRROR_REPO_URL, "The mirror repo url is required."); |
||||
} else { |
||||
URI uri; |
||||
try { |
||||
uri = URI.create(mirrorRepoUrl); |
||||
if (!uri.getScheme().toLowerCase().startsWith("http") || mirrorRepoUrl.contains("@")) { |
||||
count++; |
||||
errors.addFieldError(SETTING_MIRROR_REPO_URL, "The mirror repo url must be a valid http(s) " + |
||||
"URI and the user should be specified separately."); |
||||
} |
||||
} catch (Exception ex) { |
||||
count++; |
||||
errors.addFieldError(SETTING_MIRROR_REPO_URL, "The mirror repo url must be a valid http(s) URI."); |
||||
} |
||||
} |
||||
|
||||
if (settings.getString(SETTING_USERNAME, "").isEmpty()) { |
||||
count++; |
||||
errors.addFieldError(SETTING_USERNAME, "The username is required."); |
||||
} |
||||
|
||||
if (settings.getString(SETTING_PASSWORD, "").isEmpty()) { |
||||
count++; |
||||
errors.addFieldError(SETTING_PASSWORD, "The password is required."); |
||||
} |
||||
|
||||
logger.debug("MirrorRepositoryHook: validate completed with {} error(s).", count); |
||||
|
||||
} catch (Exception e) { |
||||
logger.error("Error running MirrorRepositoryHook validate.", e); |
||||
errors.addFormError(e.getMessage()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,50 @@
|
||||
package com.englishtown.stash.hook; |
||||
|
||||
import com.atlassian.stash.scm.CommandErrorHandler; |
||||
import com.atlassian.stash.scm.CommandExitHandler; |
||||
import com.atlassian.stash.scm.CommandOutputHandler; |
||||
import com.atlassian.utils.process.StringOutputHandler; |
||||
|
||||
import javax.annotation.Nonnull; |
||||
import javax.annotation.Nullable; |
||||
|
||||
/** |
||||
* Handles removing passwords from output text |
||||
*/ |
||||
class PasswordHandler extends StringOutputHandler |
||||
implements CommandOutputHandler<String>, CommandErrorHandler, CommandExitHandler { |
||||
|
||||
private final String target; |
||||
private final CommandExitHandler exitHandler; |
||||
|
||||
private static final String PASSWORD_REPLACEMENT = ":*****@"; |
||||
|
||||
public PasswordHandler(String password, CommandExitHandler exitHandler) { |
||||
this.exitHandler = exitHandler; |
||||
this.target = ":" + password + "@"; |
||||
} |
||||
|
||||
public String cleanText(String text) { |
||||
if (text == null || text.isEmpty()) { |
||||
return text; |
||||
} |
||||
return text.replace(target, PASSWORD_REPLACEMENT); |
||||
} |
||||
|
||||
@Override |
||||
public String getOutput() { |
||||
return cleanText(super.getOutput()); |
||||
} |
||||
|
||||
@Override |
||||
public void onCancel(@Nonnull String command, int exitCode, @Nullable String stdErr, @Nullable Throwable thrown) { |
||||
exitHandler.onCancel(cleanText(command), exitCode, cleanText(stdErr), thrown); |
||||
} |
||||
|
||||
@Override |
||||
public void onExit(@Nonnull String command, int exitCode, @Nullable String stdErr, @Nullable Throwable thrown) { |
||||
exitHandler.onExit(cleanText(command), exitCode, cleanText(stdErr), thrown); |
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<atlassian-plugin key="${project.groupId}.${project.artifactId}" name="${project.name}" plugins-version="2"> |
||||
<plugin-info> |
||||
<description>${project.description}</description> |
||||
<version>${project.version}</version> |
||||
<vendor name="${project.organization.name}" url="${project.organization.url}"/> |
||||
</plugin-info> |
||||
|
||||
<!-- Components that are injected --> |
||||
<component-import key="gitScm" interface="com.atlassian.stash.scm.git.GitScm" /> |
||||
<component-import key="i18nService" interface="com.atlassian.stash.i18n.I18nService" /> |
||||
|
||||
<!-- add our i18n resource --> |
||||
<resource type="i18n" name="i18n" location="stash-hook-mirror"/> |
||||
|
||||
<!-- import from the product container --> |
||||
<component-import key="applicationProperties" interface="com.atlassian.sal.api.ApplicationProperties"/> |
||||
|
||||
<repository-hook name="Mirror Repository Hook" i18n-name-key="mirror-repository-hook.name" |
||||
key="mirror-repository-hook" class="com.englishtown.stash.hook.MirrorRepositoryHook"> |
||||
<description key="mirror-repository-hook.description">Mirror Repository Hook</description> |
||||
<icon>/icons/mirror-icon.png</icon> |
||||
<config-form name="Mirror Hook Config" key="mirror-repository-hook-config"> |
||||
<view>com.englishtown.stash.hook.mirrorrepositoryhook.view</view> |
||||
<directory location="/static/"/> |
||||
</config-form> |
||||
</repository-hook> |
||||
</atlassian-plugin> |
After Width: | Height: | Size: 27 KiB |
@ -0,0 +1,4 @@
|
||||
#put any key/value pairs here |
||||
my.plugin.name=stash-hook-mirror |
||||
mirror-repository-hook.name=Mirror Hook |
||||
mirror-repository-hook.description=Mirrors a stash repository to a remote repository. |
@ -0,0 +1,44 @@
|
||||
{namespace com.englishtown.stash.hook.mirrorrepositoryhook} |
||||
|
||||
/** |
||||
* @param config |
||||
* @param? errors |
||||
*/ |
||||
{template .view} |
||||
{call aui.form.textField} |
||||
{param id: 'mirrorRepoUrl' /} |
||||
{param value: $config['mirrorRepoUrl'] /} |
||||
{param labelContent} |
||||
{stash_i18n('com.englishtown.stash.hook.mirror.strings.mirrorRepoUrl.label', 'Mirror Repo URL')} |
||||
{/param} |
||||
{param isRequired: true /} |
||||
{param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.mirrorRepoUrl.description', |
||||
'URL to the remote Stash mirrored repo') /} |
||||
{param extraClasses: 'long' /} |
||||
{param errorTexts: $errors ? $errors['mirrorRepoUrl'] : null /} |
||||
{/call} |
||||
{call aui.form.textField} |
||||
{param id: 'username' /} |
||||
{param value: $config['username'] /} |
||||
{param labelContent} |
||||
{stash_i18n('com.englishtown.stash.hook.mirror.strings.username.label', 'Username')} |
||||
{/param} |
||||
{param isRequired: true /} |
||||
{param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.username.description', |
||||
'The username to use for pushing to the mirror') /} |
||||
{param extraClasses: 'long' /} |
||||
{param errorTexts: $errors ? $errors['username'] : null /} |
||||
{/call} |
||||
{call aui.form.passwordField} |
||||
{param id: 'password' /} |
||||
{param value: $config['password'] /} |
||||
{param labelContent} |
||||
{stash_i18n('com.englishtown.stash.hook.mirror.strings.password.label', 'Password')} |
||||
{/param} |
||||
{param isRequired: true /} |
||||
{param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.password.description', |
||||
'The password to use for pushing to the mirror') /} |
||||
{param extraClasses: 'long' /} |
||||
{param errorTexts: $errors ? $errors['password'] : null /} |
||||
{/call} |
||||
{/template} |
@ -0,0 +1,146 @@
|
||||
package com.englishtown.stash.hook; |
||||
|
||||
import com.atlassian.stash.hook.repository.RepositoryHookContext; |
||||
import com.atlassian.stash.i18n.I18nService; |
||||
import com.atlassian.stash.repository.RefChange; |
||||
import com.atlassian.stash.repository.Repository; |
||||
import com.atlassian.stash.scm.CommandErrorHandler; |
||||
import com.atlassian.stash.scm.CommandExitHandler; |
||||
import com.atlassian.stash.scm.CommandOutputHandler; |
||||
import com.atlassian.stash.scm.git.GitCommand; |
||||
import com.atlassian.stash.scm.git.GitCommandBuilderFactory; |
||||
import com.atlassian.stash.scm.git.GitScm; |
||||
import com.atlassian.stash.scm.git.GitScmCommandBuilder; |
||||
import com.atlassian.stash.setting.Settings; |
||||
import com.atlassian.stash.setting.SettingsValidationErrors; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
import java.net.URI; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.mockito.Mockito.*; |
||||
|
||||
/** |
||||
* Unit tests for {@link MirrorRepositoryHook} |
||||
*/ |
||||
public class MirrorRepositoryHookTest { |
||||
|
||||
private MirrorRepositoryHook hook; |
||||
private GitScmCommandBuilder builder; |
||||
private GitCommand<String> cmd; |
||||
|
||||
private final String mirrorRepoUrl = "https://stash-mirror.englishtown.com/scm/test/test.git"; |
||||
private final String username = "test-user"; |
||||
private final String password = "test-password"; |
||||
private final String repository = "https://test-user:test-password@stash-mirror.englishtown.com/scm/test/test.git"; |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Before |
||||
public void setup() { |
||||
|
||||
cmd = mock(GitCommand.class); |
||||
builder = mock(GitScmCommandBuilder.class); |
||||
when(builder.command(anyString())).thenReturn(builder); |
||||
when(builder.argument(anyString())).thenReturn(builder); |
||||
when(builder.errorHandler(any(CommandErrorHandler.class))).thenReturn(builder); |
||||
when(builder.exitHandler(any(CommandExitHandler.class))).thenReturn(builder); |
||||
when(builder.build(any(CommandOutputHandler.class))).thenReturn(cmd); |
||||
|
||||
GitCommandBuilderFactory builderFactory = mock(GitCommandBuilderFactory.class); |
||||
when(builderFactory.builder(any(Repository.class))).thenReturn(builder); |
||||
|
||||
GitScm gitScm = mock(GitScm.class); |
||||
when(gitScm.getCommandBuilderFactory()).thenReturn(builderFactory); |
||||
|
||||
hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class)); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testPostReceive() throws Exception { |
||||
|
||||
Settings settings = mock(Settings.class); |
||||
when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL))).thenReturn(mirrorRepoUrl); |
||||
when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME))).thenReturn(username); |
||||
when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD))).thenReturn(password); |
||||
|
||||
RepositoryHookContext context = mock(RepositoryHookContext.class); |
||||
when(context.getSettings()).thenReturn(settings); |
||||
|
||||
Collection<RefChange> refChanges = new ArrayList<RefChange>(); |
||||
|
||||
hook.postReceive(context, refChanges); |
||||
verify(builder, times(1)).command(eq("push")); |
||||
verify(builder, times(1)).argument(eq("--mirror")); |
||||
verify(builder, times(1)).argument(eq(repository)); |
||||
verify(cmd, times(1)).call(); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testGetAuthenticatedUrl() throws Exception { |
||||
|
||||
URI result; |
||||
|
||||
result = hook.getAuthenticatedUrl(mirrorRepoUrl, username, password); |
||||
assertEquals(repository, result.toString()); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testValidate() throws Exception { |
||||
|
||||
Settings settings = mock(Settings.class); |
||||
|
||||
when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), eq(""))) |
||||
.thenThrow(new RuntimeException()) |
||||
.thenReturn("") |
||||
.thenReturn("invalid uri") |
||||
.thenReturn("http://should-not:have-user@stash-mirror.englishtown.com/scm/test/test.git") |
||||
.thenReturn(mirrorRepoUrl); |
||||
|
||||
when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME), eq(""))) |
||||
.thenReturn("") |
||||
.thenReturn(username); |
||||
|
||||
when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD), eq(""))) |
||||
.thenReturn("") |
||||
.thenReturn(password); |
||||
|
||||
Repository repo = mock(Repository.class); |
||||
SettingsValidationErrors errors; |
||||
|
||||
errors = mock(SettingsValidationErrors.class); |
||||
hook.validate(settings, errors, repo); |
||||
verify(errors, times(1)).addFormError(anyString()); |
||||
|
||||
errors = mock(SettingsValidationErrors.class); |
||||
hook.validate(settings, errors, repo); |
||||
verify(errors, never()).addFormError(anyString()); |
||||
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), anyString()); |
||||
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_USERNAME), anyString()); |
||||
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_PASSWORD), anyString()); |
||||
|
||||
errors = mock(SettingsValidationErrors.class); |
||||
hook.validate(settings, errors, repo); |
||||
verify(errors, never()).addFormError(anyString()); |
||||
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), anyString()); |
||||
verify(errors).addFieldError(anyString(), anyString()); |
||||
|
||||
errors = mock(SettingsValidationErrors.class); |
||||
hook.validate(settings, errors, repo); |
||||
verify(errors, never()).addFormError(anyString()); |
||||
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), anyString()); |
||||
verify(errors).addFieldError(anyString(), anyString()); |
||||
|
||||
errors = mock(SettingsValidationErrors.class); |
||||
hook.validate(settings, errors, repo); |
||||
verify(errors, never()).addFormError(anyString()); |
||||
verify(errors, never()).addFieldError(anyString(), anyString()); |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,59 @@
|
||||
package com.englishtown.stash.hook; |
||||
|
||||
import com.atlassian.stash.scm.CommandExitHandler; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.mockito.Mockito.*; |
||||
|
||||
/** |
||||
* Unit tests for {@link PasswordHandler} |
||||
*/ |
||||
public class PasswordHandlerTest { |
||||
|
||||
@SuppressWarnings("FieldCanBeLocal") |
||||
private final String password = "pwd@123"; |
||||
private final String secretText = "https://test.user:pwd@123@test.englishtown.com/scm/test/test.git"; |
||||
private final String cleanedText = "https://test.user:*****@test.englishtown.com/scm/test/test.git"; |
||||
private CommandExitHandler exitHandler; |
||||
private PasswordHandler handler; |
||||
|
||||
@Before |
||||
public void setup() throws Exception { |
||||
exitHandler = mock(CommandExitHandler.class); |
||||
handler = new PasswordHandler(password, exitHandler); |
||||
} |
||||
|
||||
@Test |
||||
public void testCleanText() throws Exception { |
||||
|
||||
String result = handler.cleanText(secretText); |
||||
assertEquals(cleanedText, result); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testGetOutput() throws Exception { |
||||
|
||||
String result = handler.getOutput(); |
||||
assertEquals("", result); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testOnCancel() throws Exception { |
||||
|
||||
handler.onCancel(secretText, 0, secretText, null); |
||||
verify(exitHandler).onCancel(eq(cleanedText), eq(0), eq(cleanedText), any(Throwable.class)); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testOnExit() throws Exception { |
||||
|
||||
handler.onExit(secretText, 0, secretText, null); |
||||
verify(exitHandler).onExit(eq(cleanedText), eq(0), eq(cleanedText), any(Throwable.class)); |
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue