2

In Node.js, using NodeGit. I'm using a function similar to this inside a POST Express.js route. This route should get the commits between endCommit and startCommit:

router.post('/getLog', function(req, res, next) {
    var logData = [];

    Git.Repository.open(path.join(repositories.mine.path))
        .then(function(repo) {
            return {
                    endCommit: [ First commit object ], //Just a random commit object that has a "sha" inside
                    startCommit: [ Second commit object ]  //Just a random commit object that has a "sha" inside
                };
        })
        .then(function(range) {
            // History returns an event.

            var history = range.endCommit.history(Git.Revwalk.SORT.Time);

            // History emits "commit" event for each commit in the branch's history
            history.on("commit", function(commit) {
                logData.push({
                    commit: commit.sha(),
                    message: commit.message()
                });

                if (commit.sha() == range.startCommit.sha()) {
                    console.log("---LOG CREATED---");
                    history.end();
                }
            })

            history.start();
        })
        .done(function() {
            console.log("---RETURNING---");

            return res.json({ logData: logData });
        });
});

However, since history.on("commit", ...) is not a Promise the .done() function is called first. In the log I see:

---RETURNING---
---LOG CREATED---

How can I return only after the log has been created?

I've came across issues like this in the past however in this particular case I don't know how could I promisify the history object because it is based on events.

adelriosantiago
  • 7,762
  • 7
  • 38
  • 71

1 Answers1

1

You can wrap event handling in a promise that should be resolved once you are done, and return it:

.then(function(range) {
  // History returns an event.

  var history = range.endCommit.history(Git.Revwalk.SORT.Time);

  var commitPromise = new Promise(function(resolve, reject) {
    // History emits "commit" event for each commit in the branch's history
    history.on("commit", function(commit) {
      logData.push({
        commit: commit.sha(),
        message: commit.message()
      });

      if (commit.sha() == range.startCommit.sha()) {
        console.log("---LOG CREATED---");
        resolve(); // resolve the promise
        history.end();
      }
    })
  });

  history.start();

  return commitPromise;
})

I assume you have Promise global. It's up to you choosing particular promise implementation - you may want to use bluebird for example.

adelriosantiago
  • 7,762
  • 7
  • 38
  • 71
Sergey Lapin
  • 2,633
  • 2
  • 18
  • 20
  • Thanks a lot! You pointed me to the right path. It works now but there is just a small change needed: The `resolve()` must appear before `history.end()` otherwise the line is never executed. I already changed the answer for your convenience. – adelriosantiago Feb 06 '17 at 07:21
  • 1
    @adelriosantiago the only reason I see for `resolve` not to be executed if placed after `history.end()`, is the latter throwing an error. Have a look at this to prevent possible issues. – Sergey Lapin Feb 06 '17 at 08:36
  • You are right, `history.end()` does not exist. I solved that by replacing it with a `throw Git.Error.CODE.ITEROVER` like here: https://github.com/nodegit/nodegit/blob/a7bde084cdc3537dd30522bb8fa1e6f2ff724898/lib/revwalk.js#L81. – adelriosantiago Feb 06 '17 at 20:26