Skip to content

Commit

Permalink
Read deployment configuration from DB
Browse files Browse the repository at this point in the history
Fixes #126
  • Loading branch information
micheljung committed Sep 5, 2017
1 parent df6df5b commit 0c6ed3a
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 114 deletions.
12 changes: 0 additions & 12 deletions src/main/java/com/faforever/api/config/FafApiProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

@Data
@ConfigurationProperties(prefix = "faf-api", ignoreUnknownFields = false)
Expand Down Expand Up @@ -135,16 +133,6 @@ public static class Deployment {
private String repositoriesDirectory;
private String filesDirectoryFormat = "updates_%s_files";
private String forgedAllianceExePath;
private List<DeploymentConfiguration> configurations = new ArrayList<>();

@Data
public static class DeploymentConfiguration {
private String repositoryUrl;
private String branch;
private String modName;
private String modFilesExtension;
private boolean replaceExisting;
}
}

@Data
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/faforever/api/data/domain/FeaturedMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class FeaturedMod {
private int order;
private String gitUrl;
private String gitBranch;
private Boolean replaceExisting;
private String fileExtension;

@Id
@Column(name = "id")
Expand Down Expand Up @@ -62,4 +64,14 @@ public String getGitUrl() {
public String getGitBranch() {
return gitBranch;
}

@Column(name = "replace_existing")
public Boolean isReplaceExisting() {
return replaceExisting;
}

@Column(name = "file_extension")
public String getFileExtension() {
return fileExtension;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.faforever.api.deployment;

import com.faforever.api.config.FafApiProperties;
import com.faforever.api.config.FafApiProperties.Deployment.DeploymentConfiguration;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.faforever.api.data.domain.FeaturedMod;
import com.faforever.api.featuredmods.FeaturedModService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.kohsuke.github.GHDeployment;
Expand All @@ -20,33 +20,33 @@ public class GitHubDeploymentService {

private final ApplicationContext applicationContext;
private final FafApiProperties fafApiProperties;
private final ObjectMapper objectMapper;
private final FeaturedModService featuredModService;

public GitHubDeploymentService(ApplicationContext applicationContext, FafApiProperties fafApiProperties, ObjectMapper objectMapper) {
public GitHubDeploymentService(ApplicationContext applicationContext, FafApiProperties fafApiProperties, FeaturedModService featuredModService) {
this.applicationContext = applicationContext;
this.fafApiProperties = fafApiProperties;
this.objectMapper = objectMapper;
this.featuredModService = featuredModService;
}

@SneakyThrows
public void createDeploymentIfEligible(Push push) {
String ref = push.getRef();
Optional<DeploymentConfiguration> optional = fafApiProperties.getDeployment().getConfigurations().stream()
.filter(configuration ->
push.getRepository().gitHttpTransportUrl().equals(configuration.getRepositoryUrl())
&& push.getRef().replace("refs/heads/", "").equals(configuration.getBranch()))
.findFirst();

Optional<FeaturedMod> optional = featuredModService.findByGitUrlAndGitBranch(
push.getRepository().gitHttpTransportUrl(),
push.getRef().replace("refs/heads/", "")
);

if (!optional.isPresent()) {
log.warn("No configuration present for repository '{}' and ref '{}'", push.getRepository().gitHttpTransportUrl(), push.getRef());
return;
}

GHDeployment ghDeployment = push.getRepository().createDeployment(ref)
.autoMerge(false)
.environment(fafApiProperties.getGitHub().getDeploymentEnvironment())
.payload(objectMapper.writeValueAsString(optional.get()))
.create();
.autoMerge(false)
.environment(fafApiProperties.getGitHub().getDeploymentEnvironment())
.payload(optional.get().getTechnicalName())
.create();

log.info("Created deployment: {}", ghDeployment);
}
Expand All @@ -60,8 +60,12 @@ public void deploy(GHDeployment deployment) {
return;
}

String modName = deployment.getPayload();
FeaturedMod featuredMod = featuredModService.findModByTechnicalName(modName)
.orElseThrow(() -> new IllegalArgumentException("No such mod: " + modName));

applicationContext.getBean(LegacyFeaturedModDeploymentTask.class)
.setConfiguration(objectMapper.readValue(deployment.getPayload(), DeploymentConfiguration.class))
.run();
.setFeaturedMod(featuredMod)
.run();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.faforever.api.config.FafApiProperties;
import com.faforever.api.config.FafApiProperties.Deployment;
import com.faforever.api.config.FafApiProperties.Deployment.DeploymentConfiguration;
import com.faforever.api.data.domain.FeaturedMod;
import com.faforever.api.deployment.git.GitWrapper;
import com.faforever.api.featuredmods.FeaturedModFile;
import com.faforever.api.featuredmods.FeaturedModService;
Expand Down Expand Up @@ -60,7 +60,7 @@ public class LegacyFeaturedModDeploymentTask implements Runnable {
private final FafApiProperties apiProperties;

@Setter
private DeploymentConfiguration configuration;
private FeaturedMod featuredMod;

public LegacyFeaturedModDeploymentTask(GitWrapper gitWrapper, FeaturedModService featuredModService, FafApiProperties apiProperties) {
this.gitWrapper = gitWrapper;
Expand All @@ -71,16 +71,16 @@ public LegacyFeaturedModDeploymentTask(GitWrapper gitWrapper, FeaturedModService
@Override
@SneakyThrows
public void run() {
Assert.state(configuration != null, "Configuration must be set");
String modName = configuration.getModName();
Assert.state(featuredMod != null, "Configuration must be set");
String modName = featuredMod.getTechnicalName();

Assert.state(featuredModService.getFeaturedMods().stream()
.anyMatch(featuredMod -> Objects.equals(featuredMod.getTechnicalName(), modName)), "Unknown mod: " + modName);

String repositoryUrl = configuration.getRepositoryUrl();
String branch = configuration.getBranch();
boolean replaceExisting = configuration.isReplaceExisting();
String modFilesExtension = configuration.getModFilesExtension();
String repositoryUrl = featuredMod.getGitUrl();
String branch = featuredMod.getGitBranch();
boolean replaceExisting = featuredMod.isReplaceExisting();
String modFilesExtension = featuredMod.getFileExtension();
Map<String, Short> fileIds = featuredModService.getFileIds(modName);

log.info("Starting deployment of '{}' from '{}', branch '{}', replaceExisting '{}', modFilesExtension '{}'",
Expand Down Expand Up @@ -137,7 +137,7 @@ private short readModVersion(Path modPath) {
private void verifyVersion(int version, boolean replaceExisting, String modName) {
if (!replaceExisting) {
// Normally I'd create a proper query, but this is a hotfix and a protest against the DB-driven patcher
// Luckily, BiREUS is coming soon.
// Luckily, BiReUS is coming "soon".
OptionalInt existingVersion = featuredModService.getFiles(modName, version).stream()
.mapToInt(FeaturedModFile::getVersion)
.filter(value -> value == version)
Expand Down Expand Up @@ -193,17 +193,17 @@ private StagedFile renameToFinalFile(StagedFile file) {
}

/**
* Creates a ZIP file with the file ending configured in {@link #configuration}. The content of the ZIP file is the
* Creates a ZIP file with the file ending configured in {@link #featuredMod}. The content of the ZIP file is the
* content of the directory. If no file ID is available, an empty optional is returned.
*/
@SneakyThrows
private Optional<StagedFile> packDirectory(Path directory, Short version, Path targetFolder, Map<String, Short> fileIds) {
String directoryName = directory.getFileName().toString();
Path targetNxtFile = targetFolder.resolve(String.format("%s.%d.%s", directoryName, version, configuration.getModFilesExtension()));
Path targetNxtFile = targetFolder.resolve(String.format("%s.%d.%s", directoryName, version, featuredMod.getFileExtension()));
Path tmpNxtFile = toTmpFile(targetNxtFile);

// E.g. "effects.nx2"
String clientFileName = String.format("%s.%s", directoryName, configuration.getModFilesExtension());
String clientFileName = String.format("%s.%s", directoryName, featuredMod.getFileExtension());
Short fileId = fileIds.get(clientFileName);
if (fileId == null) {
log.debug("Skipping folder '{}' because there's no file ID available", directoryName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@
import com.faforever.api.data.domain.FeaturedMod;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface FeaturedModRepository extends JpaRepository<FeaturedMod, Integer> {
Optional<FeaturedMod> findOneByTechnicalName(String name);

Optional<FeaturedMod> findByGitUrlAndGitBranch(String gitUrl, String gitBranch);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
public class FeaturedModService {
Expand Down Expand Up @@ -40,4 +41,12 @@ public void save(String modName, short version, List<FeaturedModFile> featuredMo
public Map<String, Short> getFileIds(String modName) {
return legacyFeaturedModFileRepository.getFileIds(modName);
}

public Optional<FeaturedMod> findModByTechnicalName(String name) {
return featuredModRepository.findOneByTechnicalName(name);
}

public Optional<FeaturedMod> findByGitUrlAndGitBranch(String gitHttpTransportUrl, String gitBranch) {
return featuredModRepository.findByGitUrlAndGitBranch(gitHttpTransportUrl, gitBranch);
}
}
17 changes: 0 additions & 17 deletions src/main/resources/config/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,6 @@ faf-api:
forged-alliance-exe-path: ${FORGED_ALLIANCE_EXE_PATH}
repositories-directory: ${REPOSITORIES_DIRECTORY:build/cache/repos}
featured-mods-target-directory: ${FEATURED_MODS_TARGET_DIRECTORY:build/cache/deployment}
# TODO make this runtime configuration
configurations:
- repositoryUrl: https://github.com/FAForever/fa.git
branch: deploy/faf
modName: faf
modFilesExtension: nx2
replaceExisting: false
- repositoryUrl: https://github.com/FAForever/fa.git
branch: deploy/fafbeta
modName: fafbeta
modFilesExtension: nx4
replaceExisting: true
- repositoryUrl: https://github.com/FAForever/fa.git
branch: deploy/fafdevelop
modName: fafdevelop
modFilesExtension: nx5
replaceExisting: true
clan:
website-url-format: ${CLAN_WEBSITE_URL_FORMAT:http://clans.test.faforever.com/clan/%s}

Expand Down
27 changes: 0 additions & 27 deletions src/main/resources/config/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,6 @@ faf-api:
forged-alliance-exe-path: ${FORGED_ALLIANCE_EXE_PATH}
repositories-directory: ${REPOSITORIES_DIRECTORY}
featured-mods-target-directory: ${FEATURED_MODS_TARGET_DIRECTORY}
# TODO make this runtime configuration
configurations:
- repositoryUrl: https://github.com/FAForever/fa.git
branch: deploy/faf
modName: faf
modFilesExtension: nx2
replaceExisting: false
- repositoryUrl: https://github.com/FAForever/fa.git
branch: deploy/fafbeta
modName: fafbeta
modFilesExtension: nx4
replaceExisting: true
- repositoryUrl: https://github.com/FAForever/fa.git
branch: deploy/fafdevelop
modName: fafdevelop
modFilesExtension: nx5
replaceExisting: true
- repositoryUrl: https://github.com/FAForever/faf-phantomx.git
branch: master
modName: phantomx
modFilesExtension: phx
replaceExisting: false
- repositoryUrl: https://github.com/Nomads-Project/nomads.git
branch: master
modName: nomads
modFilesExtension: nmd
replaceExisting: false
registration:
activation-url-format: ${ACTIVATION_URL_FORMAT}
mail:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.faforever.api.deployment;

import com.faforever.api.config.FafApiProperties;
import com.faforever.api.config.FafApiProperties.Deployment.DeploymentConfiguration;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.faforever.api.data.domain.FeaturedMod;
import com.faforever.api.featuredmods.FeaturedModService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -14,10 +14,9 @@
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.context.ApplicationContext;

import java.util.Collections;
import java.util.Optional;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
Expand All @@ -35,12 +34,12 @@ public class GitHubDeploymentServiceTest {
@Mock
private ApplicationContext applicationContext;
@Mock
private ObjectMapper objectMapper;
private FeaturedModService featuredModService;

@Before
public void setUp() throws Exception {
apiProperties = new FafApiProperties();
instance = new GitHubDeploymentService(applicationContext, apiProperties, objectMapper);
instance = new GitHubDeploymentService(applicationContext, apiProperties, featuredModService);
}

@Test
Expand All @@ -50,6 +49,10 @@ public void createDeploymentIfEligibleNoConfigurationAvailable() throws Exceptio
GHRepository repository = mock(GHRepository.class);
when(repository.gitHttpTransportUrl()).thenReturn(EXAMPLE_REPO_URL);
when(push.getRepository()).thenReturn(repository);
when(push.getRef()).thenReturn("refs/heads/junit");

when(featuredModService.findByGitUrlAndGitBranch(EXAMPLE_REPO_URL, "junit"))
.thenReturn(Optional.empty());

instance.createDeploymentIfEligible(push);

Expand All @@ -59,29 +62,22 @@ public void createDeploymentIfEligibleNoConfigurationAvailable() throws Exceptio
@Test
public void createDeploymentIfEligible() throws Exception {
Push push = mock(Push.class);
when(push.getRef()).thenReturn("refs/heads/master");
when(push.getRef()).thenReturn("refs/heads/junit");
when(featuredModService.findByGitUrlAndGitBranch(EXAMPLE_REPO_URL, "junit"))
.thenReturn(Optional.of(new FeaturedMod().setTechnicalName("faf")));

GHRepository repository = mock(GHRepository.class);
when(repository.gitHttpTransportUrl()).thenReturn(EXAMPLE_REPO_URL);

GHDeploymentBuilder deploymentBuilder = mock(GHDeploymentBuilder.class);
when(deploymentBuilder.autoMerge(false)).thenReturn(deploymentBuilder);
when(deploymentBuilder.environment(ENVIRONMENT)).thenReturn(deploymentBuilder);
when(deploymentBuilder.payload(anyString())).thenReturn(deploymentBuilder);
when(repository.createDeployment("refs/heads/master")).thenReturn(deploymentBuilder);

when(objectMapper.writeValueAsString(any(DeploymentConfiguration.class))).thenReturn("");
when(deploymentBuilder.payload("faf")).thenReturn(deploymentBuilder);
when(repository.createDeployment("refs/heads/junit")).thenReturn(deploymentBuilder);

when(push.getRepository()).thenReturn(repository);

apiProperties.getGitHub().setDeploymentEnvironment(ENVIRONMENT);
apiProperties.getDeployment().setConfigurations(Collections.singletonList(
new DeploymentConfiguration()
.setBranch("master")
.setModFilesExtension(".nx2")
.setModName("faf")
.setRepositoryUrl(EXAMPLE_REPO_URL)
));

instance.createDeploymentIfEligible(push);

Expand All @@ -106,10 +102,12 @@ public void deployEnvironmentMatch() throws Exception {

GHDeployment deployment = mock(GHDeployment.class);
when(deployment.getEnvironment()).thenReturn(ENVIRONMENT);
when(deployment.getPayload()).thenReturn("faf");

LegacyFeaturedModDeploymentTask task = mock(LegacyFeaturedModDeploymentTask.class);
when(task.setConfiguration(any())).thenReturn(task);
when(task.setFeaturedMod(any())).thenReturn(task);
when(applicationContext.getBean(LegacyFeaturedModDeploymentTask.class)).thenReturn(task);
when(featuredModService.findModByTechnicalName("faf")).thenReturn(Optional.of(new FeaturedMod()));

instance.deploy(deployment);

Expand Down

0 comments on commit 0c6ed3a

Please sign in to comment.