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

Merge branch 'dev' into 'master'

feat: Create initial endpoint and add all supporting elements

Closes #79 and #78

See merge request !103
parents bbf613f4 cbe37fa5
No related branches found
No related tags found
1 merge request!103feat: Create initial endpoint and add all supporting elements
Pipeline #11755 passed
Showing
with 928 additions and 17 deletions
......@@ -26,4 +26,14 @@ CREATE TABLE IF NOT EXISTS `CommitValidationStatusGrouping` (
PRIMARY KEY (`commit_id`,`fingerprint`)
);
CREATE TABLE IF NOT EXISTS `PrivateProjectEvent` (
`userId` int(10) NOT NULL,
`projectId` int(10) NOT NULL,
`projectPath` varchar(255) NOT NULL,
`parentProject` int(10) DEFAULT NULL,
`creationDate` datetime NOT NULL,
`deletionDate` datetime DEFAULT NULL,
PRIMARY KEY (`userId`, `projectId`, `projectPath`)
);
ALTER TABLE CommitValidationMessage ADD COLUMN IF NOT EXISTS `committerEmail` varchar(255) DEFAULT NULL;
......@@ -5,7 +5,7 @@
<artifactId>git-eca</artifactId>
<version>1.1.0</version>
<properties>
<eclipse-api-version>0.6.6</eclipse-api-version>
<eclipse-api-version>0.6.7</eclipse-api-version>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>11</maven.compiler.source>
......
......@@ -68,7 +68,30 @@ paths:
403:
description: User exists with no ECA
404:
description: User not found
description: User not found
/webhooks/gitlab/system:
post:
tags:
- Gitlab system event processing
summary: Gitlab event processing
description: Process incoming system hooks from GitLab
parameters:
- in: header
name: X-Gitlab-Event
schema:
type: string
required: true
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/SystemHook"
responses:
200:
description: Success
500:
description: Error while processing data
components:
schemas:
......@@ -171,7 +194,7 @@ components:
description: The commit hash of the commit that was validated
additionalProperties:
$ref: "#/components/schemas/Commit"
Commit:
type: object
properties:
......@@ -190,7 +213,7 @@ components:
description: List of errors encountered in the validation of the current commit
items:
$ref: "#/components/schemas/CommitMessage"
CommitMessage:
type: object
properties:
......@@ -200,12 +223,12 @@ components:
message:
type: string
description: Information about the commit message. This can either be information about the validation process to report or the source of an error to be corrected.
CommitValidationStatuses:
type: array
items:
$ref: "#/components/schemas/CommitValidationStatus"
CommitValidationStatus:
type: object
properties:
......@@ -238,7 +261,7 @@ components:
type: array
items:
$ref: "#/components/schemas/CommitValidationMessage"
CommitValidationMessage:
type: object
properties:
......@@ -260,3 +283,49 @@ components:
provider_id:
type: string
description: the outward facing URL of the repo the commit belongs to.
SystemHook:
type: object
properties:
created_at:
$ref: "#/components/schemas/DateTime"
description: Time of the project creation event
updated_at:
$ref: "#/components/schemas/DateTime"
description: Time indicating the last event occured
event_name:
type: string
description: The event type
name:
type: string
description: The project name
owner_email:
type: string
description: The namespace's email. If not user, will be empty
owner_name:
type: string
description: The namespace name (group, user)
owners:
type: array
description: The project owners
items:
type: object
properties:
name:
type: string
description: The project owner user name
email:
type: string
description: The project owner email
path:
type: string
description: The project path
path_with_namespace:
type: string
description: The project path with namespace
project_id:
type: integer
description: The project's gitlab id
project_visibility:
type: string
description: "The project's visibility (public, private)"
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.api;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.eclipsefoundation.git.eca.model.GitlabProjectResponse;
/**
* Interface for interacting with the GitLab API. Used to fetch project data.
*/
@ApplicationScoped
@RegisterRestClient
public interface GitlabAPI {
/**
* Fetches data for a project using the projectId. The id and a token of
* adequate permissions is required.
*
* @param privateToken the header token
* @param projectId the project id
* @return A GitlabProjectResponse object
*/
@GET
@Path("/projects/{id}")
GitlabProjectResponse getProjectInfo(@HeaderParam("PRIVATE-TOKEN") String privateToken, @PathParam("id") int projectId);
}
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.dto;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.commons.lang3.StringUtils;
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;
@Entity
@Table
public class PrivateProjectEvent extends BareNode {
public static final DtoTable TABLE = new DtoTable(PrivateProjectEvent.class, "ppe");
@EmbeddedId
private EventCompositeId compositeId;
private Integer parentProject;
private LocalDateTime creationDate;
private LocalDateTime deletionDate;
public PrivateProjectEvent() {
}
public PrivateProjectEvent(Integer userId, Integer projectId, String projectPath) {
this.compositeId = new EventCompositeId();
this.compositeId.setUserId(userId);
this.compositeId.setProjectId(projectId);
this.compositeId.setProjectPath(projectPath);
}
@Override
public EventCompositeId getId() {
return getCompositeId();
}
public EventCompositeId getCompositeId() {
return this.compositeId;
}
public void setCompositeId(EventCompositeId compositeId) {
this.compositeId = compositeId;
}
public Integer getParentProject() {
return this.parentProject;
}
public void setParentProject(Integer parentProject) {
this.parentProject = parentProject;
}
public LocalDateTime getCreationDate() {
return this.creationDate;
}
public void setCreationDate(LocalDateTime creationDate) {
this.creationDate = creationDate;
}
public LocalDateTime getDeletionDate() {
return this.deletionDate;
}
public void setDeletionDate(LocalDateTime deletionDate) {
this.deletionDate = deletionDate;
}
@Embeddable
public static class EventCompositeId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer userId;
private Integer projectId;
private String projectPath;
public Integer getUserId() {
return this.userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getProjectId() {
return this.projectId;
}
public void setProjectId(Integer projectId) {
this.projectId = projectId;
}
public String getProjectPath() {
return this.projectPath;
}
public void setProjectPath(String projectPath) {
this.projectPath = projectPath;
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PrivateProjectEvent [userId=");
builder.append(getCompositeId().getUserId());
builder.append(", projectId=");
builder.append(getCompositeId().getProjectId());
builder.append(", projectPath=");
builder.append(getCompositeId().getProjectPath());
builder.append(", parentProject=");
builder.append(getParentProject());
builder.append(", creationDate=");
builder.append(getCreationDate());
builder.append(", deletionDate=");
builder.append(getDeletionDate());
builder.append("]");
return builder.toString();
}
@Singleton
public static class PrivateProjectEventFilter implements DtoFilter<PrivateProjectEvent> {
@Inject
ParameterizedSQLStatementBuilder builder;
@Override
public ParameterizedSQLStatement getFilters(MultivaluedMap<String, String> params, boolean isRoot) {
ParameterizedSQLStatement statement = builder.build(TABLE);
String userId = params.getFirst(GitEcaParameterNames.USER_ID.getName());
if (StringUtils.isNumeric(userId)) {
statement.addClause(new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".compositeId.userId = ?",
new Object[] { userId }));
}
String projectId = params.getFirst(GitEcaParameterNames.PROJECT_ID.getName());
if (StringUtils.isNumeric(projectId)) {
statement
.addClause(new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".compositeId.projectId = ?",
new Object[] { projectId }));
}
String projectPath = params.getFirst(GitEcaParameterNames.PROJECT_PATH.getName());
if (StringUtils.isNotBlank(projectPath)) {
statement.addClause(
new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".compositeId.projectPath = ?",
new Object[] { projectPath }));
}
String parentProject = params.getFirst(GitEcaParameterNames.PARENT_PROJECT.getName());
if (StringUtils.isNotBlank(parentProject)) {
statement.addClause(
new ParameterizedSQLStatement.Clause(TABLE.getAlias() + ".parentProject = ?",
new Object[] { parentProject }));
}
return statement;
}
@Override
public Class<PrivateProjectEvent> getType() {
return PrivateProjectEvent.class;
}
}
}
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.model;
import javax.annotation.Nullable;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
@AutoValue
@JsonDeserialize(builder = AutoValue_GitlabProjectResponse.Builder.class)
public abstract class GitlabProjectResponse {
public abstract Integer getId();
public abstract Integer getCreatorId();
@Nullable
public abstract ForkedProject getForkedFromProject();
public static Builder builder() {
return new AutoValue_GitlabProjectResponse.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setId(Integer id);
@JsonProperty("creator_id")
public abstract Builder setCreatorId(Integer creatorId);
@JsonProperty("forked_from_project")
public abstract Builder setForkedFromProject(@Nullable ForkedProject project);
public abstract GitlabProjectResponse build();
}
@AutoValue
@JsonDeserialize(builder = AutoValue_GitlabProjectResponse_ForkedProject.Builder.class)
public abstract static class ForkedProject {
public abstract Integer getId();
public static Builder builder() {
return new AutoValue_GitlabProjectResponse_ForkedProject.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setId(Integer id);
public abstract ForkedProject build();
}
}
}
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.model;
import java.time.ZonedDateTime;
import java.util.List;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.google.auto.value.AutoValue;
@AutoValue
@JsonDeserialize(builder = AutoValue_SystemHook.Builder.class)
public abstract class SystemHook {
public abstract ZonedDateTime getCreatedAt();
public abstract ZonedDateTime getUpdatedAt();
public abstract String getEventName();
public abstract String getName();
public abstract String getOwnerEmail();
public abstract String getOwnerName();
public abstract List<Owner> getOwners();
public abstract String getPath();
public abstract String getPathWithNamespace();
public abstract Integer getProjectId();
public abstract String getProjectVisibility();
public static Builder builder() {
return new AutoValue_SystemHook.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setCreatedAt(ZonedDateTime created);
public abstract Builder setUpdatedAt(ZonedDateTime updated);
public abstract Builder setEventName(String eventName);
public abstract Builder setName(String name);
public abstract Builder setOwnerEmail(String ownerEmail);
public abstract Builder setOwnerName(String ownerName);
public abstract Builder setOwners(List<Owner> owners);
public abstract Builder setPath(String path);
public abstract Builder setPathWithNamespace(String path);
public abstract Builder setProjectId(Integer projectId);
public abstract Builder setProjectVisibility(String visibility);
public abstract SystemHook build();
}
@AutoValue
@JsonDeserialize(builder = AutoValue_SystemHook_Owner.Builder.class)
public abstract static class Owner {
public abstract String getName();
public abstract String getEmail();
public static Builder builder() {
return new AutoValue_SystemHook_Owner.Builder();
}
@AutoValue.Builder
@JsonPOJOBuilder(withPrefix = "set")
public abstract static class Builder {
public abstract Builder setName(String name);
public abstract Builder setEmail(String email);
public abstract Owner build();
}
}
}
......@@ -26,16 +26,22 @@ public final class GitEcaParameterNames implements UrlParameterNamespace {
public static final String PROJECT_ID_RAW = "project_id";
public static final String REPO_URL_RAW = "repo_url";
public static final String FINGERPRINT_RAW = "fingerprint";
public static final String USER_ID_RAW = "user_id";
public static final String PROJECT_PATH_RAW = "project_id";
public static final String PARENT_PROJECT_RAW = "parent_project";
public static final UrlParameter COMMIT_ID = new UrlParameter(COMMIT_ID_RAW);
public static final UrlParameter SHA = new UrlParameter(SHA_RAW);
public static final UrlParameter SHAS = new UrlParameter(SHAS_RAW);
public static final UrlParameter PROJECT_ID = new UrlParameter(PROJECT_ID_RAW);
public static final UrlParameter REPO_URL = new UrlParameter(REPO_URL_RAW);
public static final UrlParameter FINGERPRINT = new UrlParameter(FINGERPRINT_RAW);
public static final UrlParameter USER_ID = new UrlParameter(USER_ID_RAW);
public static final UrlParameter PROJECT_PATH = new UrlParameter(PROJECT_PATH_RAW);
public static final UrlParameter PARENT_PROJECT = new UrlParameter(PARENT_PROJECT_RAW);
@Override
public List<UrlParameter> getParameters() {
return Arrays.asList(COMMIT_ID, SHA, SHAS, PROJECT_ID, REPO_URL);
return Arrays.asList(COMMIT_ID, SHA, SHAS, PROJECT_ID, REPO_URL, USER_ID, PROJECT_PATH, PARENT_PROJECT);
}
}
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.resource;
import javax.inject.Inject;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.git.eca.model.SystemHook;
import org.eclipsefoundation.git.eca.service.SystemHookService;
import org.jboss.resteasy.annotations.jaxrs.HeaderParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@Path("/webhooks")
public class WebhooksResource {
private static final Logger LOGGER = LoggerFactory.getLogger(WebhooksResource.class);
@Inject
RequestWrapper wrapper;
@Inject
SystemHookService hookService;
@Inject
ObjectMapper om;
@POST
@Path("/gitlab/system")
public Response processGitlabHook(@HeaderParam("X-Gitlab-Event") String eventHeader, String jsonBody) {
// Do not process if not a valid event
String eventName = readEventName(jsonBody);
if (eventName == null) {
return Response.ok().build();
}
// Do not process if the event isn't being tracked
if (!isValidHook(eventHeader, eventName, "project_create")) {
return Response.ok().build();
}
SystemHook hook = convertRequestToHook(jsonBody);
if (hook != null) {
hookService.processProjectCreateHook(wrapper, hook);
}
return Response.ok().build();
}
/**
* Processes the json body contents and converts them to a SystemHook object.
* Returns null if the json body couldn't be processed.
*
* @param jsonBody the json body as a string
* @return A SystemHook object converted from a json string
*/
private SystemHook convertRequestToHook(String jsonBody) {
try {
return om.readerFor(SystemHook.class).readValue(jsonBody);
} catch (JsonProcessingException e) {
LOGGER.error("Error converting JSON body into system hook", e);
return null;
}
}
/**
* Processes the json body contents and returns the event_name field. Returns
* null if the was a processing error or if the event_name field is
* null/missing.
*
* @param jsonBody the json body as a String
* @return the event_name field
*/
private String readEventName(String jsonBody) {
try {
return om.readTree(jsonBody).path("event_name").asText();
} catch (JsonProcessingException e) {
LOGGER.error("Error reading event_name from JSON body", e);
return null;
}
}
/**
* Validates that the hook header and body contain the required hook type.
*
* @param eventHeader the event header value
* @param eventName the event name
* @param hookType the desired hook type to compare against
* @return true if valid, false if not
*/
private boolean isValidHook(String eventHeader, String eventName, String eventType) {
return eventHeader.equalsIgnoreCase("system hook") && eventName.equalsIgnoreCase(eventType);
}
}
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.service;
import org.eclipsefoundation.core.model.RequestWrapper;
import org.eclipsefoundation.git.eca.model.SystemHook;
/**
* Processes the various system hooks received.
*/
public interface SystemHookService {
/**
* Processes a project_create hook
*
* @param wrapper
* @param hook
*/
void processProjectCreateHook(RequestWrapper wrapper, SystemHook hook);
}
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.service.impl;
import java.util.Arrays;
import java.util.Optional;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
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.model.RequestWrapper;
import org.eclipsefoundation.core.service.CachingService;
import org.eclipsefoundation.git.eca.api.GitlabAPI;
import org.eclipsefoundation.git.eca.dto.PrivateProjectEvent;
import org.eclipsefoundation.git.eca.model.GitlabProjectResponse;
import org.eclipsefoundation.git.eca.model.SystemHook;
import org.eclipsefoundation.git.eca.service.SystemHookService;
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;
@ApplicationScoped
public class DefaultSystemHookService implements SystemHookService {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSystemHookService.class);
@ConfigProperty(name = "eclipse.gitlab.access-token")
String apiToken;
@Inject
@RestClient
GitlabAPI api;
@Inject
CachingService cache;
@Inject
PersistenceDao dao;
@Inject
FilterService filters;
@Inject
ManagedExecutor managedExecutor;
@Override
public void processProjectCreateHook(RequestWrapper wrapper, SystemHook hook) {
managedExecutor.execute(new Runnable() {
@Override
public void run() {
trackPrivateProject(wrapper, hook);
}
});
}
/**
* Gathers all relevant data related to the created project and persists the
* information into a database
*
* @param wrapper the request wrapper containing all query params
* @param hook the incoming system hook
*/
private void trackPrivateProject(RequestWrapper wrapper, SystemHook hook) {
try {
Optional<GitlabProjectResponse> response = cache.get(Integer.toString(hook.getProjectId()),
new MultivaluedMapImpl<>(), GitlabProjectResponse.class,
() -> api.getProjectInfo(apiToken, hook.getProjectId()));
if (response.isPresent()) {
PrivateProjectEvent dto = mapToDto(hook, response.get());
dao.add(new RDBMSQuery<>(wrapper, filters.get(PrivateProjectEvent.class)), Arrays.asList(dto));
} else {
LOGGER.error("No info for project with id: {}", hook.getProjectId());
}
} catch (Exception e) {
LOGGER.error("Error fetching data relevant project data from GL for project: {}", hook.getProjectId());
}
}
/**
* Takes the received hook and Gitlab api response body and maps the values to a
* PrivateProjectEvent dto.
*
* @param hookthe received system hook
* @param gitlabInfo The gitlab project data
* @return A PrivateProjectEvent object
*/
private PrivateProjectEvent mapToDto(SystemHook hook, GitlabProjectResponse gitlabInfo) {
PrivateProjectEvent eventDto = new PrivateProjectEvent(gitlabInfo.getCreatorId(), hook.getProjectId(),
hook.getPathWithNamespace());
eventDto.setCreationDate(hook.getCreatedAt().toLocalDateTime());
if (gitlabInfo.getForkedFromProject() != null) {
eventDto.setParentProject(gitlabInfo.getForkedFromProject().getId());
}
return eventDto;
}
}
......@@ -2,6 +2,7 @@ quarkus.rest-client."org.eclipsefoundation.git.eca.api.AccountsAPI".scope=javax.
quarkus.rest-client."org.eclipsefoundation.git.eca.api.AccountsAPI".url=https://api.eclipse.org
org.eclipsefoundation.git.eca.api.ProjectsAPI/mp-rest/url=https://projects.eclipse.org
org.eclipsefoundation.git.eca.api.BotsAPI/mp-rest/url=https://api.eclipse.org
quarkus.rest-client."org.eclipsefoundation.git.eca.api.GitlabAPI".url=https://gitlab.eclipse.org/api/v4/
eclipse.noreply.email-patterns=@users.noreply.github.com\$
......
......@@ -108,12 +108,12 @@ class ValidationResourceTest {
/*
* BASIC VALIDATE CASES
*/
public static final EndpointTestCase VALIDATE_SUCCESS_CASE = TestCaseHelper.prepareSuccessCase(ECA_BASE_URL,
public static final EndpointTestCase VALIDATE_SUCCESS_CASE = TestCaseHelper.prepareTestCase(ECA_BASE_URL,
new String[] {}, SchemaNamespaceHelper.VALIDATION_RESPONSE_SCHEMA_PATH)
.setBodyValidationParams(SUCCESS_BODY_PARAMS).build();
public static final EndpointTestCase VALIDATE_FORBIDDEN_CASE = TestCaseHelper
.prepareSuccessCase(ECA_BASE_URL, new String[] {}, SchemaNamespaceHelper.VALIDATION_RESPONSE_SCHEMA_PATH)
.prepareTestCase(ECA_BASE_URL, new String[] {}, SchemaNamespaceHelper.VALIDATION_RESPONSE_SCHEMA_PATH)
.setStatusCode(403).setBodyValidationParams(FAIL_SINGLE_ERR_BODY_PARAMS).build();
/*
......@@ -287,7 +287,7 @@ class ValidationResourceTest {
Map<String, Object> bodyParams = new HashMap<>(FAIL_DOUBLE_ERR_BODY_PARAMS);
bodyParams.put("commits." + c1.getHash() + ".errors[0].code", APIStatusCode.ERROR_SPEC_PROJECT.getValue());
RestAssuredTemplates.testPost(TestCaseHelper.prepareSuccessCase(ECA_BASE_URL, new String[] {}, "")
RestAssuredTemplates.testPost(TestCaseHelper.prepareTestCase(ECA_BASE_URL, new String[] {}, "")
.setStatusCode(403).setBodyValidationParams(bodyParams).build(), vr);
}
......@@ -316,7 +316,7 @@ class ValidationResourceTest {
ValidationRequest vr = createGitHubRequest(false, "http://www.github.com/eclipsefdn/sample",
Arrays.asList(c1));
RestAssuredTemplates.testPost(TestCaseHelper.prepareSuccessCase(ECA_BASE_URL, new String[] {}, "")
RestAssuredTemplates.testPost(TestCaseHelper.prepareTestCase(ECA_BASE_URL, new String[] {}, "")
.setStatusCode(403).setBodyValidationParams(FAIL_DOUBLE_ERR_BODY_PARAMS).build(), vr);
}
......@@ -553,7 +553,7 @@ class ValidationResourceTest {
APIStatusCode.SUCCESS_SKIPPED.getValue());
// repeat call to test that skipped status is passed
RestAssuredTemplates.testPost(TestCaseHelper.prepareSuccessCase(ECA_BASE_URL, new String[] {}, "")
RestAssuredTemplates.testPost(TestCaseHelper.prepareTestCase(ECA_BASE_URL, new String[] {}, "")
.setBodyValidationParams(bodyParams).build(), vr);
}
......@@ -571,7 +571,7 @@ class ValidationResourceTest {
bodyParams.put("commits." + c1.getHash() + ".errors[0].code", APIStatusCode.ERROR_AUTHOR.getValue());
// repeat call to test that previously run check still fails
RestAssuredTemplates.testPost(TestCaseHelper.prepareSuccessCase(ECA_BASE_URL, new String[] {}, "")
RestAssuredTemplates.testPost(TestCaseHelper.prepareTestCase(ECA_BASE_URL, new String[] {}, "")
.setStatusCode(403).setBodyValidationParams(bodyParams).build(), vr);
}
......@@ -597,7 +597,7 @@ class ValidationResourceTest {
APIStatusCode.SUCCESS_SKIPPED.getValue());
// repeat call to test that previously run check still fails
RestAssuredTemplates.testPost(TestCaseHelper.prepareSuccessCase(ECA_BASE_URL, new String[] {}, "")
RestAssuredTemplates.testPost(TestCaseHelper.prepareTestCase(ECA_BASE_URL, new String[] {}, "")
.setStatusCode(403).setBodyValidationParams(bodyParams).build(), vr);
}
......@@ -611,7 +611,7 @@ class ValidationResourceTest {
Map<String, Object> bodyParams = new HashMap<>(FAIL_SINGLE_ERR_BODY_PARAMS);
bodyParams.put("commits." + c1.getHash() + ".errors[0].code", APIStatusCode.ERROR_AUTHOR.getValue());
EndpointTestCase testCase = TestCaseHelper.prepareSuccessCase(ECA_BASE_URL, new String[] {}, "")
EndpointTestCase testCase = TestCaseHelper.prepareTestCase(ECA_BASE_URL, new String[] {}, "")
.setStatusCode(403).setBodyValidationParams(bodyParams).build();
RestAssuredTemplates.testPost(testCase, vr);
......@@ -631,7 +631,7 @@ class ValidationResourceTest {
bodyParams = new HashMap<>(SUCCESS_BODY_PARAMS);
bodyParams.put("commits." + c1.getHash() + ".messages[0].code", APIStatusCode.SUCCESS_DEFAULT.getValue());
testCase = TestCaseHelper.prepareSuccessCase(ECA_BASE_URL, new String[] {}, "")
testCase = TestCaseHelper.prepareTestCase(ECA_BASE_URL, new String[] {}, "")
.setBodyValidationParams(bodyParams).build();
RestAssuredTemplates.testPost(testCase, vr);
......
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.resource;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import org.eclipsefoundation.git.eca.model.SystemHook;
import org.eclipsefoundation.git.eca.model.SystemHook.Owner;
import org.eclipsefoundation.testing.helpers.TestCaseHelper;
import org.eclipsefoundation.testing.templates.RestAssuredTemplates;
import org.eclipsefoundation.testing.templates.RestAssuredTemplates.EndpointTestCase;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
public class WebhoooksResourceTest {
public static final String WEBHOOKS_BASE_URL = "/webhooks";
public static final String GITLAB_HOOK_URL = WEBHOOKS_BASE_URL + "/gitlab/system";
public static final SystemHook PROJECT_CREATE_HOOK_VALID = SystemHook.builder()
.setCreatedAt(ZonedDateTime.now())
.setUpdatedAt(ZonedDateTime.now())
.setEventName("project_create")
.setName("TestProject")
.setOwnerEmail("testuser@eclipse-foundation.org")
.setOwnerName("Test User")
.setOwners(Arrays.asList(Owner.builder()
.setEmail("projectmaker@eclipse-foundation.org")
.setName("Project Maker")
.build()))
.setPath("TestProject")
.setPathWithNamespace("testuser/testproject")
.setProjectId(69)
.setProjectVisibility("private")
.build();
public static final SystemHook PROJECT_CREATE_HOOK_NOT_TRACKED = SystemHook.builder()
.setCreatedAt(ZonedDateTime.now())
.setUpdatedAt(ZonedDateTime.now())
.setEventName("project_update")
.setName("TestProject")
.setOwnerEmail("testuser@eclipse-foundation.org")
.setOwnerName("Test User")
.setOwners(Arrays.asList(Owner.builder()
.setEmail("projectmaker@eclipse-foundation.org")
.setName("Project Maker")
.build()))
.setPath("TestProject")
.setPathWithNamespace("testuser/testproject")
.setProjectId(69)
.setProjectVisibility("private")
.build();
public static final SystemHook PROJECT_CREATE_HOOK_MISSING_EVENT = SystemHook.builder()
.setCreatedAt(ZonedDateTime.now())
.setUpdatedAt(ZonedDateTime.now())
.setEventName("")
.setName("TestProject")
.setOwnerEmail("testuser@eclipse-foundation.org")
.setOwnerName("Test User")
.setOwners(Arrays.asList(Owner.builder()
.setEmail("projectmaker@eclipse-foundation.org")
.setName("Project Maker")
.build()))
.setPath("TestProject")
.setPathWithNamespace("testuser/testproject")
.setProjectId(69)
.setProjectVisibility("private")
.build();
public static final EndpointTestCase PROJECT_CREATE_SUCCESS = TestCaseHelper
.prepareTestCase(GITLAB_HOOK_URL, new String[] {}, null)
.setHeaderParams(Optional.of(Map.of("X-Gitlab-Event", "system hook")))
.build();
public static final EndpointTestCase PROJECT_CREATE_MISSING_HEADER = TestCaseHelper
.prepareTestCase(GITLAB_HOOK_URL, new String[] {}, null)
.setStatusCode(500)
.build();
@Test
void processGitlabHook_success() {
RestAssuredTemplates.testPost(PROJECT_CREATE_SUCCESS, PROJECT_CREATE_HOOK_VALID);
}
@Test
void processGitlabHook_success_untrackedEvent() {
RestAssuredTemplates.testPost(PROJECT_CREATE_SUCCESS, PROJECT_CREATE_HOOK_NOT_TRACKED);
}
@Test
void processGitlabHook_success_missingEventName() {
RestAssuredTemplates.testPost(PROJECT_CREATE_SUCCESS, PROJECT_CREATE_HOOK_MISSING_EVENT);
}
@Test
void processGitlabHook_failure_missingHeaderParam() {
RestAssuredTemplates.testPost(PROJECT_CREATE_MISSING_HEADER, PROJECT_CREATE_HOOK_VALID);
}
}
/*********************************************************************
* Copyright (c) 2022 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.git.eca.test.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.eclipsefoundation.git.eca.api.GitlabAPI;
import org.eclipsefoundation.git.eca.model.GitlabProjectResponse;
import org.eclipsefoundation.git.eca.model.GitlabProjectResponse.ForkedProject;
import io.quarkus.test.Mock;
@Mock
@RestClient
@ApplicationScoped
public class MockGitlabAPI implements GitlabAPI {
private List<GitlabProjectResponse> projects;
public MockGitlabAPI() {
projects = new ArrayList<>();
projects.addAll(Arrays.asList(
GitlabProjectResponse.builder()
.setId(69)
.setCreatorId(1)
.build(),
GitlabProjectResponse.builder()
.setId(42)
.setCreatorId(55)
.setForkedFromProject(ForkedProject.builder().setId(41).build())
.build(),
GitlabProjectResponse.builder()
.setId(95)
.setCreatorId(33)
.setForkedFromProject(ForkedProject.builder().setId(69).build())
.build()));
}
@Override
public GitlabProjectResponse getProjectInfo(String privateToken, int projectId) {
return projects.stream().filter(p -> p.getId() == projectId).findFirst().orElseGet(null);
}
}
......@@ -24,3 +24,5 @@ quarkus.oidc.enabled=false
quarkus.keycloak.devservices.enabled=false
quarkus.oidc-client.enabled=false
quarkus.http.port=8080
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