Browse Source

Upgrade to bitbucket server 4.0.1 (WIP)

pull/40/head
Adrian Gonzalez 9 years ago
parent
commit
fc5316370c
  1. 4
      README.md
  2. 134
      pom.xml
  3. 12
      src/main/java/com/englishtown/bitbucket/hook/DefaultPasswordEncryptor.java
  4. 4
      src/main/java/com/englishtown/bitbucket/hook/DefaultSettingsReflectionHelper.java
  5. 66
      src/main/java/com/englishtown/bitbucket/hook/MirrorRepositoryHook.java
  6. 2
      src/main/java/com/englishtown/bitbucket/hook/PasswordEncryptor.java
  7. 8
      src/main/java/com/englishtown/bitbucket/hook/PasswordHandler.java
  8. 4
      src/main/java/com/englishtown/bitbucket/hook/SettingsReflectionHelper.java
  9. 20
      src/main/resources/atlassian-plugin.xml
  10. 2
      src/main/resources/bitbucket-hook-mirror.properties
  11. 16
      src/main/resources/static/mirror-repository-hook.soy
  12. 2
      src/test/java/com/englishtown/bitbucket/hook/DefaultPasswordEncryptorTest.java
  13. 107
      src/test/java/com/englishtown/bitbucket/hook/DefaultSettingsReflectionHelperTest.java
  14. 108
      src/test/java/com/englishtown/bitbucket/hook/MirrorRepositoryHookTest.java
  15. 4
      src/test/java/com/englishtown/bitbucket/hook/PasswordHandlerTest.java
  16. 36
      src/test/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelperTest.java

4
README.md

