Skip to content
Permalink
Browse files

Put the credentials lock in the remote repository

Reviewed-by: ehelin
  • Loading branch information
Robin Westberg
Robin Westberg committed Jul 1, 2019
1 parent 728cfa1 commit c704f49fa839e3ecc3722103344f885e61838fb6
Showing with 67 additions and 26 deletions.
  1. +5 −0 build.gradle
  2. +62 −26 test/src/main/java/org/openjdk/skara/test/HostCredentials.java
@@ -51,6 +51,11 @@ configure(subprojects.findAll() { it.name != 'bots' }) {
test {
useJUnitPlatform()

if (findProperty('credentials')) {
systemProperty "credentials", findProperty('credentials')
systemProperties(System.getProperties())
}

testLogging {
events "passed", "skipped", "failed"
}
@@ -25,22 +25,23 @@
import org.openjdk.skara.host.*;
import org.openjdk.skara.host.network.URIBuilder;
import org.openjdk.skara.json.*;
import org.openjdk.skara.vcs.*;

import org.junit.jupiter.api.TestInfo;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.time.Duration;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.logging.Logger;

public class HostCredentials implements AutoCloseable {
private final String testName;
private final Credentials credentials;
private final Path credentialsLock;
private final List<PullRequest> pullRequestsToBeClosed = new ArrayList<>();
private boolean hasCredentialsLock;
private HostedRepository credentialsLock;
private int nextHostIndex;

private final Logger log = Logger.getLogger("org.openjdk.skara.test");
@@ -175,43 +176,78 @@ public HostCredentials(TestInfo testInfo) throws IOException {
// If no credentials have been specified, use the test host implementation
if (credentialsFile == null) {
credentials = new TestCredentials();
credentialsLock = null;
} else {
credentialsLock = Path.of(credentialsFile + ".lock");

var credentialsPath = Paths.get(credentialsFile);
var credentialsData = Files.readAllBytes(credentialsPath);
var credentialsJson = JSON.parse(new String(credentialsData, StandardCharsets.UTF_8));
credentials = parseEntry(credentialsJson.asObject(), credentialsPath.getParent());
}
}

public HostedRepository getHostedRepository() {
if (credentialsLock != null && !hasCredentialsLock) {
var tmpLock = Path.of(credentialsLock + "." + testName + ".tmp");
private boolean getLock(HostedRepository repo) throws IOException {
try (var tempFolder = new TemporaryDirectory()) {
var repoFolder = tempFolder.path().resolve("lock");
var lockFile = repoFolder.resolve("lock.txt");
Repository localRepo;
try {
Files.writeString(tmpLock, testName);
localRepo = Repository.materialize(repoFolder, repo.getUrl(), "testlock");
} catch (IOException e) {
throw new UncheckedIOException(e);
// If the branch does not exist, we'll try to create it
localRepo = Repository.init(repoFolder, VCS.GIT);
}

while (!hasCredentialsLock) {
try {
Files.move(tmpLock, credentialsLock);
log.info("Obtained credentials lock for " + testName);
hasCredentialsLock = true;
} catch (IOException e) {
log.fine("Failed to obtain credentials lock for " + testName + ", waiting...");
try {
Thread.sleep(Duration.ofSeconds(1).toMillis());
} catch (InterruptedException ignored) {
}
if (Files.exists(lockFile)) {
var currentLock = Files.readString(lockFile, StandardCharsets.UTF_8);
var lockTime = ZonedDateTime.parse(currentLock, DateTimeFormatter.ISO_DATE_TIME);
if (lockTime.isBefore(ZonedDateTime.now().minus(Duration.ofMinutes(10)))) {
log.info("Stale lock encountered - overwriting it");
} else {
log.info("Active lock encountered - waiting");
return false;
}
}

// The lock either doesn't exist or is stale, try to grab it
Files.writeString(lockFile, ZonedDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME), StandardCharsets.UTF_8);
localRepo.add(lockFile);
var lockHash = localRepo.commit("Lock", "test", "test@test.test");
localRepo.push(lockHash, repo.getUrl(), "testlock");
log.info("Obtained credentials lock");

// If no exception occurs (such as the push fails), we have obtained the lock
return true;
}
}

private void releaseLock(HostedRepository repo) throws IOException {
try (var tempFolder = new TemporaryDirectory()) {
var repoFolder = tempFolder.path().resolve("lock");
var lockFile = repoFolder.resolve("lock.txt");
Repository localRepo;
localRepo = Repository.materialize(repoFolder, repo.getUrl(), "testlock");
localRepo.remove(lockFile);
var lockHash = localRepo.commit("Unlock", "test", "test@test.test");
localRepo.push(lockHash, repo.getUrl(), "testlock");
}
}

public HostedRepository getHostedRepository() {
var host = getHost();
return credentials.getHostedRepository(host);
var repo = credentials.getHostedRepository(host);

while (credentialsLock == null) {
try {
if (getLock(repo)) {
credentialsLock = repo;
}
} catch (IOException e) {
try {
Thread.sleep(Duration.ofSeconds(1).toMillis());
} catch (InterruptedException ignored) {
}
}
}
return repo;
}

public PullRequest createPullRequest(HostedRepository hostedRepository, String targetRef, String sourceRef, String title) {
@@ -229,14 +265,14 @@ public void close() {
for (var pr : pullRequestsToBeClosed) {
pr.setState(PullRequest.State.CLOSED);
}
if (credentialsLock != null && hasCredentialsLock) {
if (credentialsLock != null) {
try {
Files.delete(credentialsLock);
releaseLock(credentialsLock);
log.info("Released credentials lock for " + testName);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
hasCredentialsLock = false;
credentialsLock = null;
}

credentials.close();

0 comments on commit c704f49

Please sign in to comment.
You can’t perform that action at this time.