Browse Source

Mirror specific refspecs instead of using regular expressions

pull/60/merge
Adrian Gonzalez 7 years ago
parent
commit
0a88e0d2b8
  1. 6
      README.md
  2. 2
      pom.xml
  3. 93
      src/main/java/com/englishtown/bitbucket/hook/MirrorRepositoryHook.java
  4. 4
      src/main/resources/i18n/stash-hook-mirror.properties
  5. 20
      src/main/resources/static/mirror-repository-hook.soy
  6. 9
      src/test/java/com/englishtown/bitbucket/hook/DefaultPasswordEncryptorTest.java
  7. 105
      src/test/java/com/englishtown/bitbucket/hook/MirrorRepositoryHookTest.java

6
README.md

@ -12,11 +12,15 @@ The following is a plugin for Atlassian Bitbucket Server to provide repository m
- 'pi' reinstalls the plugin into the running product instance - '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:
Full documentation is always available at:
https://developer.atlassian.com/display/DOCS/Introduction+to+the+Atlassian+Plugin+SDK https://developer.atlassian.com/display/DOCS/Introduction+to+the+Atlassian+Plugin+SDK
Soy documentation is available here:
https://bitbucket.org/atlassian/aui-adg/wiki/versions/product-version-matrix
https://bitbucket.org/atlassian/aui/src/master/src/soy/form.soy
The plugin can be found on the Atlassian Marketplace here: The plugin can be found on the Atlassian Marketplace here:
https://marketplace.atlassian.com/plugins/com.englishtown.stash-hook-mirror https://marketplace.atlassian.com/plugins/com.englishtown.stash-hook-mirror

2
pom.xml

@ -33,7 +33,7 @@
<bitbucket.version>5.0.2</bitbucket.version> <bitbucket.version>5.0.2</bitbucket.version>
<bitbucket.data.version>${bitbucket.version}</bitbucket.data.version> <bitbucket.data.version>${bitbucket.version}</bitbucket.data.version>
<atlassian-sal-api.version>3.1.0</atlassian-sal-api.version> <atlassian-sal-api.version>3.1.0</atlassian-sal-api.version>
<amps.version>6.3.0</amps.version> <amps.version>6.3.7</amps.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>

93
src/main/java/com/englishtown/bitbucket/hook/MirrorRepositoryHook.java

