Skip to content
Snippets Groups Projects
Commit c479ed3a authored by Martin Lowe's avatar Martin Lowe :flag_ca:
Browse files

Merge branch 'malowe/main/141' into 'main'

Iss #141 - Add DB-backed GH installation cache for better uptime

See merge request !155
parents 27b40365 17b75791
No related branches found
No related tags found
1 merge request!155Iss #141 - Add DB-backed GH installation cache for better uptime
Pipeline #31562 passed
Showing
with 445 additions and 64 deletions
......@@ -11,6 +11,8 @@
*/
package org.eclipsefoundation.git.eca.api.models;
import javax.annotation.Nullable;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
......@@ -22,8 +24,8 @@ import com.google.auto.value.AutoValue;
*
*/
@AutoValue
@JsonDeserialize(builder = AutoValue_GithubApplicationInstallation.Builder.class)
public abstract class GithubApplicationInstallation {
@JsonDeserialize(builder = AutoValue_GithubApplicationInstallationData.Builder.class)
public abstract class GithubApplicationInstallationData {
public abstract int getId();
......@@ -31,8 +33,10 @@ public abstract class GithubApplicationInstallation {
public abstract String getTargetId();
public abstract Account getAccount();
public static Builder builder() {
return new AutoValue_GithubApplicationInstallation.Builder();
return new AutoValue_GithubApplicationInstallationData.Builder();
}
@AutoValue.Builder
......@@ -44,6 +48,31 @@ public abstract class GithubApplicationInstallation {
public abstract Builder setTargetId(String targetId);
public abstract GithubApplicationInstallation build();
public abstract Builder setAccount(Account account);
public abstract GithubApplicationInstallationData build();
}
@AutoValue
@JsonDeserialize(builder = AutoValue_GithubApplicationInstallationData_Account.Builder.class)
public abstract static class Account {
public abstract int getId();
@Nullable
public abstract String getLogin();
public static Builder builder() {
return new AutoValue_GithubApplicationInstallationData_Account.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setId(int id);
public abstract Builder setLogin(@Nullable String login);
public abstract Account build();
}
}
}
......@@ -25,5 +25,7 @@ public interface WebhooksConfig {
String context();
String serverTarget();
int appId();
}
}
/**
* Copyright (c) 2023 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.git.eca.dto;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.commons.lang3.StringUtils;
import org.eclipsefoundation.core.helper.DateTimeHelper;
import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
import org.eclipsefoundation.persistence.dto.BareNode;
import org.eclipsefoundation.persistence.dto.filter.DtoFilter;
import org.eclipsefoundation.persistence.model.DtoTable;
import org.eclipsefoundation.persistence.model.ParameterizedSQLStatement;
import org.eclipsefoundation.persistence.model.ParameterizedSQLStatementBuilder;
/**
* Tracking for github installation data for GH ECA applications used for requesting data and updating commit statuses.
*/
@Table
@Entity
public class GithubApplicationInstallation extends BareNode {
public static final DtoTable TABLE = new DtoTable(GithubApplicationInstallation.class, "gai");
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private int appId;
private int installationId;
private String name;
private Date lastUpdated;
@Override
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(long id) {
this.id = id;
}
/**
* @return the appId
*/
public int getAppId() {
return appId;
}
/**
* @param appId the appId to set
*/
public void setAppId(int appId) {
this.appId = appId;
}
/**
* @return the installationId
*/
public int getInstallationId() {
return installationId;
}
/**
* @param installationId the installationId to set
*/
public void setInstallationId(int installationId) {
this.installationId = installationId;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the lastUpdated
*/
public Date getLastUpdated() {
return lastUpdated;
}
/**
* @param lastUpdated the lastUpdated to set
*/
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + Objects.hash(appId, id, installationId, lastUpdated, name);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
GithubApplicationInstallation other = (GithubApplicationInstallation) obj;
return appId == other.appId && id == other.id && installationId == other.installationId
&& Objects.equals(lastUpdated, other.lastUpdated) && Objects.equals(name, other.name);
}
@Singleton
public static class GithubApplicationInstallationFilter implements DtoFilter<GithubApplicationInstallation> {
@Inject
ParameterizedSQLStatementBuilder builder;
@Override
public ParameterizedSQLStatement getFilters(MultivaluedMap<String, String> params, boolean isRoot) {
ParameterizedSQLStatement statement = builder.build(TABLE);
String installationId = params.getFirst(GitEcaParameterNames.INSTALLATION_ID_RAW);
if (StringUtils.isNotBlank(installationId)) {
statement
.addClause(new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".installationId = ?",
new Object[] { Integer.parseInt(installationId) }));
}
String appId = params.getFirst(GitEcaParameterNames.APPLICATION_ID_RAW);
if (StringUtils.isNumeric(appId)) {
statement
.addClause(new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".appId = ?",
new Object[] { Integer.parseInt(appId) }));
}
String lastUpdated = params.getFirst(GitEcaParameterNames.LAST_UPDATED_BEFORE_RAW);
if (StringUtils.isNotBlank(lastUpdated)) {
try {
Date dt = DateTimeHelper.toRFC3339(lastUpdated);
statement.addClause(new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".lastUpdated < ?", new Object[] { dt }));
} catch (DateTimeParseException e) {
// do not do anything for badly formatted args
}
}
return statement;
}
@Override
public Class<GithubApplicationInstallation> getType() {
return GithubApplicationInstallation.class;
}
}
}
......@@ -110,7 +110,7 @@ public class GithubValidationHelper {
// use logging helper to sanitize newlines as they aren't needed here
String fullRepoName = LoggingHelper.format(org + '/' + repoName);
// get the installation ID for the given repo if it exists, and if the PR noted exists
String installationId = ghAppService.getInstallationForRepo(fullRepoName);
String installationId = ghAppService.getInstallationForRepo(org, repoName);
Optional<PullRequest> prResponse = ghAppService.getPullRequest(installationId, fullRepoName, prNo);
if (StringUtils.isBlank(installationId)) {
throw new BadRequestException("Could not find an ECA app installation for repo name: " + fullRepoName);
......
......@@ -37,6 +37,8 @@ public final class GitEcaParameterNames implements UrlParameterNamespace {
public static final String UNTIL_RAW = "until";
public static final String REPOSITORY_FULL_NAME_RAW = "repo_full_name";
public static final String INSTALLATION_ID_RAW = "installation_id";
public static final String APPLICATION_ID_RAW = "application_id";
public static final String LAST_UPDATED_BEFORE_RAW = "last_updated_before";
public static final String PULL_REQUEST_NUMBER_RAW = "pull_request_number";
public static final String USER_MAIL_RAW = "user_mail";
public static final String NEEDS_REVALIDATION_RAW = "needs_revalidation";
......@@ -57,6 +59,8 @@ public final class GitEcaParameterNames implements UrlParameterNamespace {
public static final UrlParameter UNTIL = new UrlParameter(UNTIL_RAW);
public static final UrlParameter REPOSITORY_FULL_NAME = new UrlParameter(REPOSITORY_FULL_NAME_RAW);
public static final UrlParameter INSTALLATION_ID = new UrlParameter(INSTALLATION_ID_RAW);
public static final UrlParameter APPLICATION_ID = new UrlParameter(APPLICATION_ID_RAW);
public static final UrlParameter LAST_UPDATED_BEFORE = new UrlParameter(LAST_UPDATED_BEFORE_RAW);
public static final UrlParameter PULL_REQUEST_NUMBER = new UrlParameter(PULL_REQUEST_NUMBER_RAW);
public static final UrlParameter USER_MAIL = new UrlParameter(USER_MAIL_RAW);
public static final UrlParameter NEEDS_REVALIDATION = new UrlParameter(NEEDS_REVALIDATION_RAW);
......@@ -65,8 +69,8 @@ public final class GitEcaParameterNames implements UrlParameterNamespace {
public List<UrlParameter> getParameters() {
return Arrays
.asList(COMMIT_ID, SHA, SHAS, PROJECT_ID, PROJECT_IDS, NOT_IN_PROJECT_IDS, REPO_URL, FINGERPRINT, USER_ID, PROJECT_PATH,
PARENT_PROJECT, STATUS_ACTIVE, STATUS_DELETED, SINCE, UNTIL, REPOSITORY_FULL_NAME, INSTALLATION_ID,
PULL_REQUEST_NUMBER, USER_MAIL, NEEDS_REVALIDATION);
PARENT_PROJECT, STATUS_ACTIVE, STATUS_DELETED, SINCE, UNTIL, REPOSITORY_FULL_NAME, INSTALLATION_ID, APPLICATION_ID,
LAST_UPDATED_BEFORE, PULL_REQUEST_NUMBER, USER_MAIL, NEEDS_REVALIDATION);
}
}
......@@ -122,7 +122,7 @@ public class StatusResource extends GithubAdjacentResource {
@PathParam("prNo") Integer prNo) {
String repoFullName = org + '/' + repoName;
// check that the passed repo has a valid installation
String installationId = ghAppService.getInstallationForRepo(repoFullName);
String installationId = ghAppService.getInstallationForRepo(org, repoName);
if (StringUtils.isBlank(installationId)) {
throw new BadRequestException("Repo " + repoFullName + " requested, but does not have visible installation, returning");
}
......@@ -158,7 +158,7 @@ public class StatusResource extends GithubAdjacentResource {
.data("fullRepoName", repoFullName)
.data("project", ps.isEmpty() ? null : ps.get(0))
.data("repoUrl", repoUrl)
.data("installationId", ghAppService.getInstallationForRepo(repoFullName))
.data("installationId", installationId)
.render())
.build();
}
......
......@@ -11,11 +11,11 @@
*/
package org.eclipsefoundation.git.eca.service;
import java.util.List;
import java.util.Optional;
import javax.ws.rs.core.MultivaluedMap;
import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest;
import org.eclipsefoundation.git.eca.dto.GithubApplicationInstallation;
/**
* Service for interacting with the Github API with caching for performance.
......@@ -26,19 +26,20 @@ import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest
public interface GithubApplicationService {
/**
* Retrieve safe map of all installations that are managed by this instance of the Eclispe ECA app.
* Retrieve safe list of all installations that are managed by this instance of the Eclispe ECA app.
*
* @return map containing installation IDs mapped to the list of repos they support for the current app
* @return list containing installation records for the current application
*/
MultivaluedMap<String, String> getManagedInstallations();
List<GithubApplicationInstallation> getManagedInstallations();
/**
* Retrieves the installation ID for the ECA app on the given repo if it exists.
* Retrieves the installation ID for the ECA app on the given org or repo if it exists.
*
* @param repoFullName the full repo name to retrieve an installation ID for. E.g. eclipse/jetty
* @param org the name of organization to retrieve an installation ID for
* @param repo the name of repo to retrieve an installation ID for
* @return the numeric installation ID if it exists, or null
*/
String getInstallationForRepo(String repoFullName);
String getInstallationForRepo(String org, String repo);
/**
* Retrieves a pull request given the repo, pull request, and associated installation to action the fetch.
......
......@@ -11,8 +11,10 @@
*/
package org.eclipsefoundation.git.eca.service.impl;
import java.net.URI;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
......@@ -26,14 +28,20 @@ import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.eclipsefoundation.core.exception.ApplicationException;
import org.eclipsefoundation.core.model.FlatRequestWrapper;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.core.service.APIMiddleware;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.git.eca.api.GithubAPI;
import org.eclipsefoundation.git.eca.api.models.GithubApplicationInstallation;
import org.eclipsefoundation.git.eca.api.models.GithubInstallationRepositoriesResponse;
import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest;
import org.eclipsefoundation.git.eca.config.WebhooksConfig;
import org.eclipsefoundation.git.eca.dto.GithubApplicationInstallation;
import org.eclipsefoundation.git.eca.helper.JwtHelper;
import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
import org.eclipsefoundation.git.eca.service.GithubApplicationService;
import org.eclipsefoundation.persistence.dao.PersistenceDao;
import org.eclipsefoundation.persistence.model.RDBMSQuery;
import org.eclipsefoundation.persistence.service.FilterService;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -58,21 +66,27 @@ public class DefaultGithubApplicationService implements GithubApplicationService
@ConfigProperty(name = "eclipse.github.default-api-version", defaultValue = "2022-11-28")
String apiVersion;
@Inject
WebhooksConfig config;
@RestClient
GithubAPI gh;
@Inject
JwtHelper jwt;
PersistenceDao dao;
@Inject
FilterService filters;
@Inject
CachingService cache;
@Inject
APIMiddleware middle;
@Inject
JwtHelper jwt;
@Inject
ManagedExecutor exec;
private AsyncLoadingCache<String, MultivaluedMap<String, String>> installationRepositoriesCache;
private AsyncLoadingCache<String, List<GithubApplicationInstallation>> installationRepositoriesCache;
@PostConstruct
void init() {
......@@ -87,17 +101,18 @@ public class DefaultGithubApplicationService implements GithubApplicationService
}
@Override
public MultivaluedMap<String, String> getManagedInstallations() {
// create a deep copy of the map to protect from modifications and return it
MultivaluedMap<String, String> mapClone = new MultivaluedMapImpl<>();
getAllInstallRepos().entrySet().stream().forEach(e -> mapClone.put(e.getKey(), new ArrayList<>(e.getValue())));
return mapClone;
public List<GithubApplicationInstallation> getManagedInstallations() {
return new ArrayList<>(getAllInstallRepos());
}
@Override
public String getInstallationForRepo(String repoFullName) {
MultivaluedMap<String, String> map = getAllInstallRepos();
return map.keySet().stream().filter(k -> map.get(k).contains(repoFullName)).findFirst().orElse(null);
public String getInstallationForRepo(String org, String repo) {
return getAllInstallRepos()
.stream()
.filter(install -> install.getName().equalsIgnoreCase(org))
.map(install -> Integer.toString(install.getInstallationId()))
.findFirst()
.orElse(null);
}
@Override
......@@ -107,7 +122,7 @@ public class DefaultGithubApplicationService implements GithubApplicationService
() -> gh.getPullRequest(jwt.getGhBearerString(installationId), apiVersion, repoFullName, pullRequest));
}
private MultivaluedMap<String, String> getAllInstallRepos() {
private List<GithubApplicationInstallation> getAllInstallRepos() {
try {
return this.installationRepositoriesCache.get("all").get(INSTALL_REPO_FETCH_MAX_TIMEOUT, TimeUnit.SECONDS);
} catch (InterruptedException e) {
......@@ -118,42 +133,22 @@ public class DefaultGithubApplicationService implements GithubApplicationService
throw new ApplicationException(
"Thread interrupted while building repository cache, no entries will be available for current call", e);
}
return new MultivaluedMapImpl<>();
return Collections.emptyList();
}
/**
* Retrieves a fresh copy of installation repositories, mapped by installation ID to associated full repo names.
* Retrieves a fresh copy of tracked installations, which have the associated app, the installation ID, and the name of the namespace associated with it.
*
* @return a multivalued map relating installation IDs to associated full repo names.
*/
private MultivaluedMap<String, String> loadInstallationRepositories() {
// create map early for potential empty returns
MultivaluedMapImpl<String, String> out = new MultivaluedMapImpl<>();
// get JWT bearer and then get all associated installations of current app
String auth = "Bearer " + jwt.generateJwt();
List<GithubApplicationInstallation> installations = middle
.getAll(i -> gh.getInstallations(i, auth), GithubApplicationInstallation.class);
// check that there are installations
if (installations.isEmpty()) {
LOGGER.warn("Did not find any installations for the currently configured Github application");
return out;
}
// trace log the installations for more context
LOGGER.trace("Found the following installations: {}", installations);
// from installations, get the assoc. repos and grab their full repo name and collect them
installations
.stream()
.forEach(installation -> middle
.getAll(i -> gh.getInstallationRepositories(i, jwt.getGhBearerString(Integer.toString(installation.getId()))),
GithubInstallationRepositoriesResponse.class)
.stream()
.forEach(installRepo -> installRepo
.getRepositories()
.stream()
.forEach(r -> out.add(Integer.toString(installation.getId()), r.getFullName()))));
LOGGER.trace("Final results for generating installation mapping: {}", out);
return out;
private List<GithubApplicationInstallation> loadInstallationRepositories() {
// once records are prepared, persist them back to the database with updates where necessary as a batch
RequestWrapper wrap = new FlatRequestWrapper(URI.create("https://api.eclipse.org/git/webhooks/github/installations"));
// build query to do fetch of records for currently active application
MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
params.add(GitEcaParameterNames.APPLICATION_ID_RAW, Integer.toString(config.github().appId()));
return dao.get(new RDBMSQuery<>(wrap, filters.get(GithubApplicationInstallation.class), params));
}
}
/**
* Copyright (c) 2023 Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipsefoundation.git.eca.tasks;
import java.net.URI;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.control.ActivateRequestContext;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.maven.shared.utils.StringUtils;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.eclipsefoundation.core.helper.DateTimeHelper;
import org.eclipsefoundation.core.model.FlatRequestWrapper;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.core.service.APIMiddleware;
import org.eclipsefoundation.git.eca.api.GithubAPI;
import org.eclipsefoundation.git.eca.api.models.GithubApplicationInstallationData;
import org.eclipsefoundation.git.eca.config.WebhooksConfig;
import org.eclipsefoundation.git.eca.dto.GithubApplicationInstallation;
import org.eclipsefoundation.git.eca.helper.JwtHelper;
import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
import org.eclipsefoundation.persistence.dao.PersistenceDao;
import org.eclipsefoundation.persistence.model.RDBMSQuery;
import org.eclipsefoundation.persistence.service.FilterService;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.quarkus.scheduler.Scheduled;
/**
* Using the configured database, Github installation records are tracked for all installations available for the
* currently configured GH application. This is used over an in-memory cache as the calls to build the cache are long
* running and have been known to fail sporadically.
*/
@ApplicationScoped
public class GithubInstallationUpdateTask {
private static final Logger LOGGER = LoggerFactory.getLogger(GithubInstallationUpdateTask.class);
@ConfigProperty(name = "eclipse.git-eca.tasks.gh-installation.enabled", defaultValue = "true")
Instance<Boolean> isEnabled;
@Inject
WebhooksConfig config;
@RestClient
GithubAPI gh;
@Inject
JwtHelper jwt;
@Inject
APIMiddleware middle;
@Inject
PersistenceDao dao;
@Inject
FilterService filters;
@PostConstruct
void init() {
// indicate to log whether enabled to reduce log spam
LOGGER.info("Github installation DB cache task is{} enabled.", Boolean.TRUE.equals(isEnabled.get()) ? "" : " not");
}
/**
* Every 1h, this method will query Github for installations for the currently configured application. These
* installations will be translated into database entries for a persistent cache to be loaded on request.
*/
@Scheduled(every = "1h")
@ActivateRequestContext
public void revalidate() {
// if not enabled, don't process any potentially OOD records
if (!Boolean.TRUE.equals(isEnabled.get())) {
return;
}
// get the installations for the currently configured app
List<GithubApplicationInstallationData> installations = middle
.getAll(i -> gh.getInstallations(i, "Bearer " + jwt.generateJwt()), GithubApplicationInstallationData.class);
// check that there are installations
if (installations.isEmpty()) {
LOGGER.warn("Did not find any installations for the currently configured Github application");
return;
}
// trace log the installations for more context
LOGGER.debug("Found {} installations to cache", installations.size());
// create a common timestamp for easier lookups of stale entries
Date startingTimestamp = new Date();
// from installations, build records and start the processing for each entry
List<GithubApplicationInstallation> installationRecords = installations
.stream()
.map(this::processInstallation)
.collect(Collectors.toList());
// once records are prepared, persist them back to the database with updates where necessary as a batch
RequestWrapper wrap = new FlatRequestWrapper(URI.create("https://api.eclipse.org/git/webhooks/github/installations"));
List<GithubApplicationInstallation> repoRecords = dao
.add(new RDBMSQuery<>(wrap, filters.get(GithubApplicationInstallation.class)), installationRecords);
if (repoRecords.size() != installationRecords.size()) {
LOGGER.warn("Background update to installation records had a size mismatch, cleaning will be skipped for this run");
return;
}
// build query to do cleanup of stale records
MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
params.add(GitEcaParameterNames.APPLICATION_ID_RAW, Integer.toString(config.github().appId()));
params.add(GitEcaParameterNames.LAST_UPDATED_BEFORE_RAW, DateTimeHelper.toRFC3339(startingTimestamp));
// run the delete call, removing stale entries
dao.delete(new RDBMSQuery<>(wrap, filters.get(GithubApplicationInstallation.class), params));
}
/**
* Converts the raw installation data from Github into a short record to be persisted to database as a form of
* persistent caching. Checks database for existing record, and returns record with a touched date for existing entries.
*
* @param ghInstallation raw Github installation record for current application
* @return the new or updated installation record to be persisted to the database.
*/
private GithubApplicationInstallation processInstallation(GithubApplicationInstallationData ghInstallation) {
RequestWrapper wrap = new FlatRequestWrapper(URI.create("https://api.eclipse.org/git/webhooks/github/installations"));
// build the lookup query for the current installation record
MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
params.add(GitEcaParameterNames.APPLICATION_ID_RAW, Integer.toString(config.github().appId()));
params.add(GitEcaParameterNames.INSTALLATION_ID_RAW, Integer.toString(ghInstallation.getId()));
// lookup existing records in the database
List<GithubApplicationInstallation> existingRecords = dao
.get(new RDBMSQuery<>(wrap, filters.get(GithubApplicationInstallation.class), params));
// check for existing entry, creating if missing
GithubApplicationInstallation installation;
if (existingRecords == null || existingRecords.isEmpty()) {
installation = new GithubApplicationInstallation();
installation.setAppId(config.github().appId());
installation.setInstallationId(ghInstallation.getId());
} else {
installation = existingRecords.get(0);
}
// update the basic stats to handle renames, and update last updated time
// login is technically nullable, so this might be missing. This is best we can do, as we can't look up by id
installation
.setName(StringUtils.isNotBlank(ghInstallation.getAccount().getLogin()) ? ghInstallation.getAccount().getLogin()
: "UNKNOWN");
installation.setLastUpdated(new Date());
return installation;
}
}
......@@ -40,13 +40,14 @@ quarkus.cache.caffeine."record".expire-after-write=${quarkus.cache.caffeine."def
quarkus.cache.caffeine."accesstoken".initial-capacity=1000
quarkus.cache.caffeine."accesstoken".expire-after-write=119S
## JWT Placeholders/defaults
smallrye.jwt.new-token.lifespan=120
smallrye.jwt.new-token.issuer=262450
## Webhook configs
eclipse.webhooks.github.context=eclipsefdn/eca
eclipse.webhooks.github.server-target=https://api.eclipse.org
eclipse.webhooks.github.app-id=262450
## JWT Placeholders/defaults
smallrye.jwt.new-token.lifespan=120
smallrye.jwt.new-token.issuer=${eclipse.webhooks.github.app-id}
## Git-eca mail configs
eclipse.git-eca.mail-validation.allow-list=noreply@github.com,49699333+dependabot[bot]@users.noreply.github.com,bot@stepsecurity.io
......
......@@ -35,6 +35,7 @@ eclipse.git-eca.mail.allow-list=noreply@github.com
## Reports configs
eclipse.git-eca.reports.access-key=samplekey
eclipse.git-eca.tasks.gh-revalidation.enabled=false
eclipse.git-eca.tasks.gh-installation.enabled=false
## Misc
eclipse.gitlab.access-token=token_val
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment