Skip to content

Commit

Permalink
Gitlab container and tests (#1335)
Browse files Browse the repository at this point in the history
* add docker fixture for gitlab

* create test

* pin gitlab version

* Remove addSSHCertificate in GitLabContainer

* add createRepo test

* Reword createRepo and add TODO

* add delete repo method

* automatically create a token to be used inside the container and adapt the methods

* add gitlab to renovate

* wait for gitlab to be running

* Changing over to java http client and cleanup

* modify the wait method

* use repo name in the delete method

* code review

* create multiple users

* configure dependabot for gitlab image

* try port mapping

* fix waitForReady

* test GitLab server configuration

* create separate method for credentials

* configure token in credentials

* remove renovate

* create the multibranch pipeline

* use existing method for repo creation

* use gitlab4j to create branches and MR

* add verification for jobs and add a failed job

* Try to wait for jobs to exist before checking build number

* code review

* create GitLab group and organization folder

* create and test GitLab organization folder

* try and check the builds

* check the builds run

* code review part 1

* code review part 2

* code review part 3

* code review part 4

* refactor and code review

---------

Co-authored-by: Julie Heard <[email protected]>
Co-authored-by: Raul Arabaolaza <[email protected]>
  • Loading branch information
3 people authored Sep 18, 2023
1 parent 5d3e2a8 commit 5e76540
Show file tree
Hide file tree
Showing 11 changed files with 601 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,7 @@ updates:
ignore:
- dependency-name: "ubuntu"
versions: [">=22.04"]
- package-ecosystem: "docker"
directory: "src/main/resources/org/jenkinsci/test/acceptance/docker/fixtures/GitLabContainer"
schedule:
interval: "weekly"
4 changes: 1 addition & 3 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@
"description": "We focus on Guice 6 until core adapts 7"
},
{
"matchPackagePatterns": [
"selenium"
],
"matchPackagePatterns": ["selenium"],
"groupName": "Selenium"
}
],
Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@
</pluginRepositories>

<dependencies>
<dependency>
<groupId>org.gitlab4j</groupId>
<artifactId>gitlab4j-api</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package org.jenkinsci.test.acceptance.docker.fixtures;

import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.GroupApi;
import org.gitlab4j.api.ProjectApi;
import org.gitlab4j.api.models.*;
import org.jenkinsci.test.acceptance.docker.Docker;
import org.jenkinsci.test.acceptance.docker.DockerContainer;
import org.jenkinsci.test.acceptance.docker.DockerFixture;

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

import org.jenkinsci.test.acceptance.po.CapybaraPortingLayer;
import org.jenkinsci.test.acceptance.utils.ElasticTime;


@DockerFixture(id = "gitlab-plugin", ports = {80, 443, 22})
public class GitLabContainer extends DockerContainer {
protected static final String REPO_DIR = "/home/gitlab/gitlabRepo";

private static final HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofMillis(200))
.build();

private static final ElasticTime time = new ElasticTime();

public String host() {
return ipBound(22);
}

public int sshPort() {
return port(22);
}


public int httpPort() {
return port(80);
}

public String httpHost() {
return ipBound(80);
}

public URL getURL() throws IOException {
return new URL("http://" + getIpAddress() + sshPort());
}

public URL getHttpUrl() throws IOException {
String url = "http://" + httpHost() + ':' + httpPort();
return new URL(url);
}

/** URL visible from the host. */
public String getRepoUrl() {
return "ssh://git@" + host() + ":" + sshPort() + REPO_DIR;
}

public void waitForReady(CapybaraPortingLayer p) {
p.waitFor().withMessage("Waiting for GitLab to come up")
.withTimeout(Duration.ofSeconds(200)) // GitLab starts in about 2 minutes add some headway
.pollingEvery(Duration.ofSeconds(2))
.until( () -> {
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(getHttpUrl().toURI())
.GET()
.timeout(Duration.ofSeconds(1))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body().contains("GitLab Community Edition");
} catch (IOException ignored) {
// we can not use .ignoring as this is a checked exception (even though a callable can throw this!)
return Boolean.FALSE;
}

});
}

