Skip to content

Commit

Permalink
Add more commit-attributes to Merge (#6641)
Browse files Browse the repository at this point in the history
The new property `Merge.getCommitMeta()` allows specifying more commit
attributes than just the message:
* message
* authors
* author-time
* signed-off-by
* properties

Fixes #5995
  • Loading branch information
snazy authored Apr 25, 2023
1 parent 1fad016 commit 574222b
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import javax.validation.constraints.NotBlank;
import org.projectnessie.error.NessieConflictException;
import org.projectnessie.error.NessieNotFoundException;
import org.projectnessie.model.CommitMeta;
import org.projectnessie.model.MergeResponse;
import org.projectnessie.model.Reference;

Expand All @@ -31,14 +32,25 @@ public interface MergeReferenceBuilder extends MergeTransplantBuilder<MergeRefer
/**
* Sets a custom merge commit message. The message is auto-generated if not set.
*
* <p>How the auto-generated message is constructed is not specified, but in general it will be
* based on the individual messages of the merged commits.
* <p>How the auto-generated message is constructed is not specified.
*
* @since {@link NessieApiV2}
* @see #commitMeta(CommitMeta)
*/
@Override
MergeReferenceBuilder message(String message);

/**
* Specify commit properties for the merge-commit, including the commit message, author(s), author
* timestamp, signed-off, properties.
*
* <p>If the given {@link CommitMeta} contains a non-empty message, the message specified via
* {@link #message(String)} will be ignored by the server.
*
* @since {@link NessieApiV2}
*/
MergeReferenceBuilder commitMeta(CommitMeta commitMeta);

MergeReferenceBuilder fromHash(
@NotBlank @jakarta.validation.constraints.NotBlank String fromHash);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.HashMap;
import java.util.Map;
import org.projectnessie.client.api.OnBranchBuilder;
import org.projectnessie.model.CommitMeta;
import org.projectnessie.model.ContentKey;
import org.projectnessie.model.MergeBehavior;
import org.projectnessie.model.MergeKeyBehavior;
Expand All @@ -33,13 +34,20 @@ public abstract class BaseMergeTransplantBuilder<B extends OnBranchBuilder<B>>
protected MergeBehavior defaultMergeMode;
protected Map<ContentKey, MergeKeyBehavior> mergeModes;
protected String message;
protected CommitMeta commitMeta;

@SuppressWarnings("unchecked")
public B message(String message) {
this.message = message;
return (B) this;
}

@SuppressWarnings("unchecked")
public B commitMeta(CommitMeta commitMeta) {
this.commitMeta = commitMeta;
return (B) this;
}

@SuppressWarnings("unchecked")
public B fromRefName(String fromRefName) {
this.fromRefName = fromRefName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.projectnessie.client.http.NessieApiClient;
import org.projectnessie.error.NessieConflictException;
import org.projectnessie.error.NessieNotFoundException;
import org.projectnessie.model.CommitMeta;
import org.projectnessie.model.MergeResponse;

final class HttpMergeReference extends BaseMergeReferenceBuilder {
Expand All @@ -36,6 +37,12 @@ public MergeReferenceBuilder message(String message) {
throw new UnsupportedOperationException("Merge message overrides are not supported in API v1.");
}

@Override
public MergeReferenceBuilder commitMeta(CommitMeta commitMeta) {
throw new UnsupportedOperationException(
"Merge commit-meta overrides are not supported in API v1.");
}

@Override
public MergeResponse merge() throws NessieNotFoundException, NessieConflictException {
ImmutableMerge.Builder merge =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public MergeResponse merge() throws NessieNotFoundException, NessieConflictExcep
.fromHash(fromHash)
.fromRefName(fromRefName)
.message(message)
.commitMeta(commitMeta)
.isDryRun(dryRun)
.isFetchAdditionalInfo(fetchAdditionalInfo)
.isReturnConflictAsResult(returnConflictAsResult);
Expand Down
13 changes: 13 additions & 0 deletions api/model/src/main/java/org/projectnessie/api/v2/params/Merge.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import static org.projectnessie.api.v2.doc.ApiDoc.RETURN_CONFLICTS_AS_RESULT_DESCRIPTION;
import static org.projectnessie.model.Validation.validateHash;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import javax.annotation.Nullable;
Expand All @@ -32,6 +34,7 @@
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.media.SchemaProperty;
import org.immutables.value.Value;
import org.projectnessie.model.CommitMeta;
import org.projectnessie.model.Validation;

@Schema(
Expand Down Expand Up @@ -73,8 +76,18 @@ public interface Merge extends BaseMergeTransplant {
@jakarta.annotation.Nullable
@Size
@jakarta.validation.constraints.Size(min = 1)
@Deprecated
String getMessage();

/**
* Optional: additional merge-commit attributes. If a commit message is specified in this
* attribute, {@link #getMessage()} will be ignored.
*/
@Nullable
@jakarta.annotation.Nullable
@JsonInclude(Include.NON_NULL)
CommitMeta getCommitMeta();

@NotBlank
@jakarta.validation.constraints.NotBlank
@Pattern(regexp = Validation.HASH_REGEX, message = Validation.HASH_MESSAGE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,9 +479,48 @@ public void commitMergeTransplant() throws Exception {
.extracting(EntriesResponse.Entry::getName)
.containsExactly(ContentKey.of("a"), ContentKey.of("b"));

api().mergeRefIntoBranch().fromRef(branch).branch(main).keepIndividualCommits(false).merge();
Reference main2 = api().getReference().refName(main.getName()).get();
soft.assertThat(api().getCommitLog().refName(main.getName()).get().getLogEntries()).hasSize(3);
Reference main2;
if (isV2()) {
api()
.mergeRefIntoBranch()
.fromRef(branch)
.branch(main)
.message("not the merge message")
.commitMeta(
CommitMeta.builder()
.message("My custom merge message")
.author("NessieHerself")
.signedOffBy("Arctic")
.authorTime(Instant.EPOCH)
.putProperties("property", "value")
.build())
.keepIndividualCommits(false)
.merge();
main2 = api().getReference().refName(main.getName()).get();
List<LogEntry> postMergeLog =
api().getCommitLog().refName(main.getName()).get().getLogEntries();
soft.assertThat(postMergeLog)
.hasSize(3)
.first()
.extracting(LogEntry::getCommitMeta)
.extracting(
CommitMeta::getMessage,
CommitMeta::getAllAuthors,
CommitMeta::getAllSignedOffBy,
CommitMeta::getAuthorTime,
CommitMeta::getProperties)
.containsExactly(
"My custom merge message",
singletonList("NessieHerself"),
singletonList("Arctic"),
Instant.EPOCH,
ImmutableMap.of("property", "value", "_merge_parent", branch.getHash()));
} else {
api().mergeRefIntoBranch().fromRef(branch).branch(main).keepIndividualCommits(false).merge();
main2 = api().getReference().refName(main.getName()).get();
soft.assertThat(api().getCommitLog().refName(main.getName()).get().getLogEntries())
.hasSize(3);
}

soft.assertThat(api().getEntries().reference(main2).get().getEntries())
.extracting(EntriesResponse.Entry::getName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.projectnessie.error.NessieConflictException;
import org.projectnessie.error.NessieNotFoundException;
import org.projectnessie.model.Branch;
import org.projectnessie.model.CommitMeta;
import org.projectnessie.model.EntriesResponse;
import org.projectnessie.model.ImmutableEntriesResponse;
import org.projectnessie.model.ImmutableLogResponse;
Expand Down Expand Up @@ -219,7 +220,7 @@ public MergeResponse transplantCommitsIntoBranch(
.transplantCommitsIntoBranch(
branchName,
expectedHash,
message,
message != null ? CommitMeta.fromMessage(message) : null,
transplant.getHashesToTransplant(),
transplant.getFromRefName(),
transplant.keepIndividualCommits(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.projectnessie.api.v2.params.Transplant;
import org.projectnessie.error.NessieConflictException;
import org.projectnessie.error.NessieNotFoundException;
import org.projectnessie.model.CommitMeta;
import org.projectnessie.model.CommitResponse;
import org.projectnessie.model.ContentKey;
import org.projectnessie.model.ContentResponse;
Expand All @@ -43,6 +44,7 @@
import org.projectnessie.model.EntriesResponse;
import org.projectnessie.model.GetMultipleContentsRequest;
import org.projectnessie.model.GetMultipleContentsResponse;
import org.projectnessie.model.ImmutableCommitMeta;
import org.projectnessie.model.ImmutableDiffResponse;
import org.projectnessie.model.ImmutableEntriesResponse;
import org.projectnessie.model.ImmutableGetMultipleContentsRequest;
Expand Down Expand Up @@ -320,11 +322,15 @@ public GetMultipleContentsResponse getMultipleContents(
public MergeResponse transplantCommitsIntoBranch(String branch, Transplant transplant)
throws NessieNotFoundException, NessieConflictException {
ParsedReference ref = resolveRef(branch);

String msg = transplant.getMessage();
CommitMeta meta = CommitMeta.fromMessage(msg == null ? "" : msg);

return tree()
.transplantCommitsIntoBranch(
ref.name(),
ref.hash(),
transplant.getMessage(),
meta,
transplant.getHashesToTransplant(),
transplant.getFromRefName(),
true,
Expand All @@ -340,14 +346,29 @@ public MergeResponse transplantCommitsIntoBranch(String branch, Transplant trans
public MergeResponse mergeRefIntoBranch(String branch, Merge merge)
throws NessieNotFoundException, NessieConflictException {
ParsedReference ref = resolveRef(branch);

@SuppressWarnings("deprecation")
String msg = merge.getMessage();

ImmutableCommitMeta.Builder meta = CommitMeta.builder();
CommitMeta commitMeta = merge.getCommitMeta();
if (commitMeta != null) {
meta.from(commitMeta);
if (commitMeta.getMessage().isEmpty() && msg != null) {
meta.message(msg);
}
} else {
meta.message(msg == null ? "" : msg);
}

return tree()
.mergeRefIntoBranch(
ref.name(),
ref.hash(),
merge.getFromRefName(),
merge.getFromHash(),
false,
merge.getMessage(),
meta.build(),
merge.getKeyMergeModes(),
merge.getDefaultKeyMergeMode(),
merge.isDryRun(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package org.projectnessie.services.impl;

import static java.util.Collections.singletonList;

import java.security.Principal;
import java.time.Instant;
import java.util.HashMap;
Expand Down Expand Up @@ -133,28 +135,51 @@ protected ServerAccessContext createAccessContext() {
}

protected MetadataRewriter<CommitMeta> commitMetaUpdate(
@Nullable @jakarta.annotation.Nullable String messageOverride) {
@Nullable @jakarta.annotation.Nullable CommitMeta commitMeta) {
return new MetadataRewriter<CommitMeta>() {
// Used for setting contextual commit properties during new and merge/transplant commits.
// WARNING: ONLY SET PROPERTIES, WHICH APPLY COMMONLY TO ALL COMMIT TYPES.
private final Principal principal = getPrincipal();
private final String committer = principal == null ? "" : principal.getName();
private final Instant now = Instant.now();

@Override
public CommitMeta rewriteSingle(CommitMeta metadata) {
ImmutableCommitMeta.Builder builder =
metadata.toBuilder()
.committer(committer)
.commitTime(now)
.author(metadata.getAuthor() == null ? committer : metadata.getAuthor())
.authorTime(metadata.getAuthorTime() == null ? now : metadata.getAuthorTime());

if (messageOverride != null) {
builder.message(messageOverride);
private CommitMeta buildCommitMeta(
ImmutableCommitMeta.Builder metadata, Supplier<String> defaultMessage) {

ImmutableCommitMeta pre = metadata.message("").build();

if (commitMeta != null && !commitMeta.getAllAuthors().isEmpty()) {
metadata.allAuthors(commitMeta.getAllAuthors());
} else if (pre.getAllAuthors().isEmpty()) {
metadata.allAuthors(singletonList(committer));
}

if (commitMeta != null && !commitMeta.getAllSignedOffBy().isEmpty()) {
metadata.allSignedOffBy(commitMeta.getAllSignedOffBy());
}

if (commitMeta != null && commitMeta.getAuthorTime() != null) {
metadata.authorTime(commitMeta.getAuthorTime());
} else if (pre.getAuthorTime() == null) {
metadata.authorTime(now);
}

if (commitMeta != null && !commitMeta.getAllProperties().isEmpty()) {
metadata.allProperties(commitMeta.getAllProperties());
}

return builder.build();
if (commitMeta != null && !commitMeta.getMessage().isEmpty()) {
metadata.message(commitMeta.getMessage());
} else {
metadata.message(defaultMessage.get());
}

return metadata.committer(committer).commitTime(now).build();
}

@Override
public CommitMeta rewriteSingle(CommitMeta metadata) {
return buildCommitMeta(CommitMeta.builder().from(metadata), metadata::getMessage);
}

@Override
Expand All @@ -163,30 +188,23 @@ public CommitMeta squash(List<CommitMeta> metadata) {
return rewriteSingle(metadata.get(0));
}

ImmutableCommitMeta.Builder newMeta =
CommitMeta.builder()
.committer(committer)
.commitTime(now)
.author(committer)
.authorTime(now);
StringBuilder newMessage = new StringBuilder();

if (messageOverride != null) {
newMessage.append(messageOverride);
}

Map<String, String> newProperties = new HashMap<>();
for (CommitMeta commitMeta : metadata) {
newProperties.putAll(commitMeta.getProperties());

if (messageOverride == null) {
if (newMessage.length() > 0) {
newMessage.append("\n---------------------------------------------\n");
}
newMessage.append(commitMeta.getMessage());
}
}
return newMeta.putAllProperties(newProperties).message(newMessage.toString()).build();

return buildCommitMeta(
CommitMeta.builder().properties(newProperties),
() -> {
StringBuilder newMessage = new StringBuilder();
for (CommitMeta commitMeta : metadata) {
if (newMessage.length() > 0) {
newMessage.append("\n---------------------------------------------\n");
}
newMessage.append(commitMeta.getMessage());
}
return newMessage.toString();
});
}
};
}
Expand Down
Loading

0 comments on commit 574222b

Please sign in to comment.