@ -3,14 +3,20 @@ package com.englishtown.bitbucket.hook;
import com.atlassian.bitbucket.hook.repository.AsyncPostReceiveRepositoryHook; import com.atlassian.bitbucket.hook.repository.AsyncPostReceiveRepositoryHook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookContext; import com.atlassian.bitbucket.hook.repository.RepositoryHookContext;
import com.atlassian.bitbucket.i18n.I18nService; import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.repository.*; import com.atlassian.bitbucket.repository.RefChange;
import com.atlassian.bitbucket.scm.*; import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.RepositoryService;
import com.atlassian.bitbucket.scm.CommandExitHandler;
import com.atlassian.bitbucket.scm.DefaultCommandExitHandler;
import com.atlassian.bitbucket.scm.ScmCommandBuilder;
import com.atlassian.bitbucket.scm.ScmService;
import com.atlassian.bitbucket.scm.git.command.GitScmCommandBuilder; import com.atlassian.bitbucket.scm.git.command.GitScmCommandBuilder;
import com.atlassian.bitbucket.setting.RepositorySettingsValidator; import com.atlassian.bitbucket.setting.RepositorySettingsValidator;
import com.atlassian.bitbucket.setting.Settings; import com.atlassian.bitbucket.setting.Settings;
import com.atlassian.bitbucket.setting.SettingsValidationErrors; import com.atlassian.bitbucket.setting.SettingsValidationErrors;
import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettings;
import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
import com.google.common.base.Strings;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -21,8 +27,6 @@ import java.net.URISyntaxException;
import java.util.*; import java.util.*;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, RepositorySettingsValidator { public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, RepositorySettingsValidator {
@ -31,15 +35,16 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
String username; String username;
String password; String password;
String suffix; String suffix;
String branchesIncludePattern; String refspec;
} }
public static final String PLUGIN_SETTINGS_KEY = "com.englishtown.stash.hook.mirror"; public static final String PLUGIN_SETTINGS_KEY = "com.englishtown.stash.hook.mirror";
static final String SETTING_MIRROR_REPO_URL = "mirrorRepoUrl"; static final String SETTING_MIRROR_REPO_URL = "mirrorRepoUrl";
static final String SETTING_USERNAME = "username"; static final String SETTING_USERNAME = "username";
static final String SETTING_PASSWORD = "password"; static final String SETTING_PASSWORD = "password";
static final String SETTING_BRANCHES_INCLUDE_PATTERN = "branchesIncludePattern"; static final String SETTING_REFSPEC = "refspec";
static final int MAX_ATTEMPTS = 5; static final int MAX_ATTEMPTS = 5;
static final String DEFAULT_REFSPEC = "+refs/heads/*:refs/heads/*";
private final ScmService scmService; private final ScmService scmService;
private final I18nService i18nService; private final I18nService i18nService;
@ -97,12 +102,12 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
List<MirrorSettings> mirrorSettings = getMirrorSettings(context.getSettings()); List<MirrorSettings> mirrorSettings = getMirrorSettings(context.getSettings());
for (MirrorSettings settings : mirrorSettings) { for (MirrorSettings settings : mirrorSettings) {
runMirrorCommand(settings, context.getRepository(), refChanges); runMirrorCommand(settings, context.getRepository());
} }
} }
void runMirrorCommand(MirrorSettings settings, final Repository repository, Collection<RefChange> refChanges) { void runMirrorCommand(MirrorSettings settings, final Repository repository) {
if (repositoryService.isEmpty(repository)) { if (repositoryService.isEmpty(repository)) {
return; return;
} }
@ -129,16 +134,23 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
// Call push command with the prune flag and refspecs for heads and tags // Call push command with the prune flag and refspecs for heads and tags
// Do not use the mirror flag as pull-request refs are included // Do not use the mirror flag as pull-request refs are included
builder.command("push") builder.command("push")
.argument("--prune") // this deletes locally deleted branches .argument("--prune") // this deletes locally deleted branches
.argument("--atomic") // use an atomic transaction to have a consistent state .argument("--atomic") // use an atomic transaction to have a consistent state
.argument(authenticatedUrl) .argument(authenticatedUrl)
.argument("--force") // Canonical repository should always take precedence over mirror .argument("--force") // Canonical repository should always take precedence over mirror
.argument("+refs/tags/*:refs/tags/*") // and tags .argument("+refs/tags/*:refs/tags/*") // and tags
.argument("+refs/notes/*:refs/notes/*"); // and notes .argument("+refs/notes/*:refs/notes/*"); // and notes
// add branch arguments
addBranchArguments(settings, refChanges, builder); // Add refspec args
String refspecs = Strings.isNullOrEmpty(settings.refspec) ? DEFAULT_REFSPEC : settings.refspec;
for (String refspec : refspecs.split("\\s|\\n")) {
if (!Strings.isNullOrEmpty(refspec)) {
builder.argument(refspec);
}
}
builder.errorHandler(passwordHandler) builder.errorHandler(passwordHandler)
.exitHandler(passwordHandler); .exitHandler(passwordHandler);
String result = builder.build(passwordHandler).call(); String result = builder.build(passwordHandler).call();
@ -207,7 +219,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
if (ok) { if (ok) {
updateSettings(mirrorSettings, settings); updateSettings(mirrorSettings, settings);
for (MirrorSettings ms : mirrorSettings) { for (MirrorSettings ms : mirrorSettings) {
runMirrorCommand(ms, repository, Collections.EMPTY_LIST); runMirrorCommand(ms, repository);
} }
} }
@ -232,7 +244,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
ms.mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL + suffix, ""); ms.mirrorRepoUrl = settings.getString(SETTING_MIRROR_REPO_URL + suffix, "");
ms.username = settings.getString(SETTING_USERNAME + suffix, ""); ms.username = settings.getString(SETTING_USERNAME + suffix, "");
ms.password = settings.getString(SETTING_PASSWORD + suffix, ""); ms.password = settings.getString(SETTING_PASSWORD + suffix, "");
ms.branchesIncludePattern = (settings.getString(SETTING_BRANCHES_INCLUDE_PATTERN + suffix, "")); ms.refspec = (settings.getString(SETTING_REFSPEC + suffix, ""));
ms.suffix = String.valueOf(count++); ms.suffix = String.valueOf(count++);
results.add(ms); results.add(ms);
@ -285,12 +297,10 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
ms.password = ms.username = ""; ms.password = ms.username = "";
} }
if (!ms.branchesIncludePattern.isEmpty()) { if (!ms.refspec.isEmpty()) {
try { if (!ms.refspec.contains(":")) {
Pattern.compile(ms.branchesIncludePattern);
} catch (PatternSyntaxException e) {
result = false; result = false;
errors.addFieldError(SETTING_BRANCHES_INCLUDE_PATTERN + ms.suffix, "This is not a valid regular expression."); errors.addFieldError(SETTING_REFSPEC + ms.suffix, "A refspec should be in the form <src>:<dest>.");
} }
} }
@ -306,7 +316,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
values.put(SETTING_MIRROR_REPO_URL + ms.suffix, ms.mirrorRepoUrl); values.put(SETTING_MIRROR_REPO_URL + ms.suffix, ms.mirrorRepoUrl);
values.put(SETTING_USERNAME + ms.suffix, ms.username); values.put(SETTING_USERNAME + ms.suffix, ms.username);
values.put(SETTING_PASSWORD + ms.suffix, (ms.password.isEmpty() ? ms.password : passwordEncryptor.encrypt(ms.password))); values.put(SETTING_PASSWORD + ms.suffix, (ms.password.isEmpty() ? ms.password : passwordEncryptor.encrypt(ms.password)));
values.put(SETTING_BRANCHES_INCLUDE_PATTERN + ms.suffix, ms.branchesIncludePattern); values.put(SETTING_REFSPEC + ms.suffix, ms.refspec);
} }
// Unfortunately the settings are stored in an immutable map, so need to cheat with reflection // Unfortunately the settings are stored in an immutable map, so need to cheat with reflection
@ -330,37 +340,4 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
return new PasswordHandler(password, new DefaultCommandExitHandler(i18nService)); return new PasswordHandler(password, new DefaultCommandExitHandler(i18nService));
} }
private void addBranchArguments(MirrorSettings settings, Collection<RefChange> refChanges, CommandBuilder builder) {
Map<String, String> branchModifyArguments = new HashMap<>();
Map<String, String> branchDeleteArguments = new HashMap<>();
// if an empty list of RefChanges was provided we assume this was caused by triggering after a config change.
// same if no branch pattern was specified we sync all branches
if(refChanges.isEmpty() || settings.branchesIncludePattern.isEmpty()) {
builder.argument("+refs/heads/*:refs/heads/*");
} else {
for (RefChange refChange : refChanges) {
MinimalRef ref = refChange.getRef();
String displayId = ref.getDisplayId();
// branch operations
if (ref.getType().equals(StandardRefType.BRANCH)) {
if (displayId.matches(settings.branchesIncludePattern)) {
if (refChange.getType().equals(RefChangeType.DELETE) && !branchDeleteArguments.containsKey(displayId)) {
branchDeleteArguments.put(displayId, "+:refs/heads/" + displayId);
} else if ((refChange.getType().equals(RefChangeType.ADD) || refChange.getType().equals(RefChangeType.UPDATE)) && !branchModifyArguments.containsKey(displayId)) {
branchModifyArguments.put(displayId, "+refs/heads/" + displayId + ":refs/heads/" + displayId);
}
}
}
}
for (String key : branchDeleteArguments.keySet()) {
builder.argument(branchDeleteArguments.get(key));
}
for (String key : branchModifyArguments.keySet()) {
builder.argument(branchModifyArguments.get(key));
}
}
}
} }