public HttpResponse<String> createRepo(String repoName, String token) throws RuntimeException {
try{
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(getHttpUrl() + "/api/v4/projects"))
.header("Content-Type", "application/json")
.header("PRIVATE-TOKEN", token)
.POST(HttpRequest.BodyPublishers.ofString("{ \"name\": \"" + repoName + "\" }"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public void deleteRepo(String token, String repoName) throws IOException, GitLabApiException {
// get the project and delete the project
GitLabApi gitlabapi = new GitLabApi(getHttpUrl().toString(), token);
ProjectApi projApi = new ProjectApi(gitlabapi);

Project project = projApi.getProjects().stream().filter((proj -> repoName.equals(proj.getName()))).findAny().orElse(null);
projApi.deleteProject(project);
}

public String createUserToken(String userName, String password, String email, String isAdmin) throws IOException, InterruptedException {
return Docker.cmd("exec", getCid()).add("/bin/bash", "-c", "gitlab-rails runner -e production /usr/bin/create_user.rb" + " " + userName + " " + password + " " + email + " " + isAdmin)
.popen()
.verifyOrDieWith("Unable to create user").trim();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.jenkinsci.test.acceptance.plugins.gitlab_plugin;

import org.jenkinsci.test.acceptance.plugins.workflow_multibranch.BranchSource;
import org.jenkinsci.test.acceptance.plugins.workflow_shared_library.WorkflowSharedLibrary;
import org.jenkinsci.test.acceptance.po.Describable;
import org.jenkinsci.test.acceptance.po.WorkflowMultiBranchJob;

@Describable("GitLab Project")
public class GitLabBranchSource extends BranchSource {

public GitLabBranchSource(WorkflowMultiBranchJob job, String path) {
super(job, path);
}

public GitLabBranchSource(WorkflowSharedLibrary sharedLibrary, String path) {
super(sharedLibrary, path);
}

public void setOwner(String owner) {
find(by.path("/sources/source/projectOwner")).sendKeys(owner);
}

public void setProject(String owner, String project) {
find(by.path("/sources/source/projectPath")).click();
waitFor(by.option(owner + "/" + project)).click();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.jenkinsci.test.acceptance.plugins.gitlab_plugin;

import com.google.inject.Injector;
import org.apache.commons.io.IOUtils;
import org.jenkinsci.test.acceptance.po.*;

import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

@Describable("jenkins.branch.OrganizationFolder")
public class GitLabOrganizationFolder extends Folder {
public GitLabOrganizationFolder(Injector injector, URL url, String name) {
super(injector, url, name);
}

public void create(String owner) {
control(by.path("/hetero-list-add[navigators]")).click();
find(by.partialLinkText("GitLab Group")).click();
find(by.path("/navigators/projectOwner")).sendKeys(owner);
}

@Override
public URL getConfigUrl() {
return null;
}

public String getCheckLog() {
return driver.getPageSource();

}

public GitLabOrganizationFolder waitForCheckFinished(final int timeout) {
waitFor()
.withTimeout(Duration.ofSeconds(timeout))
.until(() -> GitLabOrganizationFolder.this.getCheckLog().contains("Finished: "));

return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.jenkinsci.test.acceptance.plugins.gitlab_plugin;

import org.jenkinsci.test.acceptance.plugins.credentials.BaseStandardCredentials;
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.Describable;
import org.jenkinsci.test.acceptance.po.PageAreaImpl;
import org.jenkinsci.test.acceptance.po.PageObject;

import static org.jenkinsci.test.acceptance.Matchers.hasContent;

@Describable("GitLab Personal Access Token")
public class GitLabPersonalAccessTokenCredential extends BaseStandardCredentials {

private Control token = control(by.path("/credentials/token"));

public GitLabPersonalAccessTokenCredential(PageObject context, String path) {
super(context, path);
}

public GitLabPersonalAccessTokenCredential(PageAreaImpl area, String relativePath) {
super(area, relativePath);
}

public void setToken(String gitLabToken) {
token.set(gitLabToken);
}

public void create() {
control(by.path("/Submit")).click();
waitFor(driver, hasContent("Global credentials"), 2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.jenkinsci.test.acceptance.plugins.gitlab_plugin;

import jakarta.inject.Inject;
import org.jenkinsci.test.acceptance.po.Control;
import org.jenkinsci.test.acceptance.po.Jenkins;
import org.jenkinsci.test.acceptance.po.PageAreaImpl;

import static org.jenkinsci.test.acceptance.Matchers.hasContent;

public class GitLabServerConfig extends PageAreaImpl {

private Control serverName = control("servers/name");
private Control serverUrl = control("servers/serverUrl");

@Inject
public GitLabServerConfig(Jenkins jenkins) {
super(jenkins, "/io-jenkins-plugins-gitlabserverconfig-servers-GitLabServers");
}

public void configureServer(String url) {
serverName.set("servername");
serverUrl.set(url);

waitFor(by.option("GitLab Personal Access Token")).click();

find(by.path("/io-jenkins-plugins-gitlabserverconfig-servers-GitLabServers/servers/validate-button")).click();

waitFor(driver, hasContent("Credentials verified for user"), 10);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Use the official GitLab Community Edition image as the base
FROM gitlab/gitlab-ce:16.2.4-ce.0

COPY create_user.rb /usr/bin/

# Expose the required ports
EXPOSE 80 443 22
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
input_array = ARGV

user = User.create();
user.name = input_array[0];
user.username = input_array[0];
user.password = input_array[1];
user.confirmed_at = '01/01/1990';
user.admin = input_array[3];
user.email = input_array[2];
user.save!;

token = user.personal_access_tokens.create(scopes: [:api], name: 'MyToken');
token.expires_at='01/01/2024';
token.save!;
puts token.token;
Loading

0 comments on commit 5e76540

Please sign in to comment.