t27.aiEnglish

Затор ревью

Вы узнаете

В каком из десяти случаев застрявший пулл-реквест и почему побеждает правило, совпавшее раньше остальных.

Пулл-реквест может застрять сразу по нескольким причинам: отклонён, снова запушен и красный на шумовой проверке. review-jam.t27 даёт Королеве один ответ. jam_case проверяет 9 фактов в постоянном порядке, и побеждает правило, совпавшее раньше остальных, так что PR, который Королева не смогла измерить, никогда не считается свободным, а отклонённый и затем запушенный не принимается за шум. Случаев 10, от none до unmeasured.

Попробовать

Снимайте факты по одному со стартового состояния и называйте каждый случай; затем найдите PR, который ни в каком заторе.

Открыть интерактивный урок →

The review jam: which case a stuck pull request is in
The review jam: which case a stuck pull request is in ↗

Nine facts about a pull request that will not move. Toggle them: the earliest rule that matches wins, and the pull request lands on that rule.

specs/automation/review-jam.t27

// Review jam: which case a stuck pull request is in, and the Queen's action.
// Part of EPIC #5388. Contract: gHashTag/t27#9032 (re-filed from #5700).
// `tri jam` (gHashTag/999-multibots-telegraf) imports these numbers instead
// of hand-copying them.

module review_jam;

// Jam case constants (u8, value = position, starting at 0)
pub const JAM_NONE: u8 = 0;
pub const JAM_NO_REVIEWER: u8 = 1;
pub const JAM_STACKED_ON_OPEN: u8 = 2;
pub const JAM_REFUSED_NOT_FIXED: u8 = 3;
pub const JAM_REFUSED_THEN_PUSHED: u8 = 4;
pub const JAM_LABELED_NOT_MERGED: u8 = 5;
pub const JAM_CONFLICTING: u8 = 6;
pub const JAM_NOISE_RED: u8 = 7;
pub const JAM_DRAFT_OR_FRESH: u8 = 8;
pub const JAM_UNMEASURED: u8 = 9;

// Queen action constants (u8, value = position, starting at 0)
pub const ACT_NOTHING: u8 = 0;
pub const ACT_DISPATCH_REVIEWER: u8 = 1;
pub const ACT_WAIT_FOR_BASE: u8 = 2;
pub const ACT_DISPATCH_CODER: u8 = 3;
pub const ACT_DISPATCH_RE_REVIEW: u8 = 4;
pub const ACT_FINISH_MERGE: u8 = 5;
pub const ACT_REBASE_BY_CODER: u8 = 6;
pub const ACT_NAME_NOISE_AND_REVIEW: u8 = 7;
pub const ACT_WAIT: u8 = 8;
pub const ACT_MEASURE_AGAIN: u8 = 9;

// The jam case of a pull request. The FIRST matching rule wins:
//  1. not measured                      -> UNMEASURED
//  2. draft or fresh                    -> DRAFT_OR_FRESH
//  3. stacked on an open PR             -> STACKED_ON_OPEN
//  4. conflicting                       -> CONFLICTING
//  5. labeled reviewed (and still open) -> LABELED_NOT_MERGED
//  6. refused and pushed after          -> REFUSED_THEN_PUSHED
//  7. refused                           -> REFUSED_NOT_FIXED
//  8. only noise checks red             -> NOISE_RED
//  9. no reviewer                       -> NO_REVIEWER
// 10. otherwise                         -> NONE
pub fn jam_case(measured: bool, draft_or_fresh: bool, stacked_on_open: bool, conflicting: bool, labeled_reviewed: bool, refused: bool, pushed_after_refusal: bool, has_reviewer: bool, only_noise_red: bool) -> u8 {
    if !measured {
        return JAM_UNMEASURED;
    }
    if draft_or_fresh {
        return JAM_DRAFT_OR_FRESH;
    }
    if stacked_on_open {
        return JAM_STACKED_ON_OPEN;
    }
    if conflicting {
        return JAM_CONFLICTING;
    }
    if labeled_reviewed {
        return JAM_LABELED_NOT_MERGED;
    }
    if refused && pushed_after_refusal {
        return JAM_REFUSED_THEN_PUSHED;
    }
    if refused {
        return JAM_REFUSED_NOT_FIXED;
    }
    if only_noise_red {
        return JAM_NOISE_RED;
    }
    if !has_reviewer {
        return JAM_NO_REVIEWER;
    }
    JAM_NONE
}

