@jonit-dev/night-watch-cli 1.7.98 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,6 +38,7 @@ fi
38
38
  # Retry configuration
39
39
  REVIEWER_MAX_RETRIES="${NW_REVIEWER_MAX_RETRIES:-2}"
40
40
  REVIEWER_RETRY_DELAY="${NW_REVIEWER_RETRY_DELAY:-30}"
41
+ REVIEWER_MAX_PRS_PER_RUN="${NW_REVIEWER_MAX_PRS_PER_RUN:-0}"
41
42
  SCRIPT_START_TIME=$(date +%s)
42
43
 
43
44
  # Normalize retry settings to safe numeric ranges
@@ -47,12 +48,18 @@ fi
47
48
  if ! [[ "${REVIEWER_RETRY_DELAY}" =~ ^[0-9]+$ ]]; then
48
49
  REVIEWER_RETRY_DELAY="30"
49
50
  fi
51
+ if ! [[ "${REVIEWER_MAX_PRS_PER_RUN}" =~ ^[0-9]+$ ]]; then
52
+ REVIEWER_MAX_PRS_PER_RUN="0"
53
+ fi
50
54
  if [ "${REVIEWER_MAX_RETRIES}" -gt 10 ]; then
51
55
  REVIEWER_MAX_RETRIES="10"
52
56
  fi
53
57
  if [ "${REVIEWER_RETRY_DELAY}" -gt 300 ]; then
54
58
  REVIEWER_RETRY_DELAY="300"
55
59
  fi
60
+ if [ "${REVIEWER_MAX_PRS_PER_RUN}" -gt 100 ]; then
61
+ REVIEWER_MAX_PRS_PER_RUN="100"
62
+ fi
56
63
 
57
64
  mkdir -p "${LOG_DIR}"
58
65
 
@@ -399,7 +406,7 @@ get_pr_score() {
399
406
  if [ -n "${REPO:-}" ]; then
400
407
  gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
401
408
  fi
402
- } | sort -u
409
+ } | awk '!seen[$0]++'
403
410
  )
404
411
  extract_review_score_from_text "${all_comments}"
405
412
  }
@@ -607,7 +614,7 @@ NEEDS_WORK=0
607
614
  REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null || echo "")
608
615
  PRS_NEEDING_WORK=""
609
616
 
610
- while IFS=$'\t' read -r pr_number pr_branch; do
617
+ while IFS=$'\t' read -r pr_number pr_branch pr_labels; do
611
618
  if [ -z "${pr_number}" ] || [ -z "${pr_branch}" ]; then
612
619
  continue
613
620
  fi
@@ -620,6 +627,11 @@ while IFS=$'\t' read -r pr_number pr_branch; do
620
627
  continue
621
628
  fi
622
629
 
630
+ if printf '%s\n' "${pr_labels:-}" | tr ',' '\n' | grep -Fxq 'needs-human-review'; then
631
+ log "INFO: PR #${pr_number} (${pr_branch}) is labeled needs-human-review; skipping automated review"
632
+ continue
633
+ fi
634
+
623
635
  # Merge-conflict signal: this PR needs action even if CI and score look fine.
624
636
  MERGE_STATE=$(gh pr view "${pr_number}" --json mergeStateStatus --jq '.mergeStateStatus' 2>/dev/null || echo "")
625
637
  if [ "${MERGE_STATE}" = "DIRTY" ] || [ "${MERGE_STATE}" = "CONFLICTING" ]; then
@@ -648,7 +660,7 @@ while IFS=$'\t' read -r pr_number pr_branch; do
648
660
  if [ -n "${REPO}" ]; then
649
661
  gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
650
662
  fi
651
- } | sort -u
663
+ } | awk '!seen[$0]++'
652
664
  )
653
665
  LATEST_SCORE=$(extract_review_score_from_text "${ALL_COMMENTS}")
654
666
  if [ -n "${LATEST_SCORE}" ] && [ "${LATEST_SCORE}" -lt "${MIN_REVIEW_SCORE}" ]; then
@@ -656,7 +668,10 @@ while IFS=$'\t' read -r pr_number pr_branch; do
656
668
  NEEDS_WORK=1
657
669
  PRS_NEEDING_WORK="${PRS_NEEDING_WORK} #${pr_number}"
658
670
  fi
659
- done < <(gh pr list --state open --json number,headRefName --jq '.[] | [.number, .headRefName] | @tsv' 2>/dev/null || true)
671
+ done < <(
672
+ gh pr list --state open --json number,headRefName,labels \
673
+ --jq '.[] | [.number, .headRefName, ((.labels // []) | map(.name) | join(","))] | @tsv' 2>/dev/null || true
674
+ )
660
675
 
661
676
  if [ "${NEEDS_WORK}" -eq 0 ]; then
662
677
  log "SKIP: All ${OPEN_PRS} open PR(s) have passing CI and review score >= ${MIN_REVIEW_SCORE} (or no score yet)"
@@ -686,7 +701,7 @@ if [ "${NEEDS_WORK}" -eq 0 ]; then
686
701
  if [ -n "${REPO}" ]; then
687
702
  gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
688
703
  fi
689
- } | sort -u
704
+ } | awk '!seen[$0]++'
690
705
  )
691
706
  PR_SCORE=$(extract_review_score_from_text "${PR_COMMENTS}")
692
707
 
@@ -747,6 +762,16 @@ for pr_token in ${PRS_NEEDING_WORK}; do
747
762
  PR_NUMBER_ARRAY+=("${pr_token#\#}")