4
src/main/resources/i18n/stash-hook-mirror.properties

@ -11,5 +11,5 @@ mirror-repository-hook.username.description=The username to use for pushing to t
mirror-repository-hook.password.label=Password mirror-repository-hook.password.label=Password
mirror-repository-hook.password.description=The password to use for pushing to the mirror over http(s) mirror-repository-hook.password.description=The password to use for pushing to the mirror over http(s)
mirror-repository-hook.branchesIncludePattern.label=Branches Include Pattern mirror-repository-hook.refspec.label=Refspec
mirror-repository-hook.branchesIncludePattern.description=Regex pattern for branches to include mirror-repository-hook.refspec.description=The git refspec(s) to mirror (defaults to +refs/heads/*:refs/heads/*)

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

@ -48,7 +48,7 @@
{/param} {/param}
{param isRequired: true /} {param isRequired: true /}
{param descriptionText: getText('mirror-repository-hook.mirrorRepoUrl.description') /} {param descriptionText: getText('mirror-repository-hook.mirrorRepoUrl.description') /}
{param extraClasses: 'long et-mirror-repo' /} {param extraClasses: 'et-mirror-repo' /}
{param errorTexts: $errors ? $errors['mirrorRepoUrl' + $index] : null /} {param errorTexts: $errors ? $errors['mirrorRepoUrl' + $index] : null /}
{/call} {/call}
{call aui.form.textField} {call aui.form.textField}
@ -58,7 +58,6 @@
{getText('mirror-repository-hook.username.label')} {getText('mirror-repository-hook.username.label')}
{/param} {/param}
{param descriptionText: getText('mirror-repository-hook.username.description') /} {param descriptionText: getText('mirror-repository-hook.username.description') /}
{param extraClasses: 'long' /}
{param errorTexts: $errors ? $errors['username' + $index] : null /} {param errorTexts: $errors ? $errors['username' + $index] : null /}
{/call} {/call}
{call aui.form.passwordField} {call aui.form.passwordField}
@ -68,20 +67,17 @@
{getText('mirror-repository-hook.password.label')} {getText('mirror-repository-hook.password.label')}
{/param} {/param}
{param descriptionText: getText('mirror-repository-hook.password.description') /} {param descriptionText: getText('mirror-repository-hook.password.description') /}
{param extraClasses: 'long' /}
{param errorTexts: $errors ? $errors['password' + $index] : null /} {param errorTexts: $errors ? $errors['password' + $index] : null /}
{/call} {/call}
{call aui.form.textField} {call aui.form.textareaField}
{param id: 'branchesIncludePattern' + $index /} {param id: 'refspec' + $index /}
{param value: $config['branchesIncludePattern' + $index] /} {param value: $config['refspec' + $index] /}
{param labelContent} {param labelContent}
{getText('mirror-repository-hook.branchesIncludePattern.label')} {getText('mirror-repository-hook.refspec.label')}
{/param} {/param}
{param descriptionText: getText('mirror-repository-hook.branchesIncludePattern.description') /} {param descriptionText: getText('mirror-repository-hook.refspec.description') /}
{param extraClasses: 'long' /} {param fieldWidth: 'long' /}
{param errorTexts: $errors ? $errors['branchesIncludePattern' + $index] : null /} {param errorTexts: $errors ? $errors['refspec' + $index] : null /}
{/call} {/call}
</fieldset> </fieldset>
{/template} {/template}

9
src/test/java/com/englishtown/bitbucket/hook/DefaultPasswordEncryptorTest.java

@ -2,10 +2,11 @@ package com.englishtown.bitbucket.hook;
import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettings;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -13,11 +14,13 @@ import static org.mockito.Mockito.*;
/** /**
* DefaultPasswordEncryptor unit tests * DefaultPasswordEncryptor unit tests
*/ */
@RunWith(MockitoJUnitRunner.class)
public class DefaultPasswordEncryptorTest { public class DefaultPasswordEncryptorTest {
private final static String CRYPTO_KEY = "m3ys5YexQc7irRlmJeCwAw=="; private final static String CRYPTO_KEY = "m3ys5YexQc7irRlmJeCwAw==";
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock @Mock
private PluginSettings pluginSettings; private PluginSettings pluginSettings;

105
src/test/java/com/englishtown/bitbucket/hook/MirrorRepositoryHookTest.java

@ -2,7 +2,8 @@ package com.englishtown.bitbucket.hook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookContext; import com.atlassian.bitbucket.hook.repository.RepositoryHookContext;
import com.atlassian.bitbucket.i18n.I18nService; import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.repository.*; import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.RepositoryService;
import com.atlassian.bitbucket.scm.CommandErrorHandler; import com.atlassian.bitbucket.scm.CommandErrorHandler;
import com.atlassian.bitbucket.scm.CommandExitHandler; import com.atlassian.bitbucket.scm.CommandExitHandler;
import com.atlassian.bitbucket.scm.CommandOutputHandler; import com.atlassian.bitbucket.scm.CommandOutputHandler;
@ -14,15 +15,18 @@ import com.atlassian.bitbucket.setting.SettingsValidationErrors;
import com.atlassian.sal.api.pluginsettings.PluginSettings; import com.atlassian.sal.api.pluginsettings.PluginSettings;
import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory; import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Matchers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -32,12 +36,14 @@ import static org.mockito.Mockito.*;
/** /**
* Unit tests for {@link MirrorRepositoryHook} * Unit tests for {@link MirrorRepositoryHook}
*/ */
@RunWith(MockitoJUnitRunner.class)
public class MirrorRepositoryHookTest { public class MirrorRepositoryHookTest {
private MirrorRepositoryHook hook; private MirrorRepositoryHook hook;
private GitScmCommandBuilder builder; private GitScmCommandBuilder builder;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock @Mock
private ScmService scmService; private ScmService scmService;
@Mock @Mock
@ -60,7 +66,7 @@ public class MirrorRepositoryHookTest {
private final String username = "test-user"; private final String username = "test-user";
private final String password = "test-password"; private final String password = "test-password";
private final String repository = "https://test-user:test-password@bitbucket-mirror.englishtown.com/scm/test/test.git"; private final String repository = "https://test-user:test-password@bitbucket-mirror.englishtown.com/scm/test/test.git";
private final String branchesIncludePattern ="master"; private final String refspec = "+refs/heads/master:refs/heads/master +refs/heads/develop:refs/heads/develop";
@Captor @Captor
ArgumentCaptor<Runnable> argumentCaptor; ArgumentCaptor<Runnable> argumentCaptor;
@ -94,44 +100,6 @@ public class MirrorRepositoryHookTest {
verifyExecutor(); verifyExecutor();
} }
@Test
public void testPostReceiveWithBranchesPatternUpdateOperation() throws Exception {
when(passwordEncryptor.decrypt(anyString())).thenReturn(password);
Repository repo = mock(Repository.class);
RefChange refChange = mock(RefChange.class);
MinimalRef ref = mock(MinimalRef.class);
List<RefChange> refChanges = new ArrayList<>();
refChanges.add(refChange);
when(refChange.getRef()).thenReturn(ref);
when(refChange.getType()).thenReturn(RefChangeType.UPDATE);
when(ref.getType()).thenReturn(StandardRefType.BRANCH);
when(ref.getDisplayId()).thenReturn("master");
hook.postReceive(buildContext(repo), refChanges);
verifyExecutorWithBranchesPatternUpdateOperation();
}
@Test
public void testPostReceiveWithBranchesPatternDeleteOperation() throws Exception {
when(passwordEncryptor.decrypt(anyString())).thenReturn(password);
Repository repo = mock(Repository.class);
RefChange refChange = mock(RefChange.class);
MinimalRef ref = mock(MinimalRef.class);
List<RefChange> refChanges = new ArrayList<>();
refChanges.add(refChange);
when(refChange.getRef()).thenReturn(ref);
when(refChange.getType()).thenReturn(RefChangeType.DELETE);
when(ref.getType()).thenReturn(StandardRefType.BRANCH);
when(ref.getDisplayId()).thenReturn("master");
hook.postReceive(buildContext(repo), refChanges);
verifyExecutorWithBranchesPatternDeleteOperation();
}
@Test @Test
public void testEmptyRepositoriesNotMirrored() { public void testEmptyRepositoriesNotMirrored() {
Repository repo = mock(Repository.class); Repository repo = mock(Repository.class);
@ -139,7 +107,7 @@ public class MirrorRepositoryHookTest {
hook.postReceive(buildContext(repo), new ArrayList<>()); hook.postReceive(buildContext(repo), new ArrayList<>());
verify(executor, never()).submit(Matchers.<Runnable>any()); verify(executor, never()).submit(ArgumentMatchers.<Runnable>any());
} }
@Test @Test
@ -152,7 +120,7 @@ public class MirrorRepositoryHookTest {
ms.mirrorRepoUrl = mirrorRepoUrlHttp; ms.mirrorRepoUrl = mirrorRepoUrlHttp;
ms.username = username; ms.username = username;
ms.password = password; ms.password = password;
hook.runMirrorCommand(ms, mock(Repository.class), Collections.emptyList()); hook.runMirrorCommand(ms, mock(Repository.class));
verify(executor).submit(argumentCaptor.capture()); verify(executor).submit(argumentCaptor.capture());
Runnable runnable = argumentCaptor.getValue(); Runnable runnable = argumentCaptor.getValue();
@ -192,40 +160,11 @@ public class MirrorRepositoryHookTest {
verify(builder, times(1)).argument(eq("--prune")); verify(builder, times(1)).argument(eq("--prune"));
verify(builder, times(1)).argument(eq("--atomic")); verify(builder, times(1)).argument(eq("--atomic"));
verify(builder, times(1)).argument(eq(repository)); verify(builder, times(1)).argument(eq(repository));
verify(builder, times(1)).argument(eq("+refs/heads/*:refs/heads/*")); verify(builder, times(1)).argument(eq("--force"));
verify(builder, times(1)).argument(eq("+refs/tags/*:refs/tags/*")); verify(builder, times(1)).argument(eq("+refs/tags/*:refs/tags/*"));
verify(cmd, times(1)).call(); verify(builder, times(1)).argument(eq("+refs/notes/*:refs/notes/*"));
}
private void verifyExecutorWithBranchesPatternUpdateOperation() throws Exception {
verify(executor).submit(argumentCaptor.capture());
Runnable runnable = argumentCaptor.getValue();
runnable.run();
verify(builder, times(1)).command(eq("push"));
verify(builder, times(1)).argument(eq("--prune"));
verify(builder, times(1)).argument(eq("--atomic"));
verify(builder, times(1)).argument(eq(repository));
verify(builder, times(1)).argument(eq("+refs/heads/master:refs/heads/master")); verify(builder, times(1)).argument(eq("+refs/heads/master:refs/heads/master"));
verify(builder, times(1)).argument(eq("+refs/tags/*:refs/tags/*")); verify(builder, times(1)).argument(eq("+refs/heads/develop:refs/heads/develop"));
verify(cmd, times(1)).call();
}
private void verifyExecutorWithBranchesPatternDeleteOperation() throws Exception {
verify(executor).submit(argumentCaptor.capture());
Runnable runnable = argumentCaptor.getValue();
runnable.run();
verify(builder, times(1)).command(eq("push"));
verify(builder, times(1)).argument(eq("--prune"));
verify(builder, times(1)).argument(eq("--atomic"));
verify(builder, times(1)).argument(eq(repository));
verify(builder, times(1)).argument(eq("+:refs/heads/master"));
verify(builder, times(1)).argument(eq("+refs/tags/*:refs/tags/*"));
verify(cmd, times(1)).call(); verify(cmd, times(1)).call();
} }
@ -270,9 +209,9 @@ public class MirrorRepositoryHookTest {
.thenReturn("") .thenReturn("")
.thenReturn(password); .thenReturn(password);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_BRANCHES_INCLUDE_PATTERN + "0"), eq(""))) when(settings.getString(eq(MirrorRepositoryHook.SETTING_REFSPEC + "0"), eq("")))
.thenReturn("??") .thenReturn("??")
.thenReturn("master") .thenReturn("+refs/heads/master:refs/heads/master")
.thenReturn(""); .thenReturn("");
Repository repo = mock(Repository.class); Repository repo = mock(Repository.class);
@ -289,7 +228,7 @@ public class MirrorRepositoryHookTest {
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), anyString()); verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL + "0"), anyString());
verify(errors, never()).addFieldError(eq(MirrorRepositoryHook.SETTING_USERNAME + "0"), anyString()); verify(errors, never()).addFieldError(eq(MirrorRepositoryHook.SETTING_USERNAME + "0"), anyString());
verify(errors, never()).addFieldError(eq(MirrorRepositoryHook.SETTING_PASSWORD + "0"), anyString()); verify(errors, never()).addFieldError(eq(MirrorRepositoryHook.SETTING_PASSWORD + "0"), anyString());
verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_BRANCHES_INCLUDE_PATTERN + "0"), anyString()); verify(errors).addFieldError(eq(MirrorRepositoryHook.SETTING_REFSPEC + "0"), anyString());
errors = mock(SettingsValidationErrors.class); errors = mock(SettingsValidationErrors.class);
hook.validate(settings, errors, repo); hook.validate(settings, errors, repo);
@ -347,7 +286,7 @@ public class MirrorRepositoryHookTest {
when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), eq(""))).thenReturn(mirrorRepoUrlHttp); when(settings.getString(eq(MirrorRepositoryHook.SETTING_MIRROR_REPO_URL), eq(""))).thenReturn(mirrorRepoUrlHttp);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME), eq(""))).thenReturn(username); when(settings.getString(eq(MirrorRepositoryHook.SETTING_USERNAME), eq(""))).thenReturn(username);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD), eq(""))).thenReturn(password); when(settings.getString(eq(MirrorRepositoryHook.SETTING_PASSWORD), eq(""))).thenReturn(password);
when(settings.getString(eq(MirrorRepositoryHook.SETTING_BRANCHES_INCLUDE_PATTERN), eq(""))).thenReturn(branchesIncludePattern); when(settings.getString(eq(MirrorRepositoryHook.SETTING_REFSPEC), eq(""))).thenReturn(refspec);
return settings; return settings;
} }
} }

Loading…
Cancel
Save