Skip to content

Commit

Permalink
Merge pull request #631 from diffplug/feat/merge-parent
Browse files Browse the repository at this point in the history
Base `ratchetFrom` on the merge base
  • Loading branch information
nedtwigg authored Jul 1, 2020
2 parents 08340a1 + c0c9da0 commit 989abbe
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
* `LineEnding.GIT_ATTRIBUTES` now creates a policy whose serialized state can be relocated from one machine to another. No user-visible change, but paves the way for remote build cache support in Gradle. ([#621](https://github.com/diffplug/spotless/pull/621))
### Added
* `prettier` will now autodetect the parser (and formatter) to use based on the filename, unless you override this using `config` or `configFile` with the option `parser` or `filepath`. ([#620](https://github.com/diffplug/spotless/pull/620))
* `GitRatchet` now lives in `lib-extra`, and is shared across `plugin-gradle` and `plugin-maven` ([#626](https://github.com/diffplug/spotless/pull/626)).
### Changed
* **BREAKING** `FileSignature` can no longer sign folders, only files. Signatures are now based only on filename (not path), size, and a content hash. It throws an error if a signature is attempted on a folder or on multiple files with different paths but the same filename - it never breaks silently. This change does not break any of Spotless' internal logic, so it is unlikely to affect any of Spotless' consumers either. ([#571](https://github.com/diffplug/spotless/pull/571))
* This change allows the maven plugin to cache classloaders across subprojects when loading config resources from the classpath (fixes [#559](https://github.com/diffplug/spotless/issues/559)).
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ VER_SLF4J=[1.6,2.0[

# Used in multiple places
VER_DURIAN=1.2.0
VER_JGIT=5.7.0.202003110725-r
VER_JGIT=5.8.0.202006091008-r
VER_JUNIT=4.13
VER_ASSERTJ=3.15.0
VER_MOCKITO=3.3.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import javax.annotation.Nullable;

Expand All @@ -31,6 +32,7 @@
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator;
Expand Down Expand Up @@ -195,13 +197,21 @@ public synchronized ObjectId rootTreeShaOf(Project project, String reference) {
Repository repo = repositoryFor(project);
ObjectId treeSha = rootTreeShaCache.get(repo, reference);
if (treeSha == null) {
ObjectId commitSha = repo.resolve(reference);
if (commitSha == null) {
throw new IllegalArgumentException("No such reference '" + reference + "'");
}
try (RevWalk revWalk = new RevWalk(repo)) {
RevCommit revCommit = revWalk.parseCommit(commitSha);
treeSha = revCommit.getTree();
ObjectId commitSha = repo.resolve(reference);
if (commitSha == null) {
throw new IllegalArgumentException("No such reference '" + reference + "'");
}

RevCommit ratchetFrom = revWalk.parseCommit(commitSha);
RevCommit head = revWalk.parseCommit(repo.resolve(Constants.HEAD));

revWalk.setRevFilter(RevFilter.MERGE_BASE);
revWalk.markStart(ratchetFrom);
revWalk.markStart(head);

RevCommit mergeBase = revWalk.next();
treeSha = Optional.ofNullable(mergeBase).orElse(ratchetFrom).getTree();
}
rootTreeShaCache.put(repo, reference, treeSha);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright 2020 DiffPlug
*
* 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 com.diffplug.spotless.extra;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefDatabase;
import org.junit.Test;

import com.diffplug.spotless.ResourceHarness;

public class GitRachetMergeBaseTest extends ResourceHarness {
@Test
public void test() throws IllegalStateException, GitAPIException, IOException {
try (Git git = initRepo()) {
setFile("mine.txt").toContent("init");
setFile("untouched.txt").toContent("init");
addAndCommit(git, "init");

git.checkout().setCreateBranch(true).setName("rem-branch").call();
// so at the point where we start work, we are clean relative to the remote
ratchetFrom("main", "rem-branch").allClean();

// but when the remote changes
setFile("untouched.txt").toContent("changed");
addAndCommit(git, "remote");

// it shouldn't affect files that we haven't changed
git.checkout().setName("main").call();
ratchetFrom("main", "rem-branch").allClean();

// and when we work, it should continue to only affect our own work
setFile("mine.txt").toContent("changed");
ratchetFrom("main", "rem-branch").onlyDirty("mine.txt");
}
}

static class GitRatchetSimple extends GitRatchet<File> {
@Override
protected File getDir(File project) {
return project;
}

@Override
protected File getParent(File project) {
return project.getParentFile();
}
}

Asserter ratchetFrom(String... ratchetFroms) {
return new Asserter(ratchetFroms);
}

class Asserter {
final GitRatchetSimple ratchet = new GitRatchetSimple();
final String[] ratchetFroms;
final ObjectId[] shas;

Asserter(String... ratchetFrom) {
this.ratchetFroms = ratchetFrom;
this.shas = Arrays.stream(ratchetFrom)
.map(from -> ratchet.rootTreeShaOf(rootFolder(), from))
.toArray(ObjectId[]::new);
}

private void assertClean(int i, String filename, boolean expected) throws IOException {
boolean actual = ratchet.isClean(rootFolder(), shas[i], newFile(filename));
if (actual != expected) {
throw new AssertionError("Expected " + filename + " to be " + (expected ? "clean" : "dirty") + " relative to " + ratchetFroms[i]);
}
}

public void allClean() throws IOException {
onlyDirty();
}

public void allDirty() throws IOException {
String[] filenames = Arrays.stream(rootFolder().listFiles())
.filter(File::isFile)
.map(File::getName)
.toArray(String[]::new);
onlyDirty(filenames);
}

public void onlyDirty(String... filenames) throws IOException {
List<String> dirtyFiles = Arrays.asList(filenames);
for (File file : rootFolder().listFiles()) {
if (!file.isFile()) {
continue;
}
boolean expectedClean = !dirtyFiles.contains(file.getName());
for (int i = 0; i < shas.length; ++i) {
assertClean(i, file.getName(), expectedClean);
}
}
}
}

private Git initRepo() throws IllegalStateException, GitAPIException, IOException {
Git git = Git.init().setDirectory(rootFolder()).call();
RefDatabase refDB = git.getRepository().getRefDatabase();
refDB.newUpdate(Constants.R_HEADS + "main", false).setNewObjectId(ObjectId.zeroId());
refDB.newUpdate(Constants.HEAD, false).link(Constants.R_HEADS + "main");
refDB.newUpdate(Constants.R_HEADS + Constants.MASTER, false).delete();
return git;
}

private void addAndCommit(Git git, String message) throws GitAPIException {
git.add().addFilepattern(".").call();
git.commit().setMessage(message).call();
}
}
1 change: 1 addition & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
* `prettier` will now autodetect the parser (and formatter) to use based on the filename, unless you override this using `config()` or `configFile()` with the option `parser` or `filepath`. ([#620](https://github.com/diffplug/spotless/pull/620))
### Fixed
* LineEndings.GIT_ATTRIBUTES is now a bit more efficient, and paves the way for remote build cache support in Gradle. ([#621](https://github.com/diffplug/spotless/pull/621))
* `ratchetFrom` now ratchets from the merge base of `HEAD` and the specified branch. This fixes the surprising behavior when a remote branch advanced ([#631](https://github.com/diffplug/spotless/pull/631) fixes [#627](https://github.com/diffplug/spotless/issues/627)).

## [4.4.0] - 2020-06-19
### Added
Expand Down

0 comments on commit 989abbe

Please sign in to comment.