]> source.dussan.org Git - jgit.git/commitdiff
Support force writing reflog on a per-update basis 96/102396/5
authorDave Borowitz <dborowitz@google.com>
Tue, 1 Aug 2017 12:53:33 +0000 (08:53 -0400)
committerDavid Pursehouse <david.pursehouse@gmail.com>
Sat, 30 Sep 2017 10:55:31 +0000 (11:55 +0100)
Even if a repository has core.logAllRefUpdates=true, ReflogWriter does
not create reflog files unless the refs are under a hard-coded list of
prefixes, or unless the forceWrite bit is set. Expose the forceWrite bit
on a per-update basis in RefUpdate/BatchRefUpdate/ReceiveCommand,
creating RefLogWriters as necessary.

Change-Id: Ifc851fba00f76bf56d4134f821d0576b37810f80

org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefUpdateTest.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackedBatchRefUpdate.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommand.java

index 8097cd6ae178fe7b5363d120d337a93430d45842..3c4b8cf4bca93ea613f06b34af286501d7c3b970 100644 (file)
@@ -142,11 +142,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
                super.setUp();
 
                diskRepo = createBareRepository();
-               StoredConfig cfg = diskRepo.getConfig();
-               cfg.load();
-               cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
-                               ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
-               cfg.save();
+               setLogAllRefUpdates(true);
 
                refdir = (RefDirectory) diskRepo.getRefDatabase();
                refdir.setRetrySleepMs(Arrays.asList(0, 0));
@@ -655,6 +651,71 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
                                getLastReflog("refs/heads/branch"));
        }
 
+       @Test
+       public void refLogNotWrittenWithoutConfigOption() throws Exception {
+               setLogAllRefUpdates(false);
+               writeRef("refs/heads/master", A);
+
+               Map<String, ReflogEntry> oldLogs =
+                               getLastReflogs("refs/heads/master", "refs/heads/branch");
+               assertTrue(oldLogs.isEmpty());
+
+               List<ReceiveCommand> cmds = Arrays.asList(
+                               new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+                               new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+               execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false));
+
+               assertResults(cmds, OK, OK);
+               assertReflogUnchanged(oldLogs, "refs/heads/master");
+               assertReflogUnchanged(oldLogs, "refs/heads/branch");
+       }
+
+       @Test
+       public void forceRefLogInUpdate() throws Exception {
+               setLogAllRefUpdates(false);
+               writeRef("refs/heads/master", A);
+               assertTrue(
+                               getLastReflogs("refs/heads/master", "refs/heads/branch").isEmpty());
+
+               List<ReceiveCommand> cmds = Arrays.asList(
+                               new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+                               new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+               execute(
+                               newBatchUpdate(cmds)
+                                               .setRefLogMessage("a reflog", false)
+                                               .setForceRefLog(true));
+
+               assertResults(cmds, OK, OK);
+               assertReflogEquals(
+                               reflog(A, B, new PersonIdent(diskRepo), "a reflog"),
+                               getLastReflog("refs/heads/master"));
+               assertReflogEquals(
+                               reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog"),
+                               getLastReflog("refs/heads/branch"));
+       }
+
+       @Test
+       public void forceRefLogInCommand() throws Exception {
+               setLogAllRefUpdates(false);
+               writeRef("refs/heads/master", A);
+
+               Map<String, ReflogEntry> oldLogs =
+                               getLastReflogs("refs/heads/master", "refs/heads/branch");
+               assertTrue(oldLogs.isEmpty());
+
+               List<ReceiveCommand> cmds = Arrays.asList(
+                               new ReceiveCommand(A, B, "refs/heads/master", UPDATE),
+                               new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE));
+               cmds.get(1).setForceRefLog(true);
+               execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", false));
+
+               assertResults(cmds, OK, OK);
+               assertReflogUnchanged(oldLogs, "refs/heads/master");
+               assertReflogEquals(
+                               reflog(zeroId(), B, new PersonIdent(diskRepo), "a reflog"),
+                               getLastReflog("refs/heads/branch"));
+       }
+
        @Test
        public void packedRefsLockFailure() throws Exception {
                writeLooseRef("refs/heads/master", A);
@@ -791,6 +852,14 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
                                "refs/heads/branch", B);
        }
 
