From db205a2c6736e41699c240287cc9ba72e56dcedb Mon Sep 17 00:00:00 2001 From: Yaroslav Svitlytskyi <53532703+YarikRevich@users.noreply.github.com> Date: Thu, 10 Oct 2024 03:14:26 +0200 Subject: [PATCH] fix: fixed repository download (#28) --- .github/workflows/build.yml | 2 +- api-server/pom.xml | 14 +- .../dto/GitHubRepositoriesDto.java | 30 +++ .../com/repoachiever/dto/GitHubUserDto.java | 22 ++ .../entity/common/ConfigEntity.java | 6 - .../entity/common/PropertiesEntity.java | 9 + ...nfigCronExpressionValidationException.java | 22 ++ .../client/github/IGitHubClientService.java | 10 +- .../service/cluster/facade/ClusterFacade.java | 2 - .../service/config/ConfigService.java | 41 +-- .../common/VendorConfigurationHelper.java | 5 +- .../git/github/GitGitHubVendorService.java | 91 +++++-- .../service/workspace/WorkspaceService.java | 2 +- .../src/main/resources/application.properties | 9 + .../com/repoachiever/entity/ConfigEntity.java | 5 - ...nfigCronExpressionValidationException.java | 22 ++ .../service/config/ConfigService.java | 8 + .../scheduler/SchedulerConfigService.java | 89 ++++--- .../service/state/StateService.java | 43 +--- .../common/VendorConfigurationHelper.java | 5 +- .../git/github/GitGitHubVendorService.java | 4 + .../service/element/list/ListVisualizer.java | 233 +++++++++--------- pom.xml | 5 + samples/config/api-server/api-server.yaml | 2 +- 24 files changed, 441 insertions(+), 240 deletions(-) create mode 100644 api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java create mode 100644 api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java create mode 100644 api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java create mode 100644 cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8988936..44b8f1c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up JDK 23 + - name: "Set up JDK 23" uses: oracle-actions/setup-java@v1 with: website: oracle.com diff --git a/api-server/pom.xml b/api-server/pom.xml index 35e81e3..f3105e7 100644 --- a/api-server/pom.xml +++ b/api-server/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 api-server 1.0-SNAPSHOT @@ -104,6 +104,10 @@ org.jboss.logging jboss-logging + + org.jboss.logmanager + log4j2-jboss-logmanager + jakarta.json jakarta.json-api @@ -236,7 +240,9 @@ file=byte[] - @lombok.Data @lombok.NoArgsConstructor @lombok.AllArgsConstructor(staticName = "of") + @lombok.Data + @lombok.NoArgsConstructor @lombok.AllArgsConstructor(staticName + = "of") src/main/java true true @@ -322,4 +328,4 @@ - + \ No newline at end of file diff --git a/api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java b/api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java new file mode 100644 index 0000000..faf9bf1 --- /dev/null +++ b/api-server/src/main/java/com/repoachiever/dto/GitHubRepositoriesDto.java @@ -0,0 +1,30 @@ +package com.repoachiever.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; + +/** + * Represents retrieved GitHub repository details. + */ +@Getter +@ApplicationScoped +public class GitHubRepositoriesDto { + /** + * Represents remote repository short name. + */ + @Valid + @NotNull + @JsonProperty("name") + public String name; + + /** + * Represents remote repository default branch. + */ + @Valid + @NotNull + @JsonProperty("default_branch") + public String defaultBranch; +} \ No newline at end of file diff --git a/api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java b/api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java new file mode 100644 index 0000000..449a4aa --- /dev/null +++ b/api-server/src/main/java/com/repoachiever/dto/GitHubUserDto.java @@ -0,0 +1,22 @@ +package com.repoachiever.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; + +/** + * Represents retrieved GitHub user details. + */ +@Getter +@ApplicationScoped +public class GitHubUserDto { + /** + * Represents user name. + */ + @Valid + @NotNull + @JsonProperty("login") + public String login; +} \ No newline at end of file diff --git a/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java b/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java index 2cab6b1..f0bcad2 100644 --- a/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java +++ b/api-server/src/main/java/com/repoachiever/entity/common/ConfigEntity.java @@ -5,7 +5,6 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; import lombok.Getter; /** @@ -189,11 +188,6 @@ public static class Cluster { @Getter public static class Worker { @NotNull - @Pattern( - regexp = - "(((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?)|(([\\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3]))|([\\?])|([\\*]))[\\s](((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?)|(([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(L(-[0-9])?)|(L(-[1-2][0-9])?)|(L(-[3][0-1])?)|(LW)|([1-9]W)|([1-3][0-9]W)|([\\?])|([\\*]))[\\s](((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?)|(([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2]))|(((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)|((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))|([\\?])|([\\*]))[\\s]((([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?)|([1-7]/([1-7]))|(((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?)|((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|(([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))?(L|LW)?)|(([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)|([\\?])|([\\*]))([\\s]?(([\\*])?|(19[7-9][0-9])|(20[0-9][0-9]))?|" - + " (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))?|" - + " ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)?)") @JsonProperty("frequency") public String frequency; } diff --git a/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java b/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java index 8092225..d3085ec 100644 --- a/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java +++ b/api-server/src/main/java/com/repoachiever/entity/common/PropertiesEntity.java @@ -23,6 +23,15 @@ public class PropertiesEntity { @ConfigProperty(name = "quarkus.rest-client.github.url") String restClientGitHubUrl; + @ConfigProperty(name = "rest-client.github.page-size") + Integer restClientGitHubPageSize; + + @ConfigProperty(name = "rest-client.github.max-page") + Integer restClientGitHubMaxPage; + + @ConfigProperty(name = "rest-client.github.repo-visibility") + String restClientGitHubRepoVisibility; + @ConfigProperty(name = "github.location.notation") String gitHubLocationNotation; diff --git a/api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java b/api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java new file mode 100644 index 0000000..6c30c94 --- /dev/null +++ b/api-server/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java @@ -0,0 +1,22 @@ +package com.repoachiever.exception; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Formatter; + +/** + * Represents exception used when configuration file cron expression validation + * process fails. + */ +public class ConfigCronExpressionValidationException extends IOException { + public ConfigCronExpressionValidationException() { + this(""); + } + + public ConfigCronExpressionValidationException(Object... message) { + super( + new Formatter() + .format("Config file cron expression is not valid: %s", Arrays.stream(message).toArray()) + .toString()); + } +} diff --git a/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java b/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java index 084cdba..d798203 100644 --- a/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java +++ b/api-server/src/main/java/com/repoachiever/service/client/github/IGitHubClientService.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @@ -24,12 +25,13 @@ public interface IGitHubClientService { Response getPermissionScopes(@HeaderParam(HttpHeaders.AUTHORIZATION) String token); @GET - @Path("/repos/{owner}/{name}}") + @Path("/user/repos") @Produces(MediaType.APPLICATION_JSON) - Response getRepository( + Response getRepositories( @HeaderParam(HttpHeaders.AUTHORIZATION) String token, - @PathParam("owner") String owner, - @PathParam("name") String name); + @QueryParam("per_page") Integer perPage, + @QueryParam("page") Integer page, + @QueryParam("visibility") String visibility); @GET @Path("/repos/{owner}/{name}/branches/{branch}") diff --git a/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java b/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java index 1a0d902..209d61e 100644 --- a/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java +++ b/api-server/src/main/java/com/repoachiever/service/cluster/facade/ClusterFacade.java @@ -367,8 +367,6 @@ public void destroy(ContentWithdrawal contentWithdrawal) throws ClusterWithdrawa logger.info( String.format("Removing RepoAchiever Cluster allocation: '%s'", clusterAllocation.getName())); - System.out.println(clusterAllocation.getPid()); - try { clusterService.destroy(clusterAllocation.getPid()); } catch (ClusterDestructionFailureException e) { diff --git a/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java b/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java index fc32c0e..025bfed 100644 --- a/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java +++ b/api-server/src/main/java/com/repoachiever/service/config/ConfigService.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.repoachiever.entity.common.ConfigEntity; import com.repoachiever.entity.common.PropertiesEntity; +import com.repoachiever.exception.ConfigCronExpressionValidationException; import com.repoachiever.exception.ConfigFileClosureFailureException; import com.repoachiever.exception.ConfigFileNotFoundException; import com.repoachiever.exception.ConfigFileReadingFailureException; @@ -28,11 +29,14 @@ import java.util.stream.Collectors; import lombok.Getter; + +import org.apache.logging.log4j.core.util.CronExpression; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** - * Service used to perform RepoAchiever API Server configuration processing operation. + * Service used to perform RepoAchiever API Server configuration processing + * operation. */ @Startup @ApplicationScoped @@ -44,16 +48,19 @@ public class ConfigService { private ConfigEntity config; /** - * Reads configuration from the opened configuration file using mapping with a configuration entity. + * Reads configuration from the opened configuration file using mapping with a + * configuration entity. * - * @throws ConfigFileNotFoundException if configuration file is not found. - * @throws ConfigValidationException if configuration file operation failed. - * @throws ConfigFileReadingFailureException if configuration file reading operation failed. - * @throws ConfigFileClosureFailureException if configuration file closure operation failed. + * @throws ConfigFileNotFoundException if configuration file is not found. + * @throws ConfigValidationException if configuration file operation + * failed. + * @throws ConfigFileReadingFailureException if configuration file reading + * operation failed. + * @throws ConfigFileClosureFailureException if configuration file closure + * operation failed. */ @PostConstruct - private void configure() throws - ConfigFileNotFoundException, + private void configure() throws ConfigFileNotFoundException, ConfigValidationException, ConfigFileReadingFailureException, ConfigFileClosureFailureException { @@ -66,11 +73,10 @@ private void configure() throws throw new ConfigFileNotFoundException(e.getMessage()); } - ObjectMapper mapper = - new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, true) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true) - .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true) + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); ObjectReader reader = mapper.reader().forType(new TypeReference() { }); @@ -89,8 +95,7 @@ private void configure() throws try (ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory()) { Validator validator = validatorFactory.getValidator(); - Set> validationResult = - validator.validate(config); + Set> validationResult = validator.validate(config); if (!validationResult.isEmpty()) { throw new ConfigValidationException( @@ -99,6 +104,12 @@ private void configure() throws .collect(Collectors.joining(", "))); } } + + if (!CronExpression.isValidExpression( + config.getResource().getWorker().getFrequency())) { + throw new ConfigValidationException( + new ConfigCronExpressionValidationException().getMessage()); + } } finally { try { file.close(); diff --git a/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java b/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java index cfa415c..cdadd88 100644 --- a/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java +++ b/api-server/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java @@ -9,6 +9,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -44,7 +45,9 @@ public GitHubLocationNotationDto parseLocationGitHubNotation(String location) { matcher.find(); - if (matcher.groupCount() == 4) { + String optionalMatch = matcher.group(4); + + if (matcher.groupCount() == 4 && Objects.nonNull(optionalMatch)) { return GitHubLocationNotationDto.of( matcher.group(1), matcher.group(2), diff --git a/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java b/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java index 8bba7f9..5b516f9 100644 --- a/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java +++ b/api-server/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java @@ -1,32 +1,77 @@ package com.repoachiever.service.vendor.git.github; +import com.repoachiever.dto.GitHubRepositoriesDto; +import com.repoachiever.dto.GitHubUserDto; +import com.repoachiever.entity.common.PropertiesEntity; import com.repoachiever.dto.GitHubLocationNotationDto; import com.repoachiever.service.client.github.IGitHubClientService; import com.repoachiever.service.vendor.common.VendorConfigurationHelper; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.GenericType; import jakarta.ws.rs.core.Response; import org.apache.http.HttpStatus; import org.eclipse.microprofile.rest.client.inject.RestClient; import java.net.SocketTimeoutException; import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Service used to represent GitHub external service operations. */ @ApplicationScoped public class GitGitHubVendorService { + @Inject + PropertiesEntity properties; + @Inject @RestClient IGitHubClientService gitHubClientService; + /** + * Retrieves repositories of all types for the provided user. + * + * @param token given access token. + * @return retrieved user repositories of all types. + */ + private List getRepositories(String token) { + List result = new ArrayList(); + + Response response; + + for (Integer page = 1; page < properties.getRestClientGitHubMaxPage(); page++) { + response = gitHubClientService.getRepositories( + token, + properties.getRestClientGitHubPageSize(), + page, + properties.getRestClientGitHubRepoVisibility()); + + if (response.getStatus() != HttpStatus.SC_OK) { + return null; + } + + List part = response + .readEntity(new GenericType>() { + }); + + if (part.isEmpty()) { + break; + } + + result.addAll(part); + } + + return result; + }; + /** * Checks if the given token is valid. * - * @param token given token to be validated. + * @param token given access token to be validated. * @return result of the check. */ public Boolean isTokenValid(String token) { @@ -48,35 +93,41 @@ public Boolean isTokenValid(String token) { * @return result of the check. */ public Boolean areLocationsValid(String token, List locations) { + List repositories = getRepositories(token); + + if (Objects.isNull(repositories)) { + return false; + } + return locations .stream() - .allMatch(element -> { - try { - Response response; + .allMatch(e1 -> { + if (e1.getBranch().isPresent()) { + if (repositories.stream() + .anyMatch(e2 -> Objects.equals( + e2.getName(), e1.getName()) && + Objects.equals( + e2.getDefaultBranch(), e1.getBranch().get()))) { + return true; + } - if (element.getBranch().isPresent()) { - response = gitHubClientService + try { + return gitHubClientService .getRepository( token, - element.getOwner(), - element.getName(), - element.getBranch().get()); - } else { - response = gitHubClientService - .getRepository( - token, - element.getOwner(), - element.getName()); - } + e1.getOwner(), + e1.getName(), + e1.getBranch().get()) + .getStatus() == HttpStatus.SC_OK; + } catch (WebApplicationException e) { + System.out.println(e.getMessage()); - if (response.getStatus() != HttpStatus.SC_OK) { return false; } - } catch (WebApplicationException e) { - return false; } - return true; + return repositories.stream() + .anyMatch(e2 -> Objects.equals(e2.getName(), e1.getName())); }); } } diff --git a/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java b/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java index 8218ff7..057c1ad 100644 --- a/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java +++ b/api-server/src/main/java/com/repoachiever/service/workspace/WorkspaceService.java @@ -392,7 +392,7 @@ public void removeEarliestRawContentFile(String workspaceUnitDirectory, String l * * @param workspaceUnitDirectory given workspace unit directory. * @param location given location of the additional content file. - * @param name given name of the additional content file. + * @param name given name of the raws content file. * @return result if additional content file exists in the given workspace unit directory. */ public Boolean isRawContentFileExist(String workspaceUnitDirectory, String location, String name) { diff --git a/api-server/src/main/resources/application.properties b/api-server/src/main/resources/application.properties index e304b0a..83e60ff 100644 --- a/api-server/src/main/resources/application.properties +++ b/api-server/src/main/resources/application.properties @@ -22,6 +22,15 @@ quarkus.rest-client.github.url=https://api.github.com # Describes timeout used by GitHub client. quarkus.rest-client.github.connect-timeout=10000 +# Describes page size used by GitHub client. +rest-client.github.page-size=100 + +# Describes max page used by GitHub client. +rest-client.github.max-page=1000 + +# Describes visibility of repositories to be retreived by GitHub client. +rest-client.github.repo-visibility=all + # Describes internal healthcheck client configuration. quarkus.rest-client.small-rye-health-check.url=http://${quarkus.http.host}:${quarkus.http.port} diff --git a/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java b/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java index 6f1cd6a..96f748e 100644 --- a/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java +++ b/cluster/src/main/java/com/repoachiever/entity/ConfigEntity.java @@ -171,11 +171,6 @@ public static class Resource { @Getter public static class Worker { @NotNull - @Pattern( - regexp = - "(((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\\?])|([\\*]))[\\s](((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?)|(([\\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3]))|([\\?])|([\\*]))[\\s](((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?)|(([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(L(-[0-9])?)|(L(-[1-2][0-9])?)|(L(-[3][0-1])?)|(LW)|([1-9]W)|([1-3][0-9]W)|([\\?])|([\\*]))[\\s](((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?)|(([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2]))|(((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)|((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))|([\\?])|([\\*]))[\\s]((([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?)|([1-7]/([1-7]))|(((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?)|((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|(([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))?(L|LW)?)|(([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)|([\\?])|([\\*]))([\\s]?(([\\*])?|(19[7-9][0-9])|(20[0-9][0-9]))?|" - + " (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))?|" - + " ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)?)") @JsonProperty("frequency") public String frequency; } diff --git a/cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java b/cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java new file mode 100644 index 0000000..87d8f8c --- /dev/null +++ b/cluster/src/main/java/com/repoachiever/exception/ConfigCronExpressionValidationException.java @@ -0,0 +1,22 @@ +package com.repoachiever.exception; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Formatter; + +/** + * Represents exception used when configuration file cron expression validation + * process fails. + */ +public class ConfigCronExpressionValidationException extends IOException { + public ConfigCronExpressionValidationException() { + this(""); + } + + public ConfigCronExpressionValidationException(Object... message) { + super( + new Formatter() + .format("Config file cron expression is not valid: %s", Arrays.stream(message).toArray()) + .toString()); + } +} diff --git a/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java b/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java index 66066fa..55241d2 100644 --- a/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java +++ b/cluster/src/main/java/com/repoachiever/service/config/ConfigService.java @@ -12,6 +12,7 @@ import com.repoachiever.exception.ConfigFileReadingFailureException; import com.repoachiever.exception.ConfigNotGivenException; import com.repoachiever.exception.ConfigValidationException; +import com.repoachiever.exception.ConfigCronExpressionValidationException; import jakarta.annotation.PostConstruct; import java.io.IOException; @@ -28,6 +29,7 @@ import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.util.CronExpression; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -95,6 +97,12 @@ private void configure() throws .collect(Collectors.joining(", "))); } } + + if (!CronExpression.isValidExpression( + config.getResource().getWorker().getFrequency())) { + throw new ConfigValidationException( + new ConfigCronExpressionValidationException().getMessage()); + } } finally { try { configFile.close(); diff --git a/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java b/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java index 42e95da..82b7ecd 100644 --- a/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java +++ b/cluster/src/main/java/com/repoachiever/service/integration/scheduler/SchedulerConfigService.java @@ -37,15 +37,16 @@ public class SchedulerConfigService { /** * Performs configuration of RepoAchiever Cluster workers. * - * @throws SchedulerPeriodRetrievalFailureException if scheduler period retrieval process failed. + * @throws SchedulerPeriodRetrievalFailureException if scheduler period + * retrieval process failed. */ @PostConstruct private void process() throws SchedulerPeriodRetrievalFailureException { - ExecutorService starterExecutorService = - Executors.newFixedThreadPool(configService.getConfig().getContent().getLocations().size()); + ExecutorService starterExecutorService = Executors + .newFixedThreadPool(configService.getConfig().getContent().getLocations().size()); - ScheduledExecutorService operationScheduledExecutorService = - Executors.newScheduledThreadPool(configService.getConfig().getContent().getLocations().size()); + ScheduledExecutorService operationScheduledExecutorService = Executors + .newScheduledThreadPool(configService.getConfig().getContent().getLocations().size()); Long period; @@ -74,8 +75,7 @@ private void process() throws SchedulerPeriodRetrievalFailureException { logger.info( LoggingConfigurationHelper.getTransferableMessage( String.format("Skipping execution for '%s' location due to suspension", - element.getName()) - )); + element.getName()))); return; } @@ -87,17 +87,14 @@ private void process() throws SchedulerPeriodRetrievalFailureException { StateService.resetSuspenderByName(element.getName()); - CountDownLatch awaiter = StateService.getSuspenderAwaiterByName(element.getName()); - if (!vendorFacade.isVendorAvailable()) { logger.info( LoggingConfigurationHelper.getTransferableMessage( String.format("Remote provider '%s' is not available: '%s'", configService.getConfig().getService().getProvider().toString(), - element.getName()) - )); + element.getName()))); - awaiter.countDown(); + StateService.countDownSuspenderByName(element.getName()); return; } @@ -116,8 +113,6 @@ record = vendorFacade.getLatestRecord(element.getName()); element.getName(), e.getMessage()))); - StateService.removeSuspenderByName(element.getName()); - closable.countDown(); return; @@ -129,7 +124,7 @@ record = vendorFacade.getLatestRecord(element.getName()); element.getName(), e.getMessage()))); - awaiter.countDown(); + StateService.countDownSuspenderByName(element.getName()); return; } @@ -137,13 +132,19 @@ record = vendorFacade.getLatestRecord(element.getName()); Boolean rawContentPresent = false; try { - rawContentPresent = - apiServerCommunicationResource.retrieveRawContentPresent( - element.getName(), record); + rawContentPresent = apiServerCommunicationResource.retrieveRawContentPresent( + element.getName(), record); } catch (ApiServerOperationFailureException ignored) { } if (!rawContentPresent) { + logger.info( + LoggingConfigurationHelper.getTransferableMessage( + String.format( + "Raw content record '%s' for '%s' location is not present", + record, + element.getName()))); + logger.info( LoggingConfigurationHelper.getTransferableMessage( String.format( @@ -191,8 +192,6 @@ record = vendorFacade.getLatestRecord(element.getName()); } } - StateService.removeSuspenderByName(element.getName()); - closable.countDown(); return; @@ -217,7 +216,7 @@ record = vendorFacade.getLatestRecord(element.getName()); } } - awaiter.countDown(); + StateService.countDownSuspenderByName(element.getName()); return; } @@ -253,7 +252,7 @@ record = vendorFacade.getLatestRecord(element.getName()); element.getName(), e.getMessage()))); - awaiter.countDown(); + StateService.countDownSuspenderByName(element.getName()); return; } @@ -264,6 +263,13 @@ record = vendorFacade.getLatestRecord(element.getName()); "Raw content transfer finished for '%s' location and '%s' record", element.getName(), record))); + } else { + logger.info( + LoggingConfigurationHelper.getTransferableMessage( + String.format( + "Raw content record '%s' for '%s' location is already present", + record, + element.getName()))); } AdditionalContentDto additionalContent; @@ -278,8 +284,6 @@ record = vendorFacade.getLatestRecord(element.getName()); element.getName(), e.getMessage()))); - StateService.removeSuspenderByName(element.getName()); - closable.countDown(); return; @@ -291,7 +295,7 @@ record = vendorFacade.getLatestRecord(element.getName()); element.getName(), e.getMessage()))); - awaiter.countDown(); + StateService.countDownSuspenderByName(element.getName()); return; } @@ -300,13 +304,19 @@ record = vendorFacade.getLatestRecord(element.getName()); Boolean additionalContentPresent = false; try { - additionalContentPresent = - apiServerCommunicationResource.retrieveAdditionalContentPresent( + additionalContentPresent = apiServerCommunicationResource + .retrieveAdditionalContentPresent( element.getName(), additionalContent.getHash()); } catch (ApiServerOperationFailureException ignored) { } if (!additionalContentPresent) { + logger.info( + LoggingConfigurationHelper.getTransferableMessage( + String.format( + "Additional content for '%s' location is not present", + element.getName()))); + logger.info( LoggingConfigurationHelper.getTransferableMessage( String.format( @@ -316,7 +326,8 @@ record = vendorFacade.getLatestRecord(element.getName()); try { apiServerCommunicationResource.performAdditionalContentUpload( - element.getName(), additionalContent.getHash(), additionalContent.getData()); + element.getName(), additionalContent.getHash(), + additionalContent.getData()); } catch (ApiServerOperationFailureException e) { logger.info( LoggingConfigurationHelper.getTransferableMessage( @@ -325,7 +336,7 @@ record = vendorFacade.getLatestRecord(element.getName()); element.getName(), e.getMessage()))); - awaiter.countDown(); + StateService.countDownSuspenderByName(element.getName()); return; } @@ -336,11 +347,23 @@ record = vendorFacade.getLatestRecord(element.getName()); "Additional content transfer finished for '%s' location and '%s' hash", element.getName(), additionalContent.getHash()))); + } else { + logger.info( + LoggingConfigurationHelper.getTransferableMessage( + String.format( + "Additional content for '%s' location is already present", + element.getName()))); } } + } catch (Exception e) { + StateService.countDownSuspenderByName(element.getName()); - awaiter.countDown(); + logger.info( + LoggingConfigurationHelper.getTransferableMessage( + String.format("ERROR APPERAED '%s' location", element.getName()))); } finally { + StateService.countDownSuspenderByName(element.getName()); + logger.info( LoggingConfigurationHelper.getTransferableMessage( String.format("Exiting execution for '%s' location", element.getName()))); @@ -353,7 +376,13 @@ record = vendorFacade.getLatestRecord(element.getName()); logger.fatal(e.getMessage()); } + StateService.removeSuspenderByName(element.getName()); + execution.cancel(true); + + logger.info( + LoggingConfigurationHelper.getTransferableMessage( + String.format("Operations were cancelled for '%s' location", element.getName()))); }); }); } diff --git a/cluster/src/main/java/com/repoachiever/service/state/StateService.java b/cluster/src/main/java/com/repoachiever/service/state/StateService.java index 536d1fb..11ff249 100644 --- a/cluster/src/main/java/com/repoachiever/service/state/StateService.java +++ b/cluster/src/main/java/com/repoachiever/service/state/StateService.java @@ -76,59 +76,28 @@ public static void resetSuspenderByName(String name) { } /** - * Retrieves RepoAchiever Cluster suspender awaiter by the given name. + * Counts down RepoAchiever Cluster suspender suspender by the given name. * * @param name given RepoAchiever Cluster suspender name. - * @return retrieved RepoAchiever Cluster suspender awaiter name. */ - public static CountDownLatch getSuspenderAwaiterByName(String name) { - return suspenders + public static void countDownSuspenderByName(String name) { + suspenders .stream() .filter(element -> Objects.equals(element.getName(), name)) .toList() .getFirst() .getAwaiter() - .get(); + .get() + .countDown(); } + /** * Represents RepoAchiever Cluster suspend state guard. */ @Getter private final static ReentrantLock suspendGuard = new ReentrantLock(); -// /** -// * Represents a set of content updates head counter, pointing at the latest scanned head of the stream for the -// * provided content locations. As keys there are used provided location names and as values commit amounts are used. -// */ -// private final static Map contentUpdatesHeadCounterSet = new HashMap<>(); -// -// /** -// * Adds current content update head counter for the given location name with the given value. -// * -// * @param location given content location. -// * @param value given content value. -// */ -// public static void setContentUpdatesHeadCounter(String location, Integer value) { -// contentUpdatesHeadCounterSet.put(location, value); -// } - -// /** -// * Checks if current content update head counter for the given location name is below or equal to the given value. -// * -// * @return result of the check. -// */ -// public static Boolean isContentUpdateHeadCounterBelow(String location, Integer value) { -// return contentUpdatesHeadCounterSet.getOrDefault(location, 0) < value; -// } - -// /** -// * Resets current content update head counter. -// */ -// public static void resetContentUpdatesHeadCounter() { -// contentUpdatesHeadCounterSet.clear(); -// } - /** * Represents log message queue used to handle RepoAchiever API Server log message transfer. */ diff --git a/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java b/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java index dfbcd27..cf847ae 100644 --- a/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java +++ b/cluster/src/main/java/com/repoachiever/service/vendor/common/VendorConfigurationHelper.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.net.InetAddress; import java.security.MessageDigest; +import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -54,7 +55,9 @@ public GitHubLocationNotationDto parseLocationGitHubNotation(String location) throw new LocationDefinitionsAreNotValidException(); } - if (matcher.groupCount() == 4) { + String optionalMatch = matcher.group(4); + + if (matcher.groupCount() == 4 && Objects.nonNull(optionalMatch)) { return GitHubLocationNotationDto.of( matcher.group(1), matcher.group(2), diff --git a/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java b/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java index 04fea2f..52e70de 100644 --- a/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java +++ b/cluster/src/main/java/com/repoachiever/service/vendor/git/github/GitGitHubVendorService.java @@ -9,11 +9,14 @@ import com.repoachiever.exception.GitHubContentRetrievalFailureException; import com.repoachiever.exception.GitHubGraphQlClientDocumentNotFoundException; import com.repoachiever.exception.GitHubServiceNotAvailableException; +import com.repoachiever.logging.common.LoggingConfigurationHelper; import com.repoachiever.service.config.ConfigService; +import com.repoachiever.service.integration.scheduler.SchedulerConfigService; import com.repoachiever.service.state.StateService; import com.repoachiever.service.vendor.common.VendorConfigurationHelper; import jakarta.annotation.PostConstruct; import jakarta.ws.rs.core.HttpHeaders; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -270,6 +273,7 @@ public DataBuffer getCommitContent(String owner, String name, String format, Str .build()) .retrieve() .bodyToMono(DataBuffer.class) + .onErrorResume(element -> Mono.empty()) .block(); dataBufferAtomic.set(response); diff --git a/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java b/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java index e9ac179..3d65f2f 100644 --- a/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java +++ b/gui/src/main/java/com/repoachiever/service/element/list/ListVisualizer.java @@ -30,116 +30,125 @@ */ @Service public class ListVisualizer - implements IElementResizable, IElementActualizable, IElement> { - private final UUID id = UUID.randomUUID(); - - @Lazy - @Autowired - private MainDeploymentScene deploymentScene; - - public ListVisualizer( - @Autowired PropertiesEntity properties, - @Autowired ApplicationEventPublisher applicationEventPublisher, - @Lazy @Autowired MainDeploymentScene deploymentScene) { - ListView listView = new ListView<>(); - - listView.setCellFactory(element -> - new ListVisualizerCell(properties, applicationEventPublisher, deploymentScene)); - - listView.setOnMouseClicked( - event -> { - if (Objects.nonNull(listView.getSelectionModel().getSelectedItem())) { - ContentRetrievalResult content = StateService.getContent(); - - applicationEventPublisher.publishEvent( - new ContentSwapEvent( - content - .getLocations() - .stream() - .filter( - element -> - element - .getName() - .equals( - listView - .getSelectionModel() - .getSelectedItem() - .getName())) - .toList() - .getFirst())); - } - }); - - ElementStorage.setElement(id, listView); - ElementStorage.setActualizable(this); - ElementStorage.setResizable(this); - } - - /** - * @see IElement - */ - @Override - public ListView getContent() { - return ElementStorage.getElement(id); - } - - /** - * @see IElementResizable - */ - @Override - public void handlePrefWidth() { - getContent().setMaxWidth(StateService.getMainWindowWidth()); - } - - /** - * @see IElementResizable - */ - @Override - public void handlePrefHeight() { - getContent().setMaxHeight(StateService.getMainWindowHeight()); - } - - /** - * @see IElementActualizable - */ - @Override - public void handleBackgroundUpdates() { - ContentRetrievalResult content = StateService.getContent(); - - Platform.runLater( - () -> { - ObservableList observableList; - - if (!Objects.isNull(content)) { - List items = - content - .getLocations() - .stream() - .sorted(Comparator.comparing(ContentRetrievalUnit::getName)) - .map(element -> - ListVisualizerCellInputDto.of( - element.getName(), - element.getActive(), - element.getAdditional().getVersions().isEmpty() - && element.getRaw().getVersions().isEmpty())) - .toList(); - - observableList = - FXCollections.observableList(items); - - getContent().setMouseTransparent(false); - getContent().setFocusTraversable(true); - } else { - List items = Stream.of(ListVisualizerCellInputDto.stub()).toList(); - - observableList = - FXCollections.observableList(items); - - getContent().setMouseTransparent(true); - getContent().setFocusTraversable(false); - } - - getContent().setItems(observableList); - }); - } + implements IElementResizable, IElementActualizable, IElement> { + private final UUID id = UUID.randomUUID(); + + private PropertiesEntity properties; + + private ApplicationEventPublisher applicationEventPublisher; + + private MainDeploymentScene deploymentScene; + + public ListVisualizer( + @Autowired PropertiesEntity properties, + @Autowired ApplicationEventPublisher applicationEventPublisher, + @Lazy @Autowired MainDeploymentScene deploymentScene) { + ListView listView = new ListView<>(); + + listView.setCellFactory(element -> new ListVisualizerCell(properties, applicationEventPublisher, + deploymentScene)); + + listView.setOnMouseClicked( + event -> { + if (Objects.nonNull(listView.getSelectionModel().getSelectedItem())) { + ContentRetrievalResult content = StateService.getContent(); + + applicationEventPublisher.publishEvent( + new ContentSwapEvent( + content + .getLocations() + .stream() + .filter( + element -> element + .getName() + .equals( + listView + .getSelectionModel() + .getSelectedItem() + .getName())) + .toList() + .getFirst())); + } + }); + + this.properties = properties; + this.applicationEventPublisher = applicationEventPublisher; + this.deploymentScene = deploymentScene; + + ElementStorage.setElement(id, listView); + ElementStorage.setActualizable(this); + ElementStorage.setResizable(this); + } + + /** + * @see IElement + */ + @Override + public ListView getContent() { + return ElementStorage.getElement(id); + } + + /** + * @see IElementResizable + */ + @Override + public void handlePrefWidth() { + getContent().setMaxWidth(StateService.getMainWindowWidth()); + } + + /** + * @see IElementResizable + */ + @Override + public void handlePrefHeight() { + getContent().setMaxHeight(StateService.getMainWindowHeight()); + } + + /** + * @see IElementActualizable + */ + @Override + public void handleBackgroundUpdates() { + ContentRetrievalResult content = StateService.getContent(); + + Platform.runLater( + () -> { + ObservableList observableList; + + if (!Objects.isNull(content)) { + List items = content + .getLocations() + .stream() + .sorted(Comparator.comparing( + ContentRetrievalUnit::getName)) + .map(element -> ListVisualizerCellInputDto.of( + element.getName(), + element.getActive(), + element.getAdditional().getVersions() + .isEmpty() + && element.getRaw() + .getVersions() + .isEmpty())) + .toList(); + + observableList = FXCollections.observableList(items); + + getContent().setMouseTransparent(false); + getContent().setFocusTraversable(true); + } else { + List items = Stream + .of(ListVisualizerCellInputDto.stub()).toList(); + + observableList = FXCollections.observableList(items); + + getContent().setMouseTransparent(true); + getContent().setFocusTraversable(false); + } + + getContent().setCellFactory(element -> new ListVisualizerCell(properties, + applicationEventPublisher, deploymentScene)); + + getContent().setItems(observableList); + }); + } } diff --git a/pom.xml b/pom.xml index 1067c09..3668539 100644 --- a/pom.xml +++ b/pom.xml @@ -243,6 +243,11 @@ jboss-logging 3.4.3.Final + + org.jboss.logmanager + log4j2-jboss-logmanager + 2.0.1.Final + jakarta.json jakarta.json-api diff --git a/samples/config/api-server/api-server.yaml b/samples/config/api-server/api-server.yaml index 9d69084..17540ab 100644 --- a/samples/config/api-server/api-server.yaml +++ b/samples/config/api-server/api-server.yaml @@ -51,4 +51,4 @@ resource: # Represents a set of options used for RepoAchiever Cluster worker configuration. worker: # Represents frequency of requests to selected VCS provider resources. - frequency: "0/30 * * * * ?" \ No newline at end of file + frequency: "0 */5 * * * ?" \ No newline at end of file