All files / src/action review-state.ts

100% Statements 12/12
100% Branches 8/8
100% Functions 2/2
100% Lines 11/11

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66                2x     12x                                                                       38x 18x 18x 4x       14x 2x     12x 11x       25x    
/**
 * GitHub Review State Management
 *
 * Tracks the bot's previous review state on a PR for dismissal logic.
 */
 
import type { ReviewState } from '../output/types.js';
 
const VALID_REVIEW_STATES: ReadonlySet<string> = new Set(['CHANGES_REQUESTED', 'APPROVED', 'COMMENTED']);
 
function isValidReviewState(state: string): state is ReviewState {
  return VALID_REVIEW_STATES.has(state);
}
 
// -----------------------------------------------------------------------------
// Bot Review History
// -----------------------------------------------------------------------------
 
/**
 * A GitHub review from the API (subset of fields we need).
 */
export interface GitHubReviewInfo {
  id: number;
  state: string;
  user?: { login: string } | null;
}
 
/**
 * The bot's most recent review info (state + review ID for dismissal).
 */
export interface BotReviewInfo {
  state: ReviewState;
  reviewId: number;
}
 
/**
 * Find the bot's most recent review state on a PR.
 *
 * Used to determine if we should dismiss a previous REQUEST_CHANGES
 * when all issues are now resolved.
 *
 * Returns null if:
 * - Bot has no reviews on this PR
 * - Bot's most recent review was DISMISSED (user explicitly cleared it)
 */
export function findBotReviewState(reviews: GitHubReviewInfo[], botLogin: string): BotReviewInfo | null {
  // GitHub API returns reviews in chronological order, search from end
  for (let i = reviews.length - 1; i >= 0; i--) {
    const review = reviews[i];
    if (!review?.user || review.user.login !== botLogin) {
      continue;
    }
 
    // User dismissed our review - don't look at older reviews
    if (review.state === 'DISMISSED') {
      return null;
    }
 
    if (isValidReviewState(review.state)) {
      return { state: review.state, reviewId: review.id };
    }
  }
 
  return null;
}