+       private void setLogAllRefUpdates(boolean enable) throws Exception {
+               StoredConfig cfg = diskRepo.getConfig();
+               cfg.load();
+               cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+                               ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, enable);
+               cfg.save();
+       }
+
        private void writeLooseRef(String name, AnyObjectId id) throws IOException {
                write(new File(diskRepo.getDirectory(), name), id.name() + "\n");
        }
index 34f9eb95d9f29edd0bbb624aaed65bcd762b99ad..52861ecd5371768c37fbcf7db9d490d6a1b74cb8 100644 (file)
@@ -1018,7 +1018,7 @@ public class RefUpdateTest extends SampleDataRepositoryTestCase {
                RefDirectory refs = (RefDirectory) db.getRefDatabase();
                RefDirectoryUpdate update = refs.newUpdate(refName, true);
                update.setNewObjectId(newId);
-               refs.log(update, msg, true);
+               refs.log(false, update, msg, true);
        }
 
        private static class SubclassedId extends ObjectId {
index 0bb502dfbf78df7112288c382e17512f22730b14..b328eb83e08c30302c25def5a87b83a9b1651005 100644 (file)
@@ -406,7 +406,6 @@ class PackedBatchRefUpdate extends BatchRefUpdate {
                if (ident == null) {
                        ident = new PersonIdent(refdb.getRepository());
                }
-               ReflogWriter w = refdb.getLogWriter();
                for (ReceiveCommand cmd : commands) {
                        // Assume any pending commands have already been executed atomically.
                        if (cmd.getResult() != ReceiveCommand.Result.OK) {
@@ -436,7 +435,8 @@ class PackedBatchRefUpdate extends BatchRefUpdate {
                                }
                        }
                        try {
-                               w.log(name, cmd.getOldId(), cmd.getNewId(), ident, msg);
+                               new ReflogWriter(refdb, isForceRefLog(cmd))
+                                               .log(name, cmd.getOldId(), cmd.getNewId(), ident, msg);
                        } catch (IOException e) {
                                // Ignore failures, but continue attempting to write more reflogs.
                                //
index 105efe7289e3383b00a7ed20dcdd3989467e1ce4..bb1dc91cdbf376a0a54bb5add19ebb3239adde3e 100644 (file)
@@ -151,8 +151,6 @@ public class RefDirectory extends RefDatabase {
 
        final File refsDir;
 
-       private final ReflogWriter logWriter;
-
        final File packedRefsFile;
 
        final File logsDir;
@@ -210,7 +208,6 @@ public class RefDirectory extends RefDatabase {
                final FS fs = db.getFS();
                parent = db;
                gitDir = db.getDirectory();
-               logWriter = new ReflogWriter(this);
                refsDir = fs.resolve(gitDir, R_REFS);
                logsDir = fs.resolve(gitDir, LOGS);
                logsRefsDir = fs.resolve(gitDir, LOGS + '/' + R_REFS);
@@ -224,8 +221,8 @@ public class RefDirectory extends RefDatabase {
                return parent;
        }
 
-       ReflogWriter getLogWriter() {
-               return logWriter;
+       ReflogWriter newLogWriter(boolean force) {
+               return new ReflogWriter(this, force);
        }
 
        /**
@@ -249,7 +246,7 @@ public class RefDirectory extends RefDatabase {
                FileUtils.mkdir(refsDir);
                FileUtils.mkdir(new File(refsDir, R_HEADS.substring(R_REFS.length())));
                FileUtils.mkdir(new File(refsDir, R_TAGS.substring(R_REFS.length())));
-               logWriter.create();
+               newLogWriter(false).create();
        }
 
        @Override
@@ -866,9 +863,9 @@ public class RefDirectory extends RefDatabase {
                }
        }
 
-       void log(final RefUpdate update, final String msg, final boolean deref)
+       void log(boolean force, RefUpdate update, String msg, boolean deref)
                        throws IOException {
-               logWriter.log(update, msg, deref);
+               newLogWriter(force).log(update, msg, deref);
        }
 
        private Ref resolve(final Ref ref, int depth, String prefix,
index 1105352524fac42a8fe9e9070ad47a78e1c6aa51..7ab30faf1027a717f650937b0fc67200ecb60415 100644 (file)
@@ -120,7 +120,7 @@ class RefDirectoryUpdate extends RefUpdate {
                                                msg = strResult;
                                }
                        }
-                       database.log(this, msg, shouldDeref);
+                       database.log(isForceRefLog(), this, msg, shouldDeref);
                }
                if (!lock.commit())
                        return Result.LOCK_FAILURE;
@@ -159,7 +159,7 @@ class RefDirectoryUpdate extends RefUpdate {
 
                String msg = getRefLogMessage();
                if (msg != null)
-                       database.log(this, msg, false);
+                       database.log(isForceRefLog(), this, msg, false);
                if (!lock.commit())
                        return Result.LOCK_FAILURE;
                database.storedSymbolicRef(this, lock.getCommitSnapshot(), target);
index 956607c9a8fe6105cb66f30e2fb773dec026e299..bcf9065dd2e8e4b1820a3c4e6b78801e98574a4f 100644 (file)
@@ -104,6 +104,12 @@ public class BatchRefUpdate {
        /** Should the result value be appended to {@link #refLogMessage}. */
        private boolean refLogIncludeResult;
 
+       /**
+        * Should reflogs be written even if the configured default for this ref is
+        * not to write it.
+        */
+       private boolean forceRefLog;
+
        /** Push certificate associated with this update. */
        private PushCertificate pushCert;
 
@@ -198,6 +204,12 @@ public class BatchRefUpdate {
        /**
         * Set the message to include in the reflog.
         * <p>
+        * Repository implementations may limit which reflogs are written by default,
+        * based on the project configuration. If a repo is not configured to write
+        * logs for this ref by default, setting the message alone may have no effect.
+        * To indicate that the repo should write logs for this update in spite of
+        * configured defaults, use {@link #setForceRefLog(boolean)}.
+        * <p>
         * Describes the default for commands in this batch that do not override it
         * with {@link ReceiveCommand#setRefLogMessage(String, boolean)}.
         *
@@ -235,6 +247,18 @@ public class BatchRefUpdate {
                return this;
        }
 
+       /**
+        * Force writing a reflog for the updated ref.
+        *
+        * @param force whether to force.
+        * @return {@code this}
+        * @since 4.9
+        */
+       public BatchRefUpdate setForceRefLog(boolean force) {
+               forceRefLog = force;
+               return this;
+       }
+
        /**
         * Check whether log has been disabled by {@link #disableRefLog()}.
         *
@@ -244,6 +268,16 @@ public class BatchRefUpdate {
                return refLogMessage == null;
        }
 
+       /**
+        * Check whether the reflog should be written regardless of repo defaults.
+        *
+        * @return whether force writing is enabled.
+        * @since 4.9
+        */
+       protected boolean isForceRefLog() {
+               return forceRefLog;
+       }
+
        /**
         * Request that all updates in this batch be performed atomically.
         * <p>
@@ -635,6 +669,7 @@ public class BatchRefUpdate {
                } else {
                        ru.setRefLogIdent(refLogIdent);
                        ru.setRefLogMessage(getRefLogMessage(cmd), isRefLogIncludingResult(cmd));
+                       ru.setForceRefLog(isForceRefLog(cmd));
                }
                ru.setPushCertificate(pushCert);
                switch (cmd.getType()) {
@@ -696,6 +731,21 @@ public class BatchRefUpdate {
                                ? cmd.isRefLogIncludingResult() : isRefLogIncludingResult();
        }
 
+       /**
+        * Check whether the reflog for a command should be written regardless of repo
+        * defaults.
+        *
+        * @param cmd
+        *            specific command.
+        * @return whether force writing is enabled.
+        * @since 4.9
+        */
+       protected boolean isForceRefLog(ReceiveCommand cmd) {
+               Boolean isForceRefLog = cmd.isForceRefLog();
+               return isForceRefLog != null ? isForceRefLog.booleanValue()
+                               : isForceRefLog();
+       }
+
        @Override
        public String toString() {
                StringBuilder r = new StringBuilder();
index 07786450a2f8244328451bc562ce0dfd318c973f..766b21da0e1a42cd787a41fbdfbfd5dec7fb2983 100644 (file)
@@ -185,6 +185,12 @@ public abstract class RefUpdate {
        /** Should the Result value be appended to {@link #refLogMessage}. */
        private boolean refLogIncludeResult;
 
+       /**
+        * Should reflogs be written even if the configured default for this ref is
+        * not to write it.
+        */
+       private boolean forceRefLog;
+
        /** Old value of the ref, obtained after we lock it. */
        private ObjectId oldValue;
 
@@ -403,6 +409,12 @@ public abstract class RefUpdate {
 
        /**
         * Set the message to include in the reflog.
+        * <p>
+        * Repository implementations may limit which reflogs are written by default,
+        * based on the project configuration. If a repo is not configured to write
+        * logs for this ref by default, setting the message alone may have no effect.
+        * To indicate that the repo should write logs for this update in spite of
+        * configured defaults, use {@link #setForceRefLog(boolean)}.
         *
         * @param msg
         *            the message to describe this change. It may be null if
@@ -430,6 +442,26 @@ public abstract class RefUpdate {
                refLogIncludeResult = false;
        }
 
+       /**
+        * Force writing a reflog for the updated ref.
+        *
+        * @param force whether to force.
+        * @since 4.9
+        */
+       public void setForceRefLog(boolean force) {
+               forceRefLog = force;
+       }
+
+       /**
+        * Check whether the reflog should be written regardless of repo defaults.
+        *
+        * @return whether force writing is enabled.
+        * @since 4.9
+        */
+       protected boolean isForceRefLog() {
+               return forceRefLog;
+       }
+
        /**
         * The old value of the ref, prior to the update being attempted.
         * <p>
index 14b35c9bfadd4e389fcae40a35688b6cb8c7c0ff..e9681b34c79113b0f1f369f07b2781cf521c5090 100644 (file)
@@ -225,6 +225,8 @@ public class ReceiveCommand {
 
        private boolean refLogIncludeResult;
 
+       private Boolean forceRefLog;
+
        private boolean typeIsCorrect;
 
        /**
@@ -390,8 +392,22 @@ public class ReceiveCommand {
        }
 
        /**
-        * Check whether this command has a custom reflog setting that should override
-        * defaults in any containing {@link org.eclipse.jgit.lib.BatchRefUpdate}.
+        * Force writing a reflog for the updated ref.
+        *
+        * @param force whether to force.
+        * @since 4.9
+        */
+       public void setForceRefLog(boolean force) {
+               forceRefLog = Boolean.valueOf(force);
+       }
+
+       /**
+        * Check whether this command has a custom reflog message setting that should
+        * override defaults in any containing
+        * {@link org.eclipse.jgit.lib.BatchRefUpdate}.
+        * <p>
+        * Does not take into account whether {@code #setForceRefLog(boolean)} has
+        * been called.
         *
         * @return whether a custom reflog is set.
         * @since 4.9
@@ -433,6 +449,18 @@ public class ReceiveCommand {
                return refLogIncludeResult;
        }
 
+       /**
+        * Check whether the reflog should be written regardless of repo defaults.
+        *
+        * @return whether force writing is enabled; null if {@code
+        * #setForceRefLog(boolean)} was never called.
+        * @since 4.9
+        */
+       @Nullable
+       public Boolean isForceRefLog() {
+               return forceRefLog;
+       }
+
        /**
         * Set the status of this command.
         *