@ -1,8 +1,8 @@
[![Build Status](https://travis-ci.org/englishtown/stash-hook-mirror.png)](https://travis-ci.org/englishtown/stash-hook-mirror)
#Stash Repository Hook for Mirroring
#Bitbucket Server Repository Hook for Mirroring
The following is a plugin for Atlassian Stash to provide repository mirroring to a remote repository.
The following is a plugin for Atlassian Bitbucket Server to provide repository mirroring to a remote repository.
* `atlas-run` -- installs this plugin into the product and starts it on localhost

134
pom.xml

@ -6,15 +6,15 @@
<groupId>com.englishtown</groupId>
<artifactId>stash-hook-mirror</artifactId>
<version>1.10.0-SNAPSHOT</version>
<version>2.0.0-SNAPSHOT</version>
<organization>
<name>Englishtown</name>
<url>http://www.englishtown.com/</url>
</organization>
<name>Repository Mirror Plugin for Stash</name>
<description>A Stash repository hook for mirroring to one or more remote repositories.</description>
<name>Repository Mirror Plugin for Bitbucket Server</name>
<description>A Bitbucket Server repository hook for mirroring to one or more remote repositories.</description>
<url>https://github.com/englishtown/stash-hook-mirror</url>
<inceptionYear>2013</inceptionYear>
<licenses>
@ -27,26 +27,20 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<stash.version>2.6.0</stash.version>
<stash.data.version>2.6.0</stash.data.version>
<amps.version>4.2.20</amps.version>
<plugin.testrunner.version>1.1.7</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>
<bitbucket.version>4.0.1</bitbucket.version>
<bitbucket.data.version>${bitbucket.version}</bitbucket.data.version>
<atlassian-sal-api.version>3.0.5</atlassian-sal-api.version>
<amps.version>6.1.0</amps.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.atlassian.stash</groupId>
<artifactId>stash-parent</artifactId>
<version>${stash.version}</version>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-parent</artifactId>
<version>${bitbucket.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -55,116 +49,64 @@
<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>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.stash</groupId>
<artifactId>stash-api</artifactId>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.stash</groupId>
<artifactId>stash-spi</artifactId>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-git-api</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>
<groupId>com.atlassian.sal</groupId>
<artifactId>sal-api</artifactId>
<version>${atlassian-sal-api.version}</version>
<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.stash</groupId>
<artifactId>stash-service-impl</artifactId>
<scope>test</scope>
</dependency>
<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>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Workaround for AMPS-1112 -->
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-amps-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-stash-plugin</artifactId>
<artifactId>bitbucket-maven-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>
<id>bitbucket</id>
<instanceId>bitbucket</instanceId>
<version>${bitbucket.version}</version>
<dataVersion>${bitbucket.data.version}</dataVersion>
</product>
</products>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${plugin.compiler.version}</version>
<version>3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
@ -173,12 +115,7 @@
<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>
<url>https://maven.atlassian.com/content/groups/public</url>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
@ -189,14 +126,11 @@
<pluginRepositories>
<pluginRepository>
<id>atlassian-public</id>
<url>https://m2proxy.atlassian.com/repository/public</url>
<url>https://maven.atlassian.com/content/groups/public</url>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>

12
src/main/java/com/englishtown/stash/hook/DefaultPasswordEncryptor.java → src/main/java/com/englishtown/bitbucket/hook/DefaultPasswordEncryptor.java

@ -1,13 +1,13 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.sal.api.pluginsettings.PluginSettings;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
/**
* Service to encrypt/decrypt git user passwords
@ -29,11 +29,11 @@ public class DefaultPasswordEncryptor implements PasswordEncryptor {
if (value == null || value.toString().isEmpty()) {
KeyGenerator gen = KeyGenerator.getInstance("AES");
secretKey = gen.generateKey();
keyBase64 = Base64.encodeBase64String(secretKey.getEncoded());
keyBase64 = Base64.getEncoder().encodeToString(secretKey.getEncoded());
pluginSettings.put(SETTINGS_CRYPTO_KEY, keyBase64);
} else {
keyBase64 = value.toString();
byte[] data = Base64.decodeBase64(keyBase64);
byte[] data = Base64.getDecoder().decode(keyBase64);
secretKey = new SecretKeySpec(data, 0, data.length, "AES");
}
@ -92,7 +92,7 @@ public class DefaultPasswordEncryptor implements PasswordEncryptor {
}
try {
byte[] encryptedData = runCipher(password.getBytes("UTF-8"), true);
return ENCRYPTED_PREFIX + Base64.encodeBase64String(encryptedData);
return ENCRYPTED_PREFIX + Base64.getEncoder().encodeToString(encryptedData);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
@ -104,7 +104,7 @@ public class DefaultPasswordEncryptor implements PasswordEncryptor {
return password;
}
try {
byte[] encryptedData = Base64.decodeBase64(password.substring(ENCRYPTED_PREFIX.length()));
byte[] encryptedData = Base64.getDecoder().decode(password.substring(ENCRYPTED_PREFIX.length()));
byte[] clearData = runCipher(encryptedData, false);
return new String(clearData, "UTF-8");
} catch (UnsupportedEncodingException e) {

4
src/main/java/com/englishtown/stash/hook/DefaultSettingsReflectionHelper.java → src/main/java/com/englishtown/bitbucket/hook/DefaultSettingsReflectionHelper.java

@ -1,6 +1,6 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.stash.setting.Settings;
import com.atlassian.bitbucket.setting.Settings;
import java.lang.reflect.Field;
import java.util.Map;

66
src/main/java/com/englishtown/stash/hook/MirrorRepositoryHook.java → src/main/java/com/englishtown/bitbucket/hook/MirrorRepositoryHook.java

@ -1,20 +1,21 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.bitbucket.hook.repository.AsyncPostReceiveRepositoryHook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookContext;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.repository.RefChange;
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.setting.RepositorySettingsValidator;
import com.atlassian.bitbucket.setting.Settings;
import com.atlassian.bitbucket.setting.SettingsValidationErrors;
import com.atlassian.sal.api.pluginsettings.PluginSettings;
import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
import com.atlassian.stash.hook.repository.AsyncPostReceiveRepositoryHook;
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.repository.RepositoryMetadataService;
import com.atlassian.stash.scm.CommandExitHandler;
import com.atlassian.stash.scm.DefaultCommandExitHandler;
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;
@ -23,7 +24,6 @@ import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -42,33 +42,33 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
static final String SETTING_PASSWORD = "password";
static final int MAX_ATTEMPTS = 5;
private final GitScm gitScm;
private final ScmService scmService;
private final I18nService i18nService;
private final ScheduledExecutorService executor;
private final PasswordEncryptor passwordEncryptor;
private final SettingsReflectionHelper settingsReflectionHelper;
private final RepositoryMetadataService repositoryMetadataService;
private final RepositoryService repositoryService;
private static final Logger logger = LoggerFactory.getLogger(MirrorRepositoryHook.class);
public MirrorRepositoryHook(
GitScm gitScm,
ScmService scmService,
I18nService i18nService,
ScheduledExecutorService executor,
PasswordEncryptor passwordEncryptor,
SettingsReflectionHelper settingsReflectionHelper,
PluginSettingsFactory pluginSettingsFactory,
RepositoryMetadataService repositoryMetadataService
RepositoryService repositoryService
) {
logger.debug("MirrorRepositoryHook: init started");
// Set fields
this.gitScm = gitScm;
this.scmService = scmService;
this.i18nService = i18nService;
this.executor = executor;
this.passwordEncryptor = passwordEncryptor;
this.settingsReflectionHelper = settingsReflectionHelper;
this.repositoryMetadataService = repositoryMetadataService;
this.repositoryService = repositoryService;
// Init password encryptor
PluginSettings pluginSettings = pluginSettingsFactory.createSettingsForKey(PLUGIN_SETTINGS_KEY);
@ -78,11 +78,11 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
}
/**
* Calls the remote stash instance(s) to push the latest changes
* <p/>
* Calls the remote bitbucket 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/>
* <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
@ -104,7 +104,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
}
void runMirrorCommand(MirrorSettings settings, final Repository repository) {
if (repositoryMetadataService.isEmpty(repository)) {
if (repositoryService.isEmpty(repository)) {
return;
}
@ -112,14 +112,19 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
final String password = passwordEncryptor.decrypt(settings.password);
final String authenticatedUrl = getAuthenticatedUrl(settings.mirrorRepoUrl, settings.username, password);
executor.submit(new Callable<Void>() {
executor.submit(new Runnable() {
int attempts = 0;
@Override
public Void call() throws Exception {
public void run() {
try {
GitScmCommandBuilder builder = gitScm.getCommandBuilderFactory().builder(repository);
ScmCommandBuilder obj = scmService.createBuilder(repository);
if (!(obj instanceof GitScmCommandBuilder)) {
logger.warn("Repository " + repository.getName() + " is not a git repo, cannot mirror");
return;
}
GitScmCommandBuilder builder = (GitScmCommandBuilder) obj;
PasswordHandler passwordHandler = getPasswordHandler(builder, password);
// Call push command with the prune flag and refspecs for heads and tags
@ -149,7 +154,6 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
}
}
return null;
}
});
@ -215,7 +219,7 @@ public class MirrorRepositoryHook implements AsyncPostReceiveRepositoryHook, Rep
protected List<MirrorSettings> getMirrorSettings(Settings settings) {
List<MirrorSettings> results = new ArrayList<MirrorSettings>();
List<MirrorSettings> results = new ArrayList<>();
Map<String, Object> allSettings = settings.asMap();
int count = 0;

2
src/main/java/com/englishtown/stash/hook/PasswordEncryptor.java → src/main/java/com/englishtown/bitbucket/hook/PasswordEncryptor.java

@ -1,4 +1,4 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.sal.api.pluginsettings.PluginSettings;

8
src/main/java/com/englishtown/stash/hook/PasswordHandler.java → src/main/java/com/englishtown/bitbucket/hook/PasswordHandler.java

@ -1,8 +1,8 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.stash.scm.CommandErrorHandler;
import com.atlassian.stash.scm.CommandExitHandler;
import com.atlassian.stash.scm.CommandOutputHandler;
import com.atlassian.bitbucket.scm.CommandErrorHandler;
import com.atlassian.bitbucket.scm.CommandExitHandler;
import com.atlassian.bitbucket.scm.CommandOutputHandler;
import com.atlassian.utils.process.StringOutputHandler;
import javax.annotation.Nonnull;

4
src/main/java/com/englishtown/stash/hook/SettingsReflectionHelper.java → src/main/java/com/englishtown/bitbucket/hook/SettingsReflectionHelper.java

@ -1,6 +1,6 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.stash.setting.Settings;
import com.atlassian.bitbucket.setting.Settings;
import java.util.Map;

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

@ -8,31 +8,27 @@
</plugin-info>
<!-- Components that are injected -->
<component-import key="i18nService" interface="com.atlassian.stash.i18n.I18nService"/>
<component-import key="i18nService" interface="com.atlassian.bitbucket.i18n.I18nService"/>
<component-import key="applicationProperties" interface="com.atlassian.sal.api.ApplicationProperties"/>
<component-import key="pluginSettingsFactory" interface="com.atlassian.sal.api.pluginsettings.PluginSettingsFactory"/>
<component-import key="scmService" interface="com.atlassian.bitbucket.scm.ScmService"/>
<component-import key="gitScm" interface="com.atlassian.stash.scm.git.GitScm"/>
<component-import key="gitAgent" interface="com.atlassian.stash.scm.git.GitAgent"/>
<component-import key="gitScmConfig" interface="com.atlassian.stash.scm.git.GitScmConfig"/>
<component-import key="gitCommandBuilderFactory" interface="com.atlassian.stash.scm.git.GitCommandBuilderFactory"/>
<component key="passwordEncryptor" class="com.englishtown.stash.hook.DefaultPasswordEncryptor">
<interface>com.englishtown.stash.hook.PasswordEncryptor</interface>
<component key="passwordEncryptor" class="com.englishtown.bitbucket.hook.DefaultPasswordEncryptor">
<interface>com.englishtown.bitbucket.hook.PasswordEncryptor</interface>
</component>
<component key="settingsReflectionHelper" class="com.englishtown.stash.hook.DefaultSettingsReflectionHelper">
<interface>com.englishtown.stash.hook.SettingsReflectionHelper</interface>
<component key="settingsReflectionHelper" class="com.englishtown.bitbucket.hook.DefaultSettingsReflectionHelper">
<interface>com.englishtown.bitbucket.hook.SettingsReflectionHelper</interface>
</component>
<!-- add our i18n resource -->
<resource type="i18n" name="i18n" location="stash-hook-mirror"/>
<repository-hook name="Mirror Repository Hook" i18n-name-key="mirror-repository-hook.name"
key="mirror-repository-hook" class="com.englishtown.stash.hook.MirrorRepositoryHook">
key="mirror-repository-hook" class="com.englishtown.bitbucket.hook.MirrorRepositoryHook">
<description key="mirror-repository-hook.description">Mirror 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>
<view>com.englishtown.bitbucket.hook.mirrorrepositoryhook.view</view>
<directory location="/static/"/>
</config-form>
</repository-hook>

2
src/main/resources/stash-hook-mirror.properties → src/main/resources/bitbucket-hook-mirror.properties

@ -1,4 +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 one or more remote repositories.
mirror-repository-hook.description=Mirrors a bitbucket repository to one or more remote repositories.

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

@ -1,4 +1,4 @@
{namespace com.englishtown.stash.hook.mirrorrepositoryhook}
{namespace com.englishtown.bitbucket.hook.mirrorrepositoryhook}
/**
* @param config
@ -29,7 +29,7 @@
// Call init method with subview callback
<script>
require("et/hook/mirror").init(com.englishtown.stash.hook.mirrorrepositoryhook.subview, stash.buttons.button);
require("et/hook/mirror").init(com.englishtown.bitbucket.hook.mirrorrepositoryhook.subview, stash.buttons.button);
</script>
{/template}
@ -44,10 +44,10 @@
{param id: 'mirrorRepoUrl' + $index /}
{param value: $config['mirrorRepoUrl' + $index] /}
{param labelContent}
{stash_i18n('com.englishtown.stash.hook.mirror.strings.mirrorRepoUrl.label', 'Mirror Repo URL')}
{stash_i18n('com.englishtown.bitbucket.hook.mirror.strings.mirrorRepoUrl.label', 'Mirror Repo URL')}
{/param}
{param isRequired: true /}
{param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.mirrorRepoUrl.description',
{param descriptionText: stash_i18n('com.englishtown.bitbucket.hook.mirror.strings.mirrorRepoUrl.description',
'The GIT URL (ssh, git, http(s), file) to the remote mirrored repo') /}
{param extraClasses: 'long et-mirror-repo' /}
{param errorTexts: $errors ? $errors['mirrorRepoUrl' + $index] : null /}
@ -56,9 +56,9 @@
{param id: 'username' + $index /}
{param value: $config['username' + $index] /}
{param labelContent}
{stash_i18n('com.englishtown.stash.hook.mirror.strings.username.label', 'Username')}
{stash_i18n('com.englishtown.bitbucket.hook.mirror.strings.username.label', 'Username')}
{/param}
{param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.username.description',
{param descriptionText: stash_i18n('com.englishtown.bitbucket.hook.mirror.strings.username.description',
'The username to use for pushing to the mirror over http(s)') /}
{param extraClasses: 'long' /}
{param errorTexts: $errors ? $errors['username' + $index] : null /}
@ -67,9 +67,9 @@
{param id: 'password' + $index /}
{param value: $config['password' + $index] /}
{param labelContent}
{stash_i18n('com.englishtown.stash.hook.mirror.strings.password.label', 'Password')}
{stash_i18n('com.englishtown.bitbucket.hook.mirror.strings.password.label', 'Password')}
{/param}
{param descriptionText: stash_i18n('com.englishtown.stash.hook.mirror.strings.password.description',
{param descriptionText: stash_i18n('com.englishtown.bitbucket.hook.mirror.strings.password.description',
'The password to use for pushing to the mirror over http(s)') /}
{param extraClasses: 'long' /}
{param errorTexts: $errors ? $errors['password' + $index] : null /}

2
src/test/java/com/englishtown/stash/hook/DefaultPasswordEncryptorTest.java → src/test/java/com/englishtown/bitbucket/hook/DefaultPasswordEncryptorTest.java

@ -1,4 +1,4 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.sal.api.pluginsettings.PluginSettings;
import org.junit.Before;

107
src/test/java/com/englishtown/bitbucket/hook/DefaultSettingsReflectionHelperTest.java

@ -0,0 +1,107 @@
package com.englishtown.bitbucket.hook;
import com.atlassian.bitbucket.setting.Settings;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Unit tests for {@link DefaultSettingsReflectionHelper}
*/
public class DefaultSettingsReflectionHelperTest {
@Test
public void testSet() throws Exception {
DefaultSettingsReflectionHelper helper = new DefaultSettingsReflectionHelper();
Map<String, Object> original = new HashMap<>();
original.put("old", "old");
TestSettings settings = new TestSettings(original);
Map<String, Object> values = new HashMap<>();
values.put("new", "new");
helper.set(values, settings);
assertNull(settings.getString("old"));
assertEquals("new", settings.getString("new"));
}
private static class TestSettings implements Settings {
private final Map<String, Object> values;
public TestSettings(Map<String, Object> values) {
this.values = ImmutableMap.copyOf(values);
}
@Nullable
@Override
public String getString(@Nonnull String key) {
return (String) values.get(key);
}
@Nonnull
@Override
public String getString(@Nonnull String key, @Nonnull String defaultValue) {
return null;
}
@Nullable
@Override
public Boolean getBoolean(@Nonnull String key) {
return null;
}
@Override
public boolean getBoolean(@Nonnull String key, boolean defaultValue) {
return false;
}
@Nullable
@Override
public Integer getInt(@Nonnull String key) {
return null;
}
@Override
public int getInt(@Nonnull String key, int defaultValue) {
return 0;
}
@Nullable
@Override
public Long getLong(@Nonnull String key) {
return null;
}
@Override
public long getLong(@Nonnull String key, long defaultValue) {
return 0;
}
@Nullable
@Override
public Double getDouble(@Nonnull String key) {
return null;
}
@Override
public double getDouble(@Nonnull String key, double defaultValue) {
return 0;
}
@Override
public Map<String, Object> asMap() {
return values;
}
}
}

108
src/test/java/com/englishtown/stash/hook/MirrorRepositoryHookTest.java → src/test/java/com/englishtown/bitbucket/hook/MirrorRepositoryHookTest.java

@ -1,21 +1,19 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.bitbucket.hook.repository.RepositoryHookContext;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.RepositoryService;
import com.atlassian.bitbucket.scm.CommandErrorHandler;
import com.atlassian.bitbucket.scm.CommandExitHandler;
import com.atlassian.bitbucket.scm.CommandOutputHandler;
import com.atlassian.bitbucket.scm.ScmService;
import com.atlassian.bitbucket.scm.git.command.GitCommand;
import com.atlassian.bitbucket.scm.git.command.GitScmCommandBuilder;
import com.atlassian.bitbucket.setting.Settings;
import com.atlassian.bitbucket.setting.SettingsValidationErrors;
import com.atlassian.sal.api.pluginsettings.PluginSettings;
import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;
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.repository.RepositoryMetadataService;
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 org.junit.runner.RunWith;
@ -25,12 +23,9 @@ import org.mockito.Matchers;
import org.mockito.Mock;
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;
@ -45,6 +40,9 @@ public class MirrorRepositoryHookTest {
private MirrorRepositoryHook hook;
private GitScmCommandBuilder builder;
@Mock
private ScmService scmService;
@Mock
private GitCommand<String> cmd;
@Mock
@ -58,17 +56,16 @@ public class MirrorRepositoryHookTest {
@Mock
private PluginSettings pluginSettings;
@Mock
private RepositoryMetadataService repositoryMetadataService;
private RepositoryService repositoryService;
private final String mirrorRepoUrlHttp = "https://stash-mirror.englishtown.com/scm/test/test.git";
private final String mirrorRepoUrlSsh = "ssh://git@stash-mirror.englishtown.com/scm/test/test.git";
private final String mirrorRepoUrlHttp = "https://bitbucket-mirror.englishtown.com/scm/test/test.git";
private final String mirrorRepoUrlSsh = "ssh://git@bitbucket-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";
private final String repository = "https://test-user:test-password@bitbucket-mirror.englishtown.com/scm/test/test.git";
@SuppressWarnings("UnusedDeclaration")
@Captor
ArgumentCaptor<Callable<Void>> argumentCaptor;
ArgumentCaptor<Runnable> argumentCaptor;
@Before
public void setup() {
@ -78,18 +75,14 @@ public class MirrorRepositoryHookTest {
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);
when(builder.<String>build(any(CommandOutputHandler.class))).thenReturn(cmd);
GitScm gitScm = mock(GitScm.class);
when(gitScm.getCommandBuilderFactory()).thenReturn(builderFactory);
doReturn(builder).when(scmService).createBuilder(any());
when(pluginSettingsFactory.createSettingsForKey(anyString())).thenReturn(pluginSettings);
hook = new MirrorRepositoryHook(gitScm, mock(I18nService.class), executor, passwordEncryptor
, settingsReflectionHelper, pluginSettingsFactory, repositoryMetadataService);
hook = new MirrorRepositoryHook(scmService, mock(I18nService.class), executor, passwordEncryptor
, settingsReflectionHelper, pluginSettingsFactory, repositoryService);
}
@ -100,27 +93,26 @@ public class MirrorRepositoryHookTest {
Repository repo = mock(Repository.class);
when(repo.getName()).thenReturn("test");
hook.postReceive(buildContext(repo), new ArrayList<RefChange>());
hook.postReceive(buildContext(repo), new ArrayList<>());
verifyExecutor();
}
@Test
public void testEmptyRepositoriesNotMirrored() {
Repository repo = mock(Repository.class);
when(repositoryMetadataService.isEmpty(repo)).thenReturn(true);
when(repositoryService.isEmpty(repo)).thenReturn(true);
hook.postReceive(buildContext(repo), new ArrayList<RefChange>());
hook.postReceive(buildContext(repo), new ArrayList<>());
verify(executor, never()).submit(Matchers.<Callable<Object>>any());
verify(executor, never()).submit(Matchers.<Runnable>any());
}
@Test
public void testRunMirrorCommand_Retries() throws Exception {
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, settingsReflectionHelper, pluginSettingsFactory, repositoryMetadataService);
when(scmService.createBuilder(any())).thenThrow(new RuntimeException("Intentional unit test exception"));
MirrorRepositoryHook hook = new MirrorRepositoryHook(scmService, mock(I18nService.class), executor,
passwordEncryptor, settingsReflectionHelper, pluginSettingsFactory, repositoryService);
MirrorRepositoryHook.MirrorSettings ms = new MirrorRepositoryHook.MirrorSettings();
ms.mirrorRepoUrl = mirrorRepoUrlHttp;
ms.username = username;
@ -128,29 +120,29 @@ public class MirrorRepositoryHookTest {
hook.runMirrorCommand(ms, mock(Repository.class));
verify(executor).submit(argumentCaptor.capture());
Callable<Void> callable = argumentCaptor.getValue();
callable.call();
Runnable runnable = argumentCaptor.getValue();
runnable.run();
verify(executor, times(1)).schedule(argumentCaptor.capture(), anyInt(), any(TimeUnit.class));
callable = argumentCaptor.getValue();
callable.call();
runnable = argumentCaptor.getValue();
runnable.run();
verify(executor, times(2)).schedule(argumentCaptor.capture(), anyInt(), any(TimeUnit.class));
callable = argumentCaptor.getValue();
callable.call();
runnable = argumentCaptor.getValue();
runnable.run();
verify(executor, times(3)).schedule(argumentCaptor.capture(), anyInt(), any(TimeUnit.class));
callable = argumentCaptor.getValue();
callable.call();
runnable = argumentCaptor.getValue();
runnable.run();
verify(executor, times(4)).schedule(argumentCaptor.capture(), anyInt(), any(TimeUnit.class));
callable = argumentCaptor.getValue();
callable.call();
runnable = argumentCaptor.getValue();
runnable.run();
// Make sure it is only called 5 times
callable.call();
callable.call();
callable.call();
runnable.run();
runnable.run();
runnable.run();
verify(executor, times(4)).schedule(argumentCaptor.capture(), anyInt(), any(TimeUnit.class));
}
@ -158,8 +150,8 @@ public class MirrorRepositoryHookTest {
private void verifyExecutor() throws Exception {
verify(executor).submit(argumentCaptor.capture());
Callable<Void> callable = argumentCaptor.getValue();
callable.call();
Runnable runnable = argumentCaptor.getValue();
runnable.run();
verify(builder, times(1)).command(eq("push"));
verify(builder, times(1)).argument(eq("--prune"));
@ -193,8 +185,8 @@ public class MirrorRepositoryHookTest {
.thenReturn("")
.thenReturn(mirrorRepoUrlHttp)
.thenReturn("invalid uri")
.thenReturn("http://should-not:have-user@stash-mirror.englishtown.com/scm/test/test.git")
.thenReturn("ssh://user@stash-mirror.englishtown.com/scm/test/test.git")
.thenReturn("http://should-not:have-user@bitbucket-mirror.englishtown.com/scm/test/test.git")
.thenReturn("ssh://user@bitbucket-mirror.englishtown.com/scm/test/test.git")
.thenReturn(mirrorRepoUrlSsh)
.thenReturn(mirrorRepoUrlHttp);

4
src/test/java/com/englishtown/stash/hook/PasswordHandlerTest.java → src/test/java/com/englishtown/bitbucket/hook/PasswordHandlerTest.java

@ -1,6 +1,6 @@
package com.englishtown.stash.hook;
package com.englishtown.bitbucket.hook;
import com.atlassian.stash.scm.CommandExitHandler;
import com.atlassian.bitbucket.scm.CommandExitHandler;
import org.junit.Before;
import org.junit.Test;

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

@ -1,36 +0,0 @@
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;
/**
* Unit tests for {@link DefaultSettingsReflectionHelper}
*/
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"));
}
}
Loading…
Cancel
Save