Skip to content

Commit

Permalink
initial bc-github integration sample application
Browse files Browse the repository at this point in the history
  • Loading branch information
porcelli committed Oct 15, 2018
1 parent 0edb08d commit b2a5f57
Show file tree
Hide file tree
Showing 27 changed files with 1,793 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/target
/local
target/
# Eclipse, Netbeans and IntelliJ files
/.*
/**/.*
!.gitignore
/nbproject
*.ipr
*.iws
*.iml

# Repository wide ignore mac DS_Store files
.DS_Store

# Created by Zanata
/org.uberfire
/org.dashbuilder

# Live editing asciidoc leaves .html files behind in the source dir
uberfire-docs/src/main/asciidoc/*.html
**/dependency-reduced-pom.xml
45 changes: 45 additions & 0 deletions bc-github-githook/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" 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">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>me.porcelli.bc-github-integration</groupId>
<artifactId>bc-github-integration-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>bc-github-githook</artifactId>
<packaging>jar</packaging>

<name>bc-github-githook</name>

<dependencies>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<mainClass>porcelli.me.git.integration.githook.GitHook</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package porcelli.me.git.integration.githook;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.RefSpec;
import porcelli.me.git.integration.githook.command.GetPreviousCommitCommand;
import porcelli.me.git.integration.githook.command.GetRepoName;
import porcelli.me.git.integration.githook.command.SetupRemote;
import porcelli.me.git.integration.githook.command.SquashCommand;
import porcelli.me.git.integration.githook.command.TrackingStatus;
import porcelli.me.git.integration.githook.command.TrackingStatusCommand;
import porcelli.me.git.integration.githook.github.GitHubCredentials;
import porcelli.me.git.integration.githook.github.GitHubIntegration;

import static java.util.Comparator.comparing;

