Browse Source

Merge pull request #7 from englishtown/feature/multi-mirrors

Feature/multi mirrors
pull/21/head
Adrian 11 years ago
parent
commit
9ca56c7467
  1. 9
      README.md
  2. 6
      pom.xml
  3. 36
      src/main/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelper.java
  4. 171
      src/main/java/com/englishtown/stash/hook/MirrorRepositoryHook.java
  5. 23
      src/main/java/com/englishtown/stash/hook/PasswordEncryptor.java
  6. 20
      src/main/java/com/englishtown/stash/hook/SettingsReflectionHelper.java
  7. 3
      src/main/resources/atlassian-plugin.xml
  8. 3
      src/main/resources/static/mirror-repository-hook.css
  9. 41
      src/main/resources/static/mirror-repository-hook.js
  10. 105
      src/main/resources/static/mirror-repository-hook.soy
  11. 40
      src/test/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelperTest.java
  12. 47
      src/test/java/com/englishtown/stash/hook/MirrorRepositoryHookTest.java

9
README.md

@ -5,11 +5,12 @@
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:
* `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-debug --jvm-debug-suspend` -- same as `atlas-debug` but waits for the debugger to attach
* `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
* `atlas-help` -- prints description for all commands in the SDK
Full documentation is always available at:

6
pom.xml

@ -26,6 +26,7 @@
<packaging>atlassian-plugin</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<stash.version>2.3.1</stash.version>
<stash.data.version>2.3.1</stash.data.version>
<amps.version>4.1.7</amps.version>
@ -100,6 +101,11 @@
<version>${common-lang.version}</version>
</dependency>
<!-- WIRED TEST RUNNER DEPENDENCIES -->
<dependency>
<groupId>com.atlassian.stash</groupId>
<artifactId>stash-service-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugins</groupId>
<artifactId>atlassian-plugins-osgi-testrunner</artifactId>

36
src/main/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelper.java

@ -0,0 +1,36 @@
package com.englishtown.stash.hook;
import com.atlassian.stash.setting.Settings;
import java.lang.reflect.Field;
import java.util.Map;
/**
* Default implementation of {@link SettingsReflectionHelper}
*/
public class DefaultSettingsReflectionHelper implements SettingsReflectionHelper {
/**
* Set the values field of the {@link Settings} via reflection
*
* @param values the values to set
* @param settings the settings to set the values field on
*/
@Override
public void set(Map<String, Object> values, Settings settings) {
try {
Field field = settings.getClass().getDeclaredField("values");
field.setAccessible(true);
field.set(settings, values);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
"hook.", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
"hook.", e);
}
}
}

171
src/main/java/com/englishtown/stash/hook/MirrorRepositoryHook.java

@ -18,18 +18,22 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, RepositorySettingsValidator {
protected static class MirrorSettings {
String mirrorRepoUrl;
String username;
String password;
String suffix;
}
public static final String PLUGIN_SETTINGS_KEY = "com.englishtown.stash.hook.mirror";
static final String SETTING_MIRROR_REPO_URL = "mirrorRepoUrl";
static final String SETTING_USERNAME = "username";
@ -40,6 +44,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
private final I18nService i18nService;
private final ScheduledExecutorService executor;
private final PasswordEncryptor passwordEncryptor;
private final SettingsReflectionHelper settingsReflectionHelper;
private static final Logger logger = LoggerFactory.getLogger(MirrorRepositoryHook.class);
public MirrorRepositoryHook(
@ -47,6 +52,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
I18nService i18nService,
ScheduledExecutorService executor,
PasswordEncryptor passwordEncryptor,
SettingsReflectionHelper settingsReflectionHelper,
PluginSettingsFactory pluginSettingsFactory
) {
logger.debug("MirrorRepositoryHook: init started");
@ -56,6 +62,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
this.i18nService = i18nService;
this.executor = executor;
this.passwordEncryptor = passwordEncryptor;
this.settingsReflectionHelper = settingsReflectionHelper;
// Init password encryptor
PluginSettings pluginSettings = pluginSettingsFactory.createSettingsForKey(PLUGIN_SETTINGS_KEY);
@ -82,20 +89,19 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
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);
List<MirrorSettings> mirrorSettings = getMirrorSettings(context.getSettings());
runMirrorCommand(mirrorRepoUrl, username, password, context.getRepository());
for (MirrorSettings settings : mirrorSettings) {
runMirrorCommand(settings, context.getRepository());
}
}
void runMirrorCommand(String mirrorRepoUrl, String username, final String encryptedPassword, final Repository repository) {
void runMirrorCommand(MirrorSettings settings, final Repository repository) {
try {
final String password = passwordEncryptor.decrypt(encryptedPassword);
final URI authenticatedUrl = getAuthenticatedUrl(mirrorRepoUrl, username, password);
final String password = passwordEncryptor.decrypt(settings.password);
final URI authenticatedUrl = getAuthenticatedUrl(settings.mirrorRepoUrl, settings.username, password);
executor.submit(new Callable<Void>() {
@ -140,7 +146,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
}
}
URI getAuthenticatedUrl(String mirrorRepoUrl, String username, String password) throws URISyntaxException {
protected URI getAuthenticatedUrl(String mirrorRepoUrl, String username, String password) throws URISyntaxException {
URI uri = URI.create(mirrorRepoUrl);
String userInfo = username + ":" + password;
@ -164,46 +170,24 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
@Nonnull Repository repository) {
try {
int count = 0;
boolean ok = true;
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.");
}
}
String username = settings.getString(SETTING_USERNAME, "");
if (username.isEmpty()) {
count++;
errors.addFieldError(SETTING_USERNAME, "The username is required.");
}
List<MirrorSettings> mirrorSettings = getMirrorSettings(settings);
String password = settings.getString(SETTING_PASSWORD, "");
if (password.isEmpty()) {
count++;
errors.addFieldError(SETTING_PASSWORD, "The password is required.");
for (MirrorSettings ms : mirrorSettings) {
if (!validate(ms, settings, errors)) {
ok = false;
}
}
// If no errors, run the mirror command
if (count == 0) {
encryptPassword(settings, SETTING_PASSWORD, password);
runMirrorCommand(mirrorRepoUrl, username, password, repository);
if (ok) {
updateSettings(mirrorSettings, settings);
for (MirrorSettings ms : mirrorSettings) {
runMirrorCommand(ms, repository);
}
}
logger.debug("MirrorRepositoryHook: validate completed with {} error(s).", count);
} catch (Exception e) {
logger.error("Error running MirrorRepositoryHook validate.", e);
@ -212,35 +196,80 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
}
void encryptPassword(Settings settings, String settingName, String password) {
protected List<MirrorSettings> getMirrorSettings(Settings settings) {
List<MirrorSettings> results = new ArrayList<MirrorSettings>();
Map<String, Object> allSettings = settings.asMap();
int count = 0;
for (String key : allSettings.keySet()) {
if (key.startsWith(SETTING_MIRROR_REPO_URL)) {
String suffix = key.substring(SETTING_MIRROR_REPO_URL.length());
// Skip if already encrypted
if (passwordEncryptor.isEncrypted(password)) {
return;
MirrorSettings ms = new MirrorSettings();
ms.mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL + suffix, "");
ms.username = settings.getString(SETTING_USERNAME + suffix, "");
ms.password = settings.getString(SETTING_PASSWORD + suffix, "");
ms.suffix = String.valueOf(count++);
results.add(ms);
}
}
try {
// Unfortunately the settings are stored in an immutable map, so need to cheat with reflection
logger.info("Encrypting password");
Field field = settings.getClass().getDeclaredField("values");
field.setAccessible(true);
// Create mutable copy of values, and encrypt the password
@SuppressWarnings("unchecked")
Map<String, Object> values = (Map<String, Object>) field.get(settings);
values = new HashMap<String, Object>(values);
values.put(settingName, passwordEncryptor.encrypt(password));
field.set(settings, values);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
"hook.", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to encrypt the password. Check for an updated version of the mirror " +
"hook.", e);
return results;
}
protected boolean validate(MirrorSettings ms, Settings settings, SettingsValidationErrors errors) {
boolean result = true;
if (ms.mirrorRepoUrl.isEmpty()) {
result = false;
errors.addFieldError(SETTING_MIRROR_REPO_URL + ms.suffix, "The mirror repo url is required.");
} else {
URI uri;
try {
uri = URI.create(ms.mirrorRepoUrl);
if (!uri.getScheme().toLowerCase().startsWith("http") || ms.mirrorRepoUrl.contains("@")) {
result = false;
errors.addFieldError(SETTING_MIRROR_REPO_URL + ms.suffix,
"The mirror repo url must be a valid http(s) URI and the username " +
"should be specified separately.");
}
} catch (Exception ex) {
result = false;
errors.addFieldError(SETTING_MIRROR_REPO_URL + ms.suffix,
"The mirror repo url must be a valid http(s) URI.");
}
}
if (ms.username.isEmpty()) {
result = false;
errors.addFieldError(SETTING_USERNAME + ms.suffix, "The username is required.");
}
if (ms.password.isEmpty()) {
result = false;
errors.addFieldError(SETTING_PASSWORD + ms.suffix, "The password is required.");
}
return result;
}
protected void updateSettings(List<MirrorSettings> mirrorSettings, Settings settings) {
Map<String, Object> values = new HashMap<String, Object>();
// Store each mirror setting
for (MirrorSettings ms : mirrorSettings) {
values.put(SETTING_MIRROR_REPO_URL + ms.suffix, ms.mirrorRepoUrl);
values.put(SETTING_USERNAME + ms.suffix, ms.username);
values.put(SETTING_PASSWORD + ms.suffix, passwordEncryptor.encrypt(ms.password));
}
// Unfortunately the settings are stored in an immutable map, so need to cheat with reflection
settingsReflectionHelper.set(values, settings);
}
}
}

23
src/main/java/com/englishtown/stash/hook/PasswordEncryptor.java

@ -7,12 +7,35 @@ import com.atlassian.sal.api.pluginsettings.PluginSettings;
*/
public interface PasswordEncryptor {
/**
* Initialize the password encryptor with the atlassian plugin settings
*
* @param pluginSettings the plugin settings
*/
void init(PluginSettings pluginSettings);
/**
* Checks whether the password is encrypted
*
* @param password the password to check
* @return true if the password is encrypted
*/
boolean isEncrypted(String password);
/**
* Encrypts the password if it is not already encrypted
*
* @param password the password to encrypt
* @return encrypted password
*/
String encrypt(String password);
/**
* Decrypts the password if it is encrypted
*
* @param password the encrypted password to decrypt
* @return the decrypted password
*/
String decrypt(String password);
}

20
src/main/java/com/englishtown/stash/hook/SettingsReflectionHelper.java

@ -0,0 +1,20 @@
package com.englishtown.stash.hook;
import com.atlassian.stash.setting.Settings;
import java.util.Map;
/**
* Helper service to set {@link Settings}
*/
public interface SettingsReflectionHelper {
/**
* Set the values field of the {@link Settings} via reflection
*
* @param values the values to set
* @param settings the settings to set the values field on
*/
void set(Map<String, Object> values, Settings settings);
}

3
src/main/resources/atlassian-plugin.xml

@ -15,6 +15,9 @@
<component key="passwordEncryptor" class="com.englishtown.stash.hook.DefaultPasswordEncryptor">
<interface>com.englishtown.stash.hook.PasswordEncryptor</interface>
</component>
<component key="settingsReflectionHelper" class="com.englishtown.stash.hook.DefaultSettingsReflectionHelper">
<interface>com.englishtown.stash.hook.SettingsReflectionHelper</interface>
</component>
<!-- add our i18n resource -->
<resource type="i18n" name="i18n" location="stash-hook-mirror"/>

3
src/main/resources/static/mirror-repository-hook.css

@ -0,0 +1,3 @@
.et-remove-button {
margin-left: 5px !important;
}

41
src/main/resources/static/mirror-repository-hook.js

@ -0,0 +1,41 @@
define('et/hook/mirror', ['jquery', 'exports'], function ($, exports) {
exports.init = function (createSubView, createButton) {
$('#et-add-button').click(function () {
try {
var currIndex, index = 0, name, html;
// Determine the current index from the last password input
name = $('div.hook-config-contents input:password').last().attr("name");
if (name && name.length >= 8) {
currIndex = parseInt(name.substring(8));
index = (isNaN(currIndex) ? 0 : currIndex) + 1;
}
// Insert template after last field-group div
html = createSubView({index: index, config: {}, errors: {}});
$('#et-add-button').before(html);
addRemoveButton();
} catch (e) {
alert(e.message);
}
});
function addRemoveButton() {
// Select all fieldset groups that don't have a remove button
var group = $(".et-mirror-group").not(":has(.et-remove-button)");
var html = createButton({name: 'et-remove-button', text: 'Remove', extraClasses: 'et-remove-button'});
group.find('.et-mirror-repo input').after(html);
group.find('.et-remove-button').click(function (e) {
$(e.currentTarget).parents('.et-mirror-group').remove();
})
}
addRemoveButton();
}
});

105
src/main/resources/static/mirror-repository-hook.soy

@ -5,40 +5,77 @@
* @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 /}
// Always add one subview
{call .subview data="all"}
{param index: 0 /}
{/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 /}
// Add additional mirrors, up to 10 total
{foreach $index in [1, 2, 3, 4, 5, 6, 7, 8, 9]}
{if $config['mirrorRepoUrl' + $index] or $config['username' + $index]}
{call .subview data="all"}
{param index: $index /}
{/call}
{/if}
{/foreach}
// Button to add additional mirrors
{call aui.form.button}
{param id: 'et-add-button' /}
{param text: 'Add Mirror' /}
{/call}
// Call init method with subview callback
<script>
require("et/hook/mirror").init(com.englishtown.stash.hook.mirrorrepositoryhook.subview, aui.form.button);
</script>
{/template}
/**
* @param config
* @param? errors
* @param index
*/
{template .subview}
<fieldset class="et-mirror-group">
{call aui.form.textField}
{param id: 'mirrorRepoUrl' + $index /}
{param value: $config['mirrorRepoUrl' + $index] /}
{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 et-mirror-repo' /}
{param errorTexts: $errors ? $errors['mirrorRepoUrl' + $index] : null /}
{/call}
{call aui.form.textField}
{param id: 'username' + $index /}
{param value: $config['username' + $index] /}
{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' + $index] : null /}
{/call}
{call aui.form.passwordField}
{param id: 'password' + $index /}
{param value: $config['password' + $index] /}
{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' + $index] : null /}
{/call}
</fieldset>
{/template}

40
src/test/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelperTest.java

@ -0,0 +1,40 @@
package com.englishtown.stash.hook;
import com.atlassian.stash.internal.setting.MapSettingsBuilder;
import com.atlassian.stash.setting.Settings;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Created with IntelliJ IDEA.
* User: adriangonzalez
* Date: 5/13/13
* Time: 3:54 PM
* To change this template use File | Settings | File Templates.
*/
public class DefaultSettingsReflectionHelperTest {
@Test
public void testSet() throws Exception {
DefaultSettingsReflectionHelper helper = new DefaultSettingsReflectionHelper();
MapSettingsBuilder builder = new MapSettingsBuilder();
Map<String, Object> values = new HashMap<String, Object>();
builder.add("old", "old");
values.put("new", "new");
Settings settings = builder.build();
helper.set(values, settings);
assertNull(settings.getString("old"));
assertEquals("new", settings.getString("new"));
}
}

47
src/test/java/com/englishtown/stash/hook/MirrorRepositoryHookTest.java

@ -26,6 +26,8 @@ import org.mockito.runners.MockitoJUnitRunner;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -48,6 +50,8 @@ public class MirrorRepositoryHookTest {
@Mock
private PasswordEncryptor passwordEncryptor;
@Mock
private SettingsReflectionHelper settingsReflectionHelper;
@Mock
private PluginSettingsFactory pluginSettingsFactory;
@Mock
private PluginSettings pluginSettings;
@ -79,7 +83,8 @@ public class MirrorRepositoryHookTest {
when(pluginSettingsFactory.createSettingsForKey(anyString())).thenReturn(pluginSettings);
hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor, passwordEncryptor, pluginSettingsFactory);
hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor, passwordEncryptor
, settingsReflectionHelper, pluginSettingsFactory);
}
@ -88,10 +93,14 @@ public class MirrorRepositoryHookTest {
when(passwordEncryptor.decrypt(anyString())).thenReturn(password);
Map<String, Object> map = new HashMap<String, Object>();
map.put(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL, "");
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);
when(settings.asMap()).thenReturn(map);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), eq(""))).thenReturn(mirrorRepoUrl);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME), eq(""))).thenReturn(username);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD), eq(""))).thenReturn(password);
Repository repo = mock(Repository.class);
when(repo.getName()).thenReturn("test");
@ -111,8 +120,13 @@ public class MirrorRepositoryHookTest {
GitScm gitScm = mock(GitScm.class);
when(gitScm.getCommandBuilderFactory()).thenThrow(new RuntimeException("Intentional unit test exception"));
MirrorRepositoryHook hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor, passwordEncryptor, pluginSettingsFactory);
hook.runMirrorCommand(mirrorRepoUrl, username, password, mock(Repository.class));
MirrorRepositoryHook hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor,
passwordEncryptor, settingsReflectionHelper, pluginSettingsFactory);
MirrorRepositoryHook.MirrorSettings ms = new MirrorRepositoryHook.MirrorSettings();
ms.mirrorRepoUrl = mirrorRepoUrl;
ms.username = username;
ms.password = password;
hook.runMirrorCommand(ms, mock(Repository.class));
verify(executor).submit(argumentCaptor.capture());
Callable<Void> callable = argumentCaptor.getValue();
@ -171,18 +185,23 @@ public class MirrorRepositoryHookTest {
Settings settings = mock(Settings.class);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), eq("")))
Map<String, Object> map = new HashMap<String, Object>();
map.put(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0", "");
when(settings.asMap()).thenReturn(map);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), eq("")))
.thenThrow(new RuntimeException("Intentional unit test exception"))
.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("")))
when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME + "0"), eq("")))
.thenReturn("")
.thenReturn(username);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD), eq("")))
when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD + "0"), eq("")))
.thenReturn("")
.thenReturn(password);
@ -196,20 +215,20 @@ public class MirrorRepositoryHookTest {
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());
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), anyString());
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_USERNAME + "0"), anyString());
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_PASSWORD + "0"), 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_MIRROR_REPO_URL + "0"), 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(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), anyString());
verify(errors).addFieldError(anyString(), anyString());
when(passwordEncryptor.isEncrypted(anyString())).thenReturn(true);

Loading…
Cancel
Save