Predicates to check commit messages and edits Adds predicate commit_message that returns the commit message as a symbol. commit_message_matches takes in a regex pattern and checks it against the commit message, returns true if a match is found. Adds predicate commit_edits that takes in a regex pattern for filenames and a regex pattern for edits. For all files in a commit that match the filename regex, if the edits in any of those files match the edit regex, then the predicate returns true. Change-Id: I1c0b5ddb669aaca77908e18d7bb314c5aa6aec70 (cherry picked from commit 0cec9e6f7ff1e62ce7f4e487e6a06e2a973baeb7)
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_edits_2.java b/gerrit-server/src/main/java/gerrit/PRED_commit_edits_2.java new file mode 100644 index 0000000..f9e3036 --- /dev/null +++ b/gerrit-server/src/main/java/gerrit/PRED_commit_edits_2.java
@@ -0,0 +1,171 @@ +// Copyright (C) 2011 The Android Open Source Project +// +// 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 gerrit; + +import com.google.gerrit.reviewdb.PatchSetInfo; +import com.google.gerrit.rules.PrologEnvironment; +import com.google.gerrit.rules.StoredValues; +import com.google.gerrit.server.patch.PatchList; +import com.google.gerrit.server.patch.PatchListEntry; +import com.google.gerrit.server.patch.Text; + +import com.googlecode.prolog_cafe.lang.IllegalTypeException; +import com.googlecode.prolog_cafe.lang.JavaException; +import com.googlecode.prolog_cafe.lang.Operation; +import com.googlecode.prolog_cafe.lang.PInstantiationException; +import com.googlecode.prolog_cafe.lang.Predicate; +import com.googlecode.prolog_cafe.lang.Prolog; +import com.googlecode.prolog_cafe.lang.PrologException; +import com.googlecode.prolog_cafe.lang.SystemException; +import com.googlecode.prolog_cafe.lang.Term; + +import org.eclipse.jgit.diff.Edit; +import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; + +import java.io.IOException; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Returns true if any of the files that match FileNameRegex have edited lines + * that match EditRegex + * + * <pre> + * 'commit_edits'(+FileNameRegex, +EditRegex) + * </pre> + */ +public class PRED_commit_edits_2 extends Predicate.P2 { + private static final long serialVersionUID = 1L; + + public PRED_commit_edits_2(Term a1, Term a2, Operation n) { + arg1 = a1; + arg2 = a2; + cont = n; + } + + @Override + public Operation exec(Prolog engine) throws PrologException { + engine.setB0(); + + Term a1 = arg1.dereference(); + Term a2 = arg2.dereference(); + + Pattern fileRegex = getRegexParameter(a1); + Pattern editRegex = getRegexParameter(a2); + + PrologEnvironment env = (PrologEnvironment) engine.control; + PatchSetInfo psInfo = StoredValues.PATCH_SET_INFO.get(engine); + PatchList pl = StoredValues.PATCH_LIST.get(engine); + Repository repo = StoredValues.REPOSITORY.get(engine); + + final ObjectReader reader = repo.newObjectReader(); + final RevTree aTree; + final RevTree bTree; + try { + final RevWalk rw = new RevWalk(reader); + final RevCommit bCommit = rw.parseCommit(pl.getNewId()); + + if (pl.getOldId() != null) { + aTree = rw.parseTree(pl.getOldId()); + } else { + // Octopus merge with unknown automatic merge result, since the + // web UI returns no files to match against, just fail. + return engine.fail(); + } + bTree = bCommit.getTree(); + + for (PatchListEntry entry : pl.getPatches()) { + String newName = entry.getNewName(); + String oldName = entry.getOldName(); + + if (newName.equals("/COMMIT_MSG")) { + continue; + } + + if (fileRegex.matcher(newName).find() || + (oldName != null && fileRegex.matcher(oldName).find())) { + List<Edit> edits = entry.getEdits(); + + if (edits.isEmpty()) { + continue; + } + Text tA; + if (oldName != null) { + tA = load(aTree, oldName, reader); + } else { + tA = load(aTree, newName, reader); + } + Text tB = load(bTree, newName, reader); + for (Edit edit : edits) { + if (tA != Text.EMPTY) { + String aDiff = tA.getString(edit.getBeginA(), edit.getEndA(), true); + if (editRegex.matcher(aDiff).find()) { + return cont; + } + } + if (tB != Text.EMPTY) { + String bDiff = tB.getString(edit.getBeginB(), edit.getEndB(), true); + if (editRegex.matcher(bDiff).find()) { + return cont; + } + } + } + } + } + } catch (IOException err) { + throw new JavaException(this, 1, err); + } finally { + reader.release(); + } + + return engine.fail(); + } + + private Pattern getRegexParameter(Term term) { + if (term.isVariable()) { + throw new PInstantiationException(this, 1); + } + if (!term.isSymbol()) { + throw new IllegalTypeException(this, 1, "symbol", term); + } + return Pattern.compile(term.name(), Pattern.MULTILINE); + } + + private Text load(final ObjectId tree, final String path, final ObjectReader reader) + throws MissingObjectException, IncorrectObjectTypeException, + CorruptObjectException, IOException { + if (path == null) { + return Text.EMPTY; + } + final TreeWalk tw = TreeWalk.forPath(reader, path, tree); + if (tw == null) { + return Text.EMPTY; + } + if (tw.getFileMode(0).getObjectType() != Constants.OBJ_BLOB) { + return Text.EMPTY; + } + return new Text(reader.open(tw.getObjectId(0), Constants.OBJ_BLOB)); + } +} \ No newline at end of file
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java b/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java new file mode 100644 index 0000000..8c94b34 --- /dev/null +++ b/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java
@@ -0,0 +1,55 @@ +// Copyright (C) 2011 The Android Open Source Project +// +// 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 gerrit; + +import com.google.gerrit.reviewdb.PatchSetInfo; +import com.google.gerrit.rules.StoredValues; + +import com.googlecode.prolog_cafe.lang.Operation; +import com.googlecode.prolog_cafe.lang.Predicate; +import com.googlecode.prolog_cafe.lang.Prolog; +import com.googlecode.prolog_cafe.lang.PrologException; +import com.googlecode.prolog_cafe.lang.SymbolTerm; +import com.googlecode.prolog_cafe.lang.Term; + +/** + * Returns the commit message as a symbol + * + * <pre> + * 'commit_message'(-Msg) + * </pre> + */ +public class PRED_commit_message_1 extends Predicate.P1 { + private static final long serialVersionUID = 1L; + + public PRED_commit_message_1(Term a1, Operation n) { + arg1 = a1; + cont = n; + } + + @Override + public Operation exec(Prolog engine) throws PrologException { + engine.setB0(); + Term a1 = arg1.dereference(); + + PatchSetInfo psInfo = StoredValues.PATCH_SET_INFO.get(engine); + + SymbolTerm msg = SymbolTerm.create(psInfo.getMessage()); + if (!a1.unify(msg, engine.trail)) { + return engine.fail(); + } + return cont; + } +} \ No newline at end of file
diff --git a/gerrit-server/src/main/prolog/gerrit_common.pl b/gerrit-server/src/main/prolog/gerrit_common.pl index eb83ffd..5342b84 100644 --- a/gerrit-server/src/main/prolog/gerrit_common.pl +++ b/gerrit-server/src/main/prolog/gerrit_common.pl
@@ -394,3 +394,12 @@ split_commit_delta(rename, NewPath, OldPath, add, NewPath) :- !. split_commit_delta(copy, NewPath, OldPath, add, NewPath) :- !. split_commit_delta(Type, Path, _, Type, Path). + + +%% commit_message_matches/1: +%% +:- public commit_message_matches/1. +%% +commit_message_matches(Pattern) :- + commit_message(Msg), + regex_matches(Pattern, Msg).