public class GitHook {

public static void main(String[] args) throws IOException, GitAPIException {
final Path currentPath = new File("").toPath().toAbsolutePath();
final String parentFolderName = currentPath.getParent().getName(currentPath.getParent().getNameCount() - 1).toString();
if (parentFolderName.equalsIgnoreCase("system")) {
return;
}
final Repository repo = new FileRepositoryBuilder()
.setGitDir(currentPath.toFile())
.build();

final Git git = new Git(repo);
final StoredConfig storedConfig = repo.getConfig();
final Set<String> remotes = storedConfig.getSubsections("remote");

final GitHubCredentials ghCredentials = new GitHubCredentials();
final GitHubIntegration integration = new GitHubIntegration(ghCredentials);

if (remotes.isEmpty()) {
new SetupRemote(ghCredentials, integration).execute(git, currentPath);
return;
}

final List<Ref> branches = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
final RevWalk revWalk = new RevWalk(git.getRepository());

branches.stream()
.map(branch -> {
try {
return revWalk.parseCommit(branch.getObjectId());
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.max(comparing((RevCommit commit) -> commit.getAuthorIdent().getWhen()))
.ifPresent(newestCommit -> {
RevCommit commit = newestCommit;
try {
boolean hasSyncOnCommitMessage = commit.getFullMessage().trim().startsWith("sync:");

if (hasSyncOnCommitMessage) {
final Map<ObjectId, String> branchesAffected = git
.nameRev()
.addPrefix("refs/heads")
.add(commit)
.call();

for (String remoteName : remotes) {
final String remoteURL = storedConfig.getString("remote", remoteName, "url");
for (String ref : branchesAffected.values()) {
final String remote = storedConfig.getString("branch", ref, "remote");

if (remote == null) {
git.push()
.setRefSpecs(new RefSpec(ref + ":" + ref))
.setRemote(remoteURL)
.setCredentialsProvider(ghCredentials.getCredentials())
.call();
storedConfig.setString("branch", ref, "remote", "origin");
storedConfig.setString("branch", ref, "merge", "refs/heads/" + ref);
storedConfig.save();
if (ref.contains("-pr")) {
integration.createPR(new GetRepoName().execute(currentPath), ref);
}
} else {
git.fetch().call();
final TrackingStatusCommand trackingStatusCommand = new TrackingStatusCommand(git.getRepository());
final TrackingStatus counts = trackingStatusCommand.getCounts(ref);
if (counts.getCommitsAhead() > 0) {
final RevCommit id = new GetPreviousCommitCommand(repo).execute(commit, counts.getCommitsAhead() - 1);
new SquashCommand(git, ref, id.name(), commit.getFullMessage()).execute(commit);
}
git.push()
.setRefSpecs(new RefSpec(ref + ":" + ref))
.setRemote(remoteURL)
.setCredentialsProvider(ghCredentials.getCredentials())
.call();
}
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package porcelli.me.git.integration.githook.command;

public interface Command {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package porcelli.me.git.integration.githook.command;

import java.io.IOException;

import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;

public class GetPreviousCommitCommand implements Command {

private final Repository repo;

public GetPreviousCommitCommand(Repository repo) {
this.repo = repo;
}

public RevCommit execute(final RevCommit commit,
final int commitsAhead) throws IOException {
RevCommit result = commit;
for (int i = 0; i < commitsAhead; i++) {
result = repo.parseCommit(repo.resolve(result.getParent(0).name()));
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package porcelli.me.git.integration.githook.command;

import java.nio.file.Path;

public class GetRepoName implements Command {

public String execute(final Path currentPath) {
return currentPath
.getName(currentPath.getNameCount() - 1)
.toString()
.replaceAll(".git", "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package porcelli.me.git.integration.githook.command;

import java.io.IOException;
import java.text.MessageFormat;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.revwalk.RevCommit;

import static java.util.Objects.requireNonNull;

public class RefUpdateCommand implements Command {

private final Git git;
private final String refName;
private final RevCommit commit;

public RefUpdateCommand(final Git git,
final String refName,
final RevCommit commit) {
this.git = requireNonNull(git);
this.refName = requireNonNull(refName);
this.commit = commit;
}

public void execute(final RevCommit lastCommit)
throws IOException, ConcurrentRefUpdateException {
requireNonNull(lastCommit, "lastCommit");
final RefUpdate ru = git.getRepository().updateRef("refs/heads/" + refName);
if (commit == null) {
ru.setExpectedOldObjectId(ObjectId.zeroId());
} else {
ru.setExpectedOldObjectId(commit);
}
ru.setNewObjectId(lastCommit.getId());
ru.setRefLogMessage(commit.getFullMessage(), false);
forceUpdate(ru, commit.getId());
}

private void forceUpdate(final RefUpdate ru,
final ObjectId id) throws IOException, ConcurrentRefUpdateException {
final RefUpdate.Result rc = ru.forceUpdate();
switch (rc) {
case NEW:
case FORCED:
case FAST_FORWARD:
case NO_CHANGE:
break;
case REJECTED:
case LOCK_FAILURE:
throw new ConcurrentRefUpdateException(JGitText.get().couldNotLockHEAD,
ru.getRef(),
rc);
default:
throw new JGitInternalException(MessageFormat.format(JGitText.get().updatingRefFailed,
Constants.HEAD,
id.toString(),
rc));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package porcelli.me.git.integration.githook.command;

import java.io.IOException;
import java.nio.file.Path;
import java.util.List;

import porcelli.me.git.integration.githook.github.GitHubCredentials;
import porcelli.me.git.integration.githook.github.GitHubIntegration;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.CredentialsProvider;

public class SetupRemote implements Command {

private final GitHubCredentials credentials;
private final GitHubIntegration integration;

public SetupRemote(GitHubCredentials credentials,
GitHubIntegration integration) {
this.credentials = credentials;
this.integration = integration;
}

public String execute(final Git git,
final Path currentPath) throws IOException, GitAPIException {
final StoredConfig storedConfig = git.getRepository().getConfig();

final String repoName = new GetRepoName().execute(currentPath);
final String remoteURL = integration.createRepository(repoName);
storedConfig.setString("remote", "origin", "url", remoteURL);
storedConfig.setString("remote", "origin", "fetch", "+refs/heads/*:refs/remotes/origin/*");

final List<Ref> branches = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
for (Ref value : branches) {
final String shortName = value.getName().replaceAll("refs/heads/", "");
storedConfig.setString("branch", shortName, "remote", "origin");
storedConfig.setString("branch", shortName, "merge", "refs/heads/" + shortName);
}
storedConfig.save();

git.push().setCredentialsProvider(credentials.getCredentials()).call();
return repoName;
}
}
Loading

0 comments on commit b2a5f57

Please sign in to comment.