Repository: incubator-zeppelin Updated Branches: refs/heads/master fe4d62518 -> 7a58d4610
Zeppelin-540: Notebook versioning control, commit from frontend notebook menu ### What is this PR for? This PR improves the front-end experience to use git versioning on notebooks. Any community feedback is welcome. ### What type of PR is it? Improvement ### Todos * [x] - front-end and back-end changes * [x] - add `checkpoint` interface * [x] - ~~error propagation to front-end~~ in a separate PR * [x] - tests * [x] - UI feedback? ### Is there a relevant Jira issue? [ZEPPELIN-540](https://issues.apache.org/jira/browse/ZEPPELIN-540) ### How should this be tested? 1. Uncomment `GitNotebookRepo` as a storage in `/conf/zeppelin-site.xml` 2. Start Zeppelin 3. Make changes to some notebook 4. Use `git` menu to commit 5. To check whether successfully committed, do `git log` in `/notebooks` folder ### Screenshots (if appropriate)  ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Khalid Huseynov <[email protected]> Closes #577 from khalidhuseynov/feat/git-commit-frontend-access and squashes the following commits: 4f04af0 [Khalid Huseynov] remove initial commit at start 64111e0 [Khalid Huseynov] Merge branch 'master' into feat/commit-frontend-access 5f10b46 [Khalid Huseynov] backend gitCommit -> commit ef3a8fb [Khalid Huseynov] Merge branch 'master' into feat/commit-frontend-access 8b5766f [Khalid Huseynov] change icon git -> file-code-o 74db747 [Khalid Huseynov] remove git from wording a03a953 [Khalid Huseynov] add repoSync checkpoint test for 1 storage 33f6e0f [Khalid Huseynov] add gitNotebookRepo checkpoint test b0fa219 [Khalid Huseynov] only commit message 339c9fe [Khalid Huseynov] Merge 'master' into feat/git-commit-frontend-access 39c2873 [Khalid Huseynov] use sinqle quotes b8fc035 [Khalid Huseynov] empty input field after commit message is hit c9192cb [Khalid Huseynov] temp fix for padding issue b69f2ff [Khalid Huseynov] change div to button 39c8e00 [Khalid Huseynov] fix formatting for checkstyle 32e403c [Khalid Huseynov] propagate changes to frontend bdeb0ed [Khalid Huseynov] add checkpoint interface and propagate to backend de7bdd6 [Khalid Huseynov] add checkpoint interface a1894c2 [Khalid Huseynov] backend handling of git notebook commit 8069ccd [Khalid Huseynov] add frontend handler via websocket 2ebe628 [Khalid Huseynov] add button and git menu Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/7a58d461 Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/7a58d461 Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/7a58d461 Branch: refs/heads/master Commit: 7a58d46103d8db4b81d4b2e2a18e9524a57cbd28 Parents: fe4d625 Author: Khalid Huseynov <[email protected]> Authored: Tue Feb 9 02:38:46 2016 +0900 Committer: Lee moon soo <[email protected]> Committed: Sat Feb 13 14:01:16 2016 +0900 ---------------------------------------------------------------------- .../org/apache/zeppelin/socket/Message.java | 9 +++- .../apache/zeppelin/socket/NotebookServer.java | 10 ++++ .../src/app/notebook/notebook-actionBar.html | 26 +++++++++++ .../src/app/notebook/notebook.controller.js | 15 ++++++ .../websocketEvents/websocketMsg.service.js | 10 ++++ .../org/apache/zeppelin/notebook/Notebook.java | 4 ++ .../zeppelin/notebook/repo/GitNotebookRepo.java | 21 ++++++--- .../zeppelin/notebook/repo/NotebookRepo.java | 5 ++ .../notebook/repo/NotebookRepoSync.java | 26 ++++++++++- .../zeppelin/notebook/repo/S3NotebookRepo.java | 6 +++ .../zeppelin/notebook/repo/VFSNotebookRepo.java | 6 +++ .../notebook/repo/GitNotebookRepoTest.java | 48 +++++++++++++++++++- .../notebook/repo/NotebookRepoSyncTest.java | 43 +++++++++++++++++- 13 files changed, 217 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java index 2a8e06d..54d9ab2 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/Message.java @@ -99,12 +99,17 @@ public class Message { ANGULAR_OBJECT_UPDATE, // [s-c] add/update angular object ANGULAR_OBJECT_REMOVE, // [s-c] add angular object del - + ANGULAR_OBJECT_UPDATED, // [c-s] angular object value updated, LIST_CONFIGURATIONS, // [c-s] ask all key/value pairs of configurations - CONFIGURATIONS_INFO // [s-c] all key/value pairs of configurations + CONFIGURATIONS_INFO, // [s-c] all key/value pairs of configurations // @param settings serialized Map<String, String> object + + CHECKPOINT_NOTEBOOK // [c-s] checkpoint notebook to storage repository + // @param noteId + // @param checkpointName + } public OP op; http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 9a4a378..5ae4ad7 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -171,6 +171,9 @@ public class NotebookServer extends WebSocketServlet implements case LIST_CONFIGURATIONS: sendAllConfigurations(conn, notebook); break; + case CHECKPOINT_NOTEBOOK: + checkpointNotebook(conn, notebook, messagereceived); + break; default: broadcastNoteList(); break; @@ -736,6 +739,13 @@ public class NotebookServer extends WebSocketServlet implements .put("configurations", configurations))); } + private void checkpointNotebook(NotebookSocket conn, Notebook notebook, + Message fromMessage) throws IOException { + String noteId = (String) fromMessage.get("noteId"); + String commitMessage = (String) fromMessage.get("commitMessage"); + notebook.checkpointNote(noteId, commitMessage); + } + /** * This callback is for the paragraph that runs on ZeppelinServer * @param noteId http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-web/src/app/notebook/notebook-actionBar.html ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/notebook-actionBar.html b/zeppelin-web/src/app/notebook/notebook-actionBar.html index 0340e28..f69a087 100644 --- a/zeppelin-web/src/app/notebook/notebook-actionBar.html +++ b/zeppelin-web/src/app/notebook/notebook-actionBar.html @@ -61,6 +61,32 @@ limitations under the License. tooltip-placement="bottom" tooltip="Export the notebook"> <i class="fa fa-download"></i> </button> + <ul class="dropdown-menu" role="menu" style="width:250px"> + <li> + <div class="cron-preset-container"> + <div> + <input type="text" + dropdown-input + placeholder="commit message" + id="note.checkpoint.message" + ng-model="note.checkpoint.message"/> + <button type="button" + class="btn btn-default btn-xs" + ng-hide="viewOnly" + ng-click="checkpointNotebook(note.checkpoint.message)" + tooltip-placement="bottom" tooltip="Commit the notebook">Commit + </button> + </div> + </div> + </li> + </ul> + <button type="button" + class="btn btn-default btn-xs dropdown-toggle" + ng-hide="viewOnly" + data-toggle="dropdown" + tooltip-placement="bottom" tooltip="Version control"> + <i class="fa fa-file-code-o"></i> + </button> </span> <!-- put the delete action by itself for your protection --> http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-web/src/app/notebook/notebook.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index 5919e4e..859ea33 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -154,6 +154,21 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', }); }; + // checkpoint/commit notebook + $scope.checkpointNotebook = function(commitMessage) { + BootstrapDialog.confirm({ + closable: true, + title: '', + message: 'Commit notebook to current repository?', + callback: function(result) { + if (result) { + websocketMsgSrv.checkpointNotebook($routeParams.noteId, commitMessage); + } + } + }); + document.getElementById('note.checkpoint.message').value=''; + }; + $scope.runNote = function() { BootstrapDialog.confirm({ closable: true, http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js index df44010..245ab77 100644 --- a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js +++ b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js @@ -128,6 +128,16 @@ angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope, }); }, + checkpointNotebook: function(noteId, commitMessage) { + websocketEvents.sendNewEvent({ + op: 'CHECKPOINT_NOTEBOOK', + data: { + noteId: noteId, + commitMessage: commitMessage + } + }); + }, + isConnected: function(){ return websocketEvents.isConnected(); } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java index df80cd0..14d2fd8 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java @@ -307,6 +307,10 @@ public class Notebook { } } + public void checkpointNote(String noteId, String checkpointMessage) throws IOException { + notebookRepo.checkpoint(noteId, checkpointMessage); + } + @SuppressWarnings("rawtypes") private Note loadNoteFromRepo(String id) { Note note = null; http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java index fe49753..85a534e 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/GitNotebookRepo.java @@ -25,6 +25,7 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.notebook.Note; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.internal.storage.file.FileRepository; @@ -61,28 +62,33 @@ public class GitNotebookRepo extends VFSNotebookRepo implements NotebookRepoVers localRepo.create(); } git = new Git(localRepo); - maybeAddAndCommit("."); } @Override public synchronized void save(Note note) throws IOException { super.save(note); - maybeAddAndCommit(note.getId()); } - private void maybeAddAndCommit(String pattern) { + /* implemented as git add+commit + * @param pattern is the noteId + * @param commitMessage is a commit message (checkpoint name) + * (non-Javadoc) + * @see org.apache.zeppelin.notebook.repo.VFSNotebookRepo#checkpoint(String, String) + */ + @Override + public void checkpoint(String pattern, String commitMessage) { try { List<DiffEntry> gitDiff = git.diff().call(); if (!gitDiff.isEmpty()) { LOG.debug("Changes found for pattern '{}': {}", pattern, gitDiff); DirCache added = git.add().addFilepattern(pattern).call(); LOG.debug("{} changes are about to be commited", added.getEntryCount()); - git.commit().setMessage("Updated " + pattern).call(); + git.commit().setMessage(commitMessage).call(); } else { LOG.debug("No changes found {}", pattern); } } catch (GitAPIException e) { - LOG.error("Faild to add+comit {} to Git", pattern, e); + LOG.error("Failed to add+comit {} to Git", pattern, e); } } @@ -100,8 +106,11 @@ public class GitNotebookRepo extends VFSNotebookRepo implements NotebookRepoVers Iterable<RevCommit> logs = git.log().addPath(noteId).call(); for (RevCommit log: logs) { history.add(new Rev(log.getName(), log.getCommitTime())); - LOG.debug(" - ({},{})", log.getName(), log.getCommitTime()); + LOG.debug(" - ({},{},{})", log.getName(), log.getCommitTime(), log.getFullMessage()); } + } catch (NoHeadException e) { + //when no initial commit exists + LOG.warn("No Head found for {}, {}", noteId, e.getMessage()); } catch (GitAPIException e) { LOG.error("Failed to get logs for {}", noteId, e); } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java index f8e0b57..d135032 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepo.java @@ -36,4 +36,9 @@ public interface NotebookRepo { * Release any underlying resources */ public void close(); + + /** + * chekpoint (versioning) for notebooks (optional) + */ + public void checkpoint(String noteId, String checkPointName) throws IOException; } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java index 55cdac2..88399d0 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/NotebookRepoSync.java @@ -224,7 +224,8 @@ public class NotebookRepoSync implements NotebookRepo { NotebookRepo getRepo(int repoIndex) throws IOException { if (repoIndex < 0 || repoIndex >= getRepoCount()) { - throw new IOException("Storage repo index is out of range"); + throw new IOException("Requested storage index " + repoIndex + + " isn't initialized," + " repository count is " + getRepoCount()); } return repos.get(repoIndex); } @@ -351,4 +352,27 @@ public class NotebookRepoSync implements NotebookRepo { } } + //checkpoint to all available storages + @Override + public void checkpoint(String noteId, String checkPointName) throws IOException { + int repoCount = getRepoCount(); + int errorCount = 0; + String errorMessage = ""; + for (int i = 0; i < Math.min(repoCount, getMaxRepoNum()); i++) { + try { + getRepo(i).checkpoint(noteId, checkPointName); + } catch (IOException e) { + LOG.warn("Couldn't checkpoint in {} storage with index {} for note {}", + getRepo(i).getClass().toString(), i, noteId); + errorMessage += "Error on storage class " + getRepo(i).getClass().toString() + + " with index " + i + " : " + e.getMessage() + "\n"; + errorCount++; + } + } + // throw exception if failed to commit for all initialized repos + if (errorCount == Math.min(repoCount, getMaxRepoNum())) { + throw new IOException(errorMessage); + } + + } } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java index 870aa86..a78dcb6 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/S3NotebookRepo.java @@ -189,4 +189,10 @@ public class S3NotebookRepo implements NotebookRepo { public void close() { //no-op } + + @Override + public void checkpoint(String noteId, String checkPointName) throws IOException { + // no-op + LOG.info("Checkpoint feature isn't suported in {}", this.getClass().toString()); + } } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java index 67f9b64..5f3676a 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepo.java @@ -244,4 +244,10 @@ public class VFSNotebookRepo implements NotebookRepo { //no-op } + @Override + public void checkpoint(String noteId, String checkPointName) throws IOException { + // no-op + logger.info("Checkpoint feature isn't suported in {}", this.getClass().toString()); + } + } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java index b92c7a9..879b1ad 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/GitNotebookRepoTest.java @@ -22,12 +22,16 @@ import static com.google.common.truth.Truth.assertThat; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Map; import org.apache.commons.io.FileUtils; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; import org.apache.zeppelin.interpreter.mock.MockInterpreter1; import org.apache.zeppelin.interpreter.mock.MockInterpreter2; +import org.apache.zeppelin.notebook.Note; +import org.apache.zeppelin.notebook.NoteInfo; +import org.apache.zeppelin.notebook.Paragraph; import org.apache.zeppelin.notebook.repo.NotebookRepoVersioned.Rev; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; @@ -96,7 +100,8 @@ public class GitNotebookRepoTest { assertThat(notebookRepo.list()).isNotEmpty(); List<DiffEntry> diff = git.diff().call(); - assertThat(diff).isEmpty(); + // no commit, diff isn't empty + assertThat(diff).isNotEmpty(); } @Test @@ -109,7 +114,46 @@ public class GitNotebookRepoTest { List<Rev> testNotebookHistory = notebookRepo.history(TEST_NOTE_ID); //then - assertThat(testNotebookHistory).isNotEmpty(); + //no initial commit, empty history + assertThat(testNotebookHistory).isEmpty(); } + @Test + public void addCheckpoint() throws IOException { + // initial checks + notebookRepo = new GitNotebookRepo(conf); + assertThat(notebookRepo.list()).isNotEmpty(); + assertThat(containsNote(notebookRepo.list(), TEST_NOTE_ID)).isTrue(); + assertThat(notebookRepo.history(TEST_NOTE_ID)).isEmpty(); + + notebookRepo.checkpoint(TEST_NOTE_ID, "first commit"); + List<Rev> notebookHistoryBefore = notebookRepo.history(TEST_NOTE_ID); + assertThat(notebookRepo.history(TEST_NOTE_ID)).isNotEmpty(); + int initialCount = notebookHistoryBefore.size(); + + // add changes to note + Note note = notebookRepo.get(TEST_NOTE_ID); + Paragraph p = note.addParagraph(); + Map<String, Object> config = p.getConfig(); + config.put("enabled", true); + p.setConfig(config); + p.setText("%md checkpoint test text"); + + // save and checkpoint note + notebookRepo.save(note); + notebookRepo.checkpoint(TEST_NOTE_ID, "second commit"); + + // see if commit is added + List<Rev> notebookHistoryAfter = notebookRepo.history(TEST_NOTE_ID); + assertThat(notebookHistoryAfter.size()).isEqualTo(initialCount + 1); + } + + private boolean containsNote(List<NoteInfo> notes, String noteId) { + for (NoteInfo note: notes) { + if (note.getId().equals(noteId)) { + return true; + } + } + return false; + } } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/7a58d461/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java index 753fab2..b162c88 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/repo/NotebookRepoSyncTest.java @@ -17,6 +17,7 @@ package org.apache.zeppelin.notebook.repo; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; @@ -44,6 +45,7 @@ import org.apache.zeppelin.search.LuceneSearch; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.quartz.SchedulerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,6 +61,7 @@ public class NotebookRepoSyncTest implements JobListenerFactory { private NotebookRepoSync notebookRepoSync; private InterpreterFactory factory; private DependencyResolver depResolver; + private SearchService search; private static final Logger LOG = LoggerFactory.getLogger(NotebookRepoSyncTest.class); @Before @@ -90,7 +93,7 @@ public class NotebookRepoSyncTest implements JobListenerFactory { depResolver = new DependencyResolver(mainZepDir.getAbsolutePath() + "/local-repo"); factory = new InterpreterFactory(conf, new InterpreterOption(false), null, null, depResolver); - SearchService search = mock(SearchService.class); + search = mock(SearchService.class); notebookRepoSync = new NotebookRepoSync(conf); notebookSync = new Notebook(conf, notebookRepoSync, schedulerFactory, factory, this, search); } @@ -211,6 +214,44 @@ public class NotebookRepoSyncTest implements JobListenerFactory { assertEquals(1, notebookRepoSync.list(1).size()); } + @Test + public void testCheckpointOneStorage() throws IOException, SchedulerException { + System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_STORAGE.getVarName(), "org.apache.zeppelin.notebook.repo.GitNotebookRepo"); + ZeppelinConfiguration vConf = ZeppelinConfiguration.create(); + + NotebookRepoSync vRepoSync = new NotebookRepoSync(vConf); + Notebook vNotebookSync = new Notebook(vConf, vRepoSync, schedulerFactory, factory, this, search); + + // one git versioned storage initialized + assertThat(vRepoSync.getRepoCount()).isEqualTo(1); + assertThat(vRepoSync.getRepo(0)).isInstanceOf(GitNotebookRepo.class); + + GitNotebookRepo gitRepo = (GitNotebookRepo) vRepoSync.getRepo(0); + + // no notes + assertThat(vRepoSync.list().size()).isEqualTo(0); + // create note + Note note = vNotebookSync.createNote(); + assertThat(vRepoSync.list().size()).isEqualTo(1); + + String noteId = vRepoSync.list().get(0).getId(); + // first checkpoint + vRepoSync.checkpoint(noteId, "checkpoint message"); + int vCount = gitRepo.history(noteId).size(); + assertThat(vCount).isEqualTo(1); + + Paragraph p = note.addParagraph(); + Map<String, Object> config = p.getConfig(); + config.put("enabled", true); + p.setConfig(config); + p.setText("%md checkpoint test"); + + // save and checkpoint again + vRepoSync.save(note); + vRepoSync.checkpoint(noteId, "checkpoint message 2"); + assertThat(gitRepo.history(noteId).size()).isEqualTo(vCount + 1); + } + static void delete(File file){ if(file.isFile()) file.delete(); else if(file.isDirectory()){