// The Queen's action for a case: the action with the SAME position.
// Any value above 9 is an unknown case, and an unknown case is never
// "nothing to do": it maps to ACT_MEASURE_AGAIN.
pub fn jam_action(case: u8) -> u8 {
    if case > 9 {
        return ACT_MEASURE_AGAIN;
    }
    case
}

// Whether the case is the Queen's turn to act: true for every case except
// NONE, DRAFT_OR_FRESH and STACKED_ON_OPEN.
pub fn jam_is_queens_turn(case: u8) -> bool {
    case != JAM_NONE && case != JAM_DRAFT_OR_FRESH && case != JAM_STACKED_ON_OPEN
}

// ---- jam_case: one test per case ----

test "unmeasured beats every other flag" {
    assert jam_case(false, true, true, true, true, true, true, true, true) == JAM_UNMEASURED;
}

test "unmeasured with every other flag clear" {
    assert jam_case(false, false, false, false, false, false, false, false, false) == JAM_UNMEASURED;
}

test "draft or fresh" {
    assert jam_case(true, true, false, false, false, false, false, false, false) == JAM_DRAFT_OR_FRESH;
}

test "stacked on open PR" {
    assert jam_case(true, false, true, false, false, false, false, true, false) == JAM_STACKED_ON_OPEN;
}

test "conflicting" {
    assert jam_case(true, false, false, true, false, false, false, true, false) == JAM_CONFLICTING;
}

test "labeled not merged" {
    assert jam_case(true, false, false, false, true, false, false, true, false) == JAM_LABELED_NOT_MERGED;
}

test "refused then pushed" {
    assert jam_case(true, false, false, false, false, true, true, true, false) == JAM_REFUSED_THEN_PUSHED;
}

test "refused not fixed" {
    assert jam_case(true, false, false, false, false, true, false, true, false) == JAM_REFUSED_NOT_FIXED;
}

test "noise red" {
    assert jam_case(true, false, false, false, false, false, false, true, true) == JAM_NOISE_RED;
}

test "no reviewer" {
    assert jam_case(true, false, false, false, false, false, false, false, false) == JAM_NO_REVIEWER;
}

test "none" {
    assert jam_case(true, false, false, false, false, false, false, true, false) == JAM_NONE;
}

// ---- jam_case: first-match order, each rule against the next one ----

test "draft beats stacked" {
    assert jam_case(true, true, true, false, false, false, false, true, false) == JAM_DRAFT_OR_FRESH;
}

test "stacked and unreviewed is stacked, not no reviewer" {
    assert jam_case(true, false, true, false, false, false, false, false, false) == JAM_STACKED_ON_OPEN;
}

test "stacked beats conflicting" {
    assert jam_case(true, false, true, true, false, false, false, true, false) == JAM_STACKED_ON_OPEN;
}

test "conflicting beats labeled" {
    assert jam_case(true, false, false, true, true, false, false, true, false) == JAM_CONFLICTING;
}

test "labeled beats refused then pushed" {
    assert jam_case(true, false, false, false, true, true, true, true, false) == JAM_LABELED_NOT_MERGED;
}

test "refused then pushed beats noise red" {
    assert jam_case(true, false, false, false, false, true, true, true, true) == JAM_REFUSED_THEN_PUSHED;
}

test "refused not fixed beats noise red" {
    assert jam_case(true, false, false, false, false, true, false, true, true) == JAM_REFUSED_NOT_FIXED;
}

