-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e094255
commit 08ba8f5
Showing
30 changed files
with
993 additions
and
586 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.faforever.api.config; | ||
|
||
import org.kohsuke.github.GitHub; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
import java.io.IOException; | ||
|
||
@Configuration | ||
public class GitHubConfig { | ||
@Bean | ||
public GitHub gitHub(FafApiProperties fafApiProperties) throws IOException { | ||
return GitHub.connectUsingOAuth(fafApiProperties.getGitHub().getAccessToken()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
src/main/java/com/faforever/api/deployment/GitHubController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package com.faforever.api.deployment; | ||
|
||
import com.faforever.api.config.FafApiProperties; | ||
import lombok.SneakyThrows; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.kohsuke.github.GHEventPayload; | ||
import org.kohsuke.github.GHEventPayload.Deployment; | ||
import org.kohsuke.github.GHEventPayload.Push; | ||
import org.kohsuke.github.GitHub; | ||
import org.springframework.scheduling.annotation.Async; | ||
import org.springframework.security.jwt.crypto.sign.MacSigner; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestHeader; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestMethod; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import javax.crypto.spec.SecretKeySpec; | ||
import javax.xml.bind.DatatypeConverter; | ||
import java.io.StringReader; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
@RestController | ||
@RequestMapping(path = "/gitHub") | ||
@Slf4j | ||
public class GitHubController { | ||
|
||
private static final String HMAC_SHA1 = "HmacSHA1"; | ||
private final GitHubDeploymentService gitHubDeploymentService; | ||
private final GitHub gitHub; | ||
private final FafApiProperties apiProperties; | ||
|
||
public GitHubController(GitHubDeploymentService gitHubDeploymentService, GitHub gitHub, FafApiProperties apiProperties) { | ||
this.gitHubDeploymentService = gitHubDeploymentService; | ||
this.gitHub = gitHub; | ||
this.apiProperties = apiProperties; | ||
} | ||
|
||
@Async | ||
@RequestMapping(path = "/webhook", method = RequestMethod.POST) | ||
@SneakyThrows | ||
public void onPush(@RequestBody String body, | ||
@RequestHeader("X-Hub-Signature") String signature, | ||
@RequestHeader("X-GitHub-Event") String eventType) { | ||
verifyRequest(body, signature); | ||
switch (eventType) { | ||
case "push": | ||
gitHubDeploymentService.createDeploymentIfEligible(parseEvent(body, Push.class)); | ||
break; | ||
case "deployment": | ||
gitHubDeploymentService.deploy(parseEvent(body, Deployment.class).getDeployment()); | ||
break; | ||
default: | ||
log.warn("Unhandled event: " + eventType); | ||
} | ||
} | ||
|
||
@SneakyThrows | ||
private <T extends GHEventPayload> T parseEvent(@RequestBody String body, Class<T> type) { | ||
return gitHub.parseEventPayload(new StringReader(body), type); | ||
} | ||
|
||
@SneakyThrows | ||
private void verifyRequest(String payload, String signature) { | ||
String secret = apiProperties.getGitHub().getWebhookSecret(); | ||
MacSigner macSigner = new MacSigner(HMAC_SHA1, new SecretKeySpec(secret.getBytes(StandardCharsets.US_ASCII), HMAC_SHA1)); | ||
|
||
byte[] content = payload.getBytes(StandardCharsets.US_ASCII); | ||
// Signature starts with "sha1=" | ||
macSigner.verify(content, DatatypeConverter.parseHexBinary(signature.substring(5))); | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
src/main/java/com/faforever/api/deployment/GitHubDeploymentService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package com.faforever.api.deployment; | ||
|
||
import com.faforever.api.config.FafApiProperties; | ||
import com.faforever.api.config.FafApiProperties.Deployment.DeploymentConfiguration; | ||
import com.faforever.api.error.ProgrammingError; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import lombok.SneakyThrows; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.kohsuke.github.GHDeployment; | ||
import org.kohsuke.github.GHEventPayload.Push; | ||
import org.kohsuke.github.GHEventPayload.Push.PushCommit; | ||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.scheduling.annotation.Async; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
|
||
|
||
@Service | ||
@Slf4j | ||
public class GitHubDeploymentService { | ||
|
||
private final ApplicationContext applicationContext; | ||
private final FafApiProperties fafApiProperties; | ||
private final ObjectMapper objectMapper; | ||
|
||
public GitHubDeploymentService(ApplicationContext applicationContext, FafApiProperties fafApiProperties, ObjectMapper objectMapper) { | ||
this.applicationContext = applicationContext; | ||
this.fafApiProperties = fafApiProperties; | ||
this.objectMapper = objectMapper; | ||
} | ||
|
||
@SneakyThrows | ||
public void createDeploymentIfEligible(Push push) { | ||
List<PushCommit> commits = push.getCommits(); | ||
PushCommit headCommit = commits.get(0); | ||
|
||
if (!Objects.equals(headCommit.getSha(), push.getHead())) { | ||
throw new ProgrammingError("Expected first commit to be the head commit, apparently that is not the case"); | ||
} | ||
|
||
String ref = push.getRef(); | ||
if (!headCommit.isDistinct()) { | ||
log.debug("Ignoring non-distinct commit to ref: {}", ref); | ||
return; | ||
} | ||
Optional<DeploymentConfiguration> optional = fafApiProperties.getDeployment().getConfigurations().stream() | ||
.filter(configuration -> | ||
push.getRepository().gitHttpTransportUrl().equals(configuration.getRepositoryUrl()) | ||
&& push.getRef().replace("refs/heads/", "").equals(configuration.getBranch())) | ||
.findFirst(); | ||
|
||
if (!optional.isPresent()) { | ||
log.warn("No configuration present for repository '{}' and ref '{}'", push.getRepository().gitHttpTransportUrl(), push.getRef()); | ||
return; | ||
} | ||
|
||
GHDeployment ghDeployment = push.getRepository().createDeployment(ref) | ||
.environment(fafApiProperties.getGitHub().getDeploymentEnvironment()) | ||
.payload(objectMapper.writeValueAsString(optional.get())) | ||
.create(); | ||
|
||
log.info("Created deployment: {}", ghDeployment); | ||
} | ||
|
||
@Async | ||
@SneakyThrows | ||
public void deploy(GHDeployment deployment) { | ||
String environment = deployment.getEnvironment(); | ||
if (!fafApiProperties.getGitHub().getDeploymentEnvironment().equals(environment)) { | ||
log.warn("Ignoring deployment for environment: {}", environment); | ||
return; | ||
} | ||
|
||
applicationContext.getBean(LegacyFeaturedModDeploymentTask.class) | ||
.setConfiguration(objectMapper.readValue(deployment.getPayload(), DeploymentConfiguration.class)) | ||
.run(); | ||
} | ||
} |
Oops, something went wrong.