748
763
  done
749
764
 
765
+ if [ "${REVIEWER_MAX_PRS_PER_RUN}" -gt 0 ] && [ "${#PR_NUMBER_ARRAY[@]}" -gt "${REVIEWER_MAX_PRS_PER_RUN}" ]; then
766
+ log "LIMIT: Restricting reviewer run to first ${REVIEWER_MAX_PRS_PER_RUN} PR(s) out of ${#PR_NUMBER_ARRAY[@]} needing work"
767
+ PR_NUMBER_ARRAY=("${PR_NUMBER_ARRAY[@]:0:${REVIEWER_MAX_PRS_PER_RUN}}")
768
+ PRS_NEEDING_WORK=""
769
+ for pr_number in "${PR_NUMBER_ARRAY[@]}"; do
770
+ PRS_NEEDING_WORK="${PRS_NEEDING_WORK}${PRS_NEEDING_WORK:+ }#${pr_number}"
771
+ done
772
+ PRS_NEEDING_WORK_CSV="${PRS_NEEDING_WORK// /,}"
773
+ fi
774
+
750
775
  if [ -z "${TARGET_PR}" ] && [ "${WORKER_MODE}" != "1" ] && [ "${PARALLEL_ENABLED}" = "1" ] && [ "${#PR_NUMBER_ARRAY[@]}" -gt 1 ]; then
751
776
  # Dry-run mode: print diagnostics and exit
752
777
  if [ "${NW_DRY_RUN:-0}" = "1" ]; then
@@ -758,6 +783,7 @@ if [ -z "${TARGET_PR}" ] && [ "${WORKER_MODE}" != "1" ] && [ "${PARALLEL_ENABLED
758
783
  if [ "${AUTO_MERGE}" = "1" ]; then
759
784
  echo "Auto-merge Method: ${AUTO_MERGE_METHOD}"
760
785
  fi
786
+ echo "Max PRs Per Run: ${REVIEWER_MAX_PRS_PER_RUN}"
761
787
  echo "Open PRs needing work:${PRS_NEEDING_WORK}"
762
788
  echo "Default Branch: ${DEFAULT_BRANCH}"
763
789
  echo "Parallel Workers: ${#PR_NUMBER_ARRAY[@]}"
@@ -892,6 +918,7 @@ if [ "${NW_DRY_RUN:-0}" = "1" ]; then
892
918
  fi
893
919
  echo "Max Retries: ${REVIEWER_MAX_RETRIES}"
894
920
  echo "Retry Delay: ${REVIEWER_RETRY_DELAY}s"
921
+ echo "Max PRs Per Run: ${REVIEWER_MAX_PRS_PER_RUN}"
895
922
  echo "Open PRs needing work:${PRS_NEEDING_WORK}"
896
923
  echo "Default Branch: ${DEFAULT_BRANCH}"
897
924
  echo "Review Worktree: ${REVIEW_WORKTREE_DIR}"
@@ -1204,7 +1231,7 @@ if [ "${AUTO_MERGE}" = "1" ] && [ ${EXIT_CODE} -eq 0 ]; then
1204
1231
  if [ -n "${REPO}" ]; then
1205
1232
  gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
1206
1233
  fi
1207
- } | sort -u
1234
+ } | awk '!seen[$0]++'
1208
1235
  )
1209
1236
  LATEST_SCORE=$(extract_review_score_from_text "${ALL_COMMENTS}")
1210
1237
 
@@ -446,7 +446,7 @@ while IFS=$'\t' read -r pr_number pr_branch pr_title pr_labels; do
446
446
  if [ -n "${REPO}" ]; then
447
447
  gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
448
448
  fi
449
- } | sort -u
449
+ } | awk '!seen[$0]++'
450
450
  )
451
451
  if echo "${ALL_COMMENTS}" | grep -q '<!-- night-watch-qa-marker -->'; then
452
452
  log "SKIP-QA: PR #${pr_number} (${pr_branch}) already has QA comment"
@@ -153,8 +153,9 @@ Parse the review score from the comment body. Look for patterns like:
153
153
  - Re-run local equivalents of the failing jobs before pushing to confirm the CI issues are fixed.
154
154
 
155
155
  e. **Run verification**: Run the project's test/lint commands (e.g., `npm test`, `npm run lint`, `npm run verify` or equivalent). Fix until it passes.
156
+ - **Do NOT paste verification command output anywhere** — not in the PR comment, not in the commit message. Only note pass/fail.
156
157
 
157
- f. **Commit and push** the fixes (only if there are staged changes beyond the rebase):
158
+ f. **Commit and push** the fixes (required whenever any code changes were made):
158
159
 
159
160
  ```
160
161
  git add <files>
@@ -197,11 +198,13 @@ Parse the review score from the comment body. Look for patterns like:
197
198
  <If CI was fixed>### CI Failures Fixed:
198
199
  - <job>: <what was wrong and how it was fixed><end>
199
200
 
200
- \`npm run verify\` passes locally. Ready for re-review.
201
+ Verification: passes locally. Ready for re-review.
201
202
 
202
203
  Night Watch PR Reviewer"
203
204
  ```
204
205
 
206
+ **Important**: Do NOT paste any command output (verify, lint, test logs) into the PR comment. Keep comments concise — bullet points only, no terminal output.
207
+
205
208
  h. **Do not manage worktrees directly**:
206
209
  - Do **not** run `git worktree add`, `git worktree remove`, or `git worktree prune`.
207
210
  - The cron wrapper handles worktree lifecycle.