test "noise red beats no reviewer" {
    assert jam_case(true, false, false, false, false, false, false, false, true) == JAM_NOISE_RED;
}

test "pushed without a refusal is not refused then pushed" {
    assert jam_case(true, false, false, false, false, false, true, true, false) == JAM_NONE;
}

// ---- jam_action: same position, unknown -> measure again ----

test "action none to nothing" {
    assert jam_action(JAM_NONE) == ACT_NOTHING;
}

test "action no reviewer to dispatch reviewer" {
    assert jam_action(JAM_NO_REVIEWER) == ACT_DISPATCH_REVIEWER;
}

test "action stacked to wait for base" {
    assert jam_action(JAM_STACKED_ON_OPEN) == ACT_WAIT_FOR_BASE;
}

test "action refused not fixed to dispatch coder" {
    assert jam_action(JAM_REFUSED_NOT_FIXED) == ACT_DISPATCH_CODER;
}

test "action refused then pushed to dispatch re-review" {
    assert jam_action(JAM_REFUSED_THEN_PUSHED) == ACT_DISPATCH_RE_REVIEW;
}

test "action labeled not merged to finish merge" {
    assert jam_action(JAM_LABELED_NOT_MERGED) == ACT_FINISH_MERGE;
}

test "action conflicting to rebase by coder" {
    assert jam_action(JAM_CONFLICTING) == ACT_REBASE_BY_CODER;
}

test "action noise red to name noise and review" {
    assert jam_action(JAM_NOISE_RED) == ACT_NAME_NOISE_AND_REVIEW;
}

test "action draft or fresh to wait" {
    assert jam_action(JAM_DRAFT_OR_FRESH) == ACT_WAIT;
}

test "action unmeasured to measure again" {
    assert jam_action(JAM_UNMEASURED) == ACT_MEASURE_AGAIN;
}

test "action first unknown case measures again" {
    assert jam_action(10) == ACT_MEASURE_AGAIN;
}

test "action unknown case 200 measures again" {
    assert jam_action(200) == ACT_MEASURE_AGAIN;
}

// ---- jam_is_queens_turn ----

test "queens turn for no reviewer" {
    assert jam_is_queens_turn(JAM_NO_REVIEWER) == true;
}

test "queens turn for refused not fixed" {
    assert jam_is_queens_turn(JAM_REFUSED_NOT_FIXED) == true;
}

test "queens turn for refused then pushed" {
    assert jam_is_queens_turn(JAM_REFUSED_THEN_PUSHED) == true;
}

test "queens turn for labeled not merged" {
    assert jam_is_queens_turn(JAM_LABELED_NOT_MERGED) == true;
}

test "queens turn for conflicting" {
    assert jam_is_queens_turn(JAM_CONFLICTING) == true;
}

test "queens turn for noise red" {
    assert jam_is_queens_turn(JAM_NOISE_RED) == true;
}

test "queens turn for unmeasured" {
    assert jam_is_queens_turn(JAM_UNMEASURED) == true;
}

test "not queens turn for none" {
    assert jam_is_queens_turn(JAM_NONE) == false;
}

test "not queens turn for draft or fresh" {
    assert jam_is_queens_turn(JAM_DRAFT_OR_FRESH) == false;
}

test "not queens turn for stacked on open" {
    assert jam_is_queens_turn(JAM_STACKED_ON_OPEN) == false;
}

// ---- the two scenarios of #9032, end to end ----

test "scenario bee-reviewed but still open finishes the merge" {
    assert jam_action(jam_case(true, false, false, false, true, false, false, true, false)) == ACT_FINISH_MERGE;
}

test "scenario failed read is never reported as free" {
    assert jam_action(jam_case(false, false, false, false, false, false, false, true, false)) == ACT_MEASURE_AGAIN;
}

Открыть спеку урока в плеере ↗

Все уроки