public async Task <CommitStatus> Execute(GetCommitStatus query)
            {
                var cacheKey = CacheKey(query.ReviewId);

                var summary = await _queryRunner.Query(new GetReviewStatus(query.ReviewId));

                if (_cache.TryGetValue <CommitStatus>(cacheKey, out var cachedStatus) && cachedStatus.Commit == summary.CurrentHead)
                {
                    return(cachedStatus);
                }

                var fileMatrix = await _queryRunner.Query(new GetFileMatrix(query.ReviewId));

                var reviewFile = await GetReviewFiles(query, summary);

                var statusInput = new
                {
                    Matrix = fileMatrix,
                    UnresolvedDiscussions = summary.UnresolvedDiscussions,
                    ResolvedDiscussions   = summary.ResolvedDiscussions,
                    Discussions           = summary.Discussions
                };

                var commitStatus = new CommitStatus
                {
                    Commit    = summary.CurrentHead,
                    Name      = "Code review (CodeSaw)",
                    TargetUrl = $"{_siteBase}/project/{query.ReviewId.ProjectId}/review/{query.ReviewId.ReviewId}"
                };

                try
                {
                    var result = _node.ExecuteScriptFunction(reviewFile, "status", statusInput);

                    if (result is JObject obj && obj.Property("ok") != null && obj.Property("reasons") != null)
                    {
                        var isOk    = obj.Property("ok").Value.Value <bool>();
                        var reasons = obj.Property("reasons").Value.Values <string>();

                        commitStatus.State       = isOk ? CommitStatusState.Success : CommitStatusState.Pending;
                        commitStatus.Description = string.Join(", ", reasons);
                    }
                    else
                    {
                        commitStatus.State       = CommitStatusState.Failed;
                        commitStatus.Description = "Invalid review script output";
                    }
                }
            public async Task <Result> Execute(GetReviewEmoji query)
            {
                var summary = await _queryRunner.Query(new GetReviewStatus(query.ReviewId));

                var fileMatrix = await _queryRunner.Query(new GetFileMatrix(query.ReviewId));

                var reviewFile = await GetReviewFiles(query, summary);

                var statusInput = new
                {
                    Matrix = fileMatrix,
                    summary.UnresolvedDiscussions,
                    summary.ResolvedDiscussions,
                    summary.Discussions
                };

                try
                {
                    var result = _node.ExecuteScriptFunction(reviewFile, "thumb", statusInput, _currentUser.UserName);

                    var numericResult = result.Value <int?>();

                    if (numericResult == 1)
                    {
                        return(Result.AddAndRemove(EmojiType.ThumbsUp, EmojiType.ThumbsDown));
                    }

                    if (numericResult == -1)
                    {
                        return(Result.AddAndRemove(EmojiType.ThumbsDown, EmojiType.ThumbsUp));
                    }

                    return(Result.Remove(EmojiType.ThumbsUp, EmojiType.ThumbsDown));
                }
                catch (NodeException e)
                {
                    Log.Warn(e, "Thumb script failed");
                }

                return(new Result()
                {
                    ToAdd = new EmojiType[0],
                    ToRemove = new EmojiType[0]
                });
            }