Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ci): TODO GitHub issue checker #7642

Merged
merged 6 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,22 @@ jobs:
VITE_E2E_RPC_URL_L1: http://localhost:8545
VITE_E2E_RPC_URL_L2: http://localhost:9545

todo-issues:
machine:
image: ubuntu-2204:2022.07.1
steps:
- checkout
- run:
name: Install ripgrep
command: sudo apt-get install -y ripgrep
- run:
name: Check TODO issues
command: ./ops/scripts/todo-checker.sh --verbose
- slack/notify:
channel: C03N11M0BBN
event: fail
template: basic_fail_1

bedrock-markdown:
machine:
image: ubuntu-2204:2022.07.1
Expand Down Expand Up @@ -1502,6 +1518,15 @@ workflows:
requires:
- hold

scheduled-todo-issues:
when:
equal: [ build_four_hours, <<pipeline.schedule.name>> ]
jobs:
- todo-issues:
name: todo-issue-checks
context:
- slack

scheduled-fpp:
when:
equal: [ build_four_hours, <<pipeline.schedule.name>> ]
Expand Down
150 changes: 150 additions & 0 deletions ops/scripts/todo-checker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/bin/bash

clabby marked this conversation as resolved.
Show resolved Hide resolved
set -uo pipefail

# Flags
FAIL_INVALID_FMT=false
VERBOSE=false

# Github API access token (Optional - necessary for private repositories.)
GH_API_TOKEN="${CI_TODO_CHECKER_PAT:-""}"
AUTH=""
if [[ $GH_API_TOKEN != "" ]]; then
AUTH="Authorization: token $GH_API_TOKEN"
fi

# Default org and repo
ORG="ethereum-optimism"
REPO="optimism"

# Counter for issues that were not found and issues that are still open.
NOT_FOUND_COUNT=0
MISMATCH_COUNT=0
OPEN_COUNT=0
declare -a OPEN_ISSUES

# Colors
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
GREY='\033[1;30m'
CYAN='\033[0;36m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color

# Parse flags
#
# `--strict`: Toggle strict mode; Will fail if any TODOs are found that don't match the expected
# `--verbose`: Toggle verbose mode; Will print out details about each TODO
for arg in "$@"; do
case $arg in
--strict)
FAIL_INVALID_FMT=true
shift
;;
--verbose)
VERBOSE=true
shift
;;
esac
done

# Use ripgrep to search for the pattern in all files within the repo
todos=$(rg -o --with-filename -n -g '!ops/scripts/todo-checker.sh' 'TODO\(([^)]+)\): [^,;]*')

# Check each TODO comment in the repo
IFS=$'\n' # Set Internal Field Separator to newline for iteration
clabby marked this conversation as resolved.
Show resolved Hide resolved
for todo in $todos; do
# Extract the text inside the parenthesis
FILE=$(echo $todo | awk -F':' '{print $1}')
LINE_NUM=$(echo $todo | awk -F':' '{print $2}')
ISSUE_REFERENCE=$(echo $todo | sed -n 's/.*TODO(\([^)]*\)).*/\1/p')

# Parse the format of the TODO comment. There are 3 supported formats:
# * TODO(<issue_number>): <description> (Default org & repo: "ethereum-optimism/monorepo")
# * TODO(repo#<issue_number>): <description> (Default org "ethereum-optimism")
# * TODO(org/repo#<issue_number>): <description>
#
# Check if it's just a number
if [[ $ISSUE_REFERENCE =~ ^[0-9]+$ ]]; then
REPO_FULL="$ORG/$REPO"
ISSUE_NUM="$ISSUE_REFERENCE"
# Check for org_name/repo_name#number format
elif [[ $ISSUE_REFERENCE =~ ^([^/]+)/([^#]+)#([0-9]+)$ ]]; then
REPO_FULL="${BASH_REMATCH[1]}/${BASH_REMATCH[2]}"
ISSUE_NUM="${BASH_REMATCH[3]}"
# Check for repo_name#number format
elif [[ $ISSUE_REFERENCE =~ ^([^#]+)#([0-9]+)$ ]]; then
REPO_FULL="$ORG/${BASH_REMATCH[1]}"
ISSUE_NUM="${BASH_REMATCH[2]}"
else
if $FAIL_INVALID_FMT || $VERBOSE; then
echo -e "${YELLOW}[Warning]:${NC} Invalid TODO format: $todo"
if $FAIL_INVALID_FMT; then
exit 1
fi
fi
((MISMATCH_COUNT++))
continue
fi

# Use GitHub API to fetch issue details
GH_URL_PATH="$REPO_FULL/issues/$ISSUE_NUM"
RESPONSE=$(curl -sL -H "$AUTH" --request GET "https://api.github.com/repos/$GH_URL_PATH")

# Check if issue was found
if echo "$RESPONSE" | rg -q "Not Found"; then
if [[ $VERBOSE ]]; then
echo -e "${YELLOW}[Warning]:${NC} Issue not found: ${RED}$REPO_FULL/$ISSUE_NUM${NC}"
fi
((NOT_FOUND_COUNT++))
continue
fi

# Check issue state
STATE=$(echo "$RESPONSE" | jq -r .state)

if [[ "$STATE" == "closed" ]]; then
echo -e "${RED}[Error]:${NC} Issue #$ISSUE_NUM is closed. Please remove the TODO in ${GREEN}$FILE:$LINE_NUM${NC} referencing ${YELLOW}$ISSUE_REFERENCE${NC} (${CYAN}https://github.com/$GH_URL_PATH${NC})"
exit 1
fi

((OPEN_COUNT++))
TITLE=$(echo "$RESPONSE" | jq -r .title)
OPEN_ISSUES+=("$REPO_FULL/issues/$ISSUE_NUM|$TITLE|$FILE:$LINE_NUM")
done

# Print summary
if [[ $NOT_FOUND_COUNT -gt 0 ]]; then
echo -e "${YELLOW}[Warning]:${NC} ${CYAN}$NOT_FOUND_COUNT${NC} TODOs referred to issues that were not found."
fi
if [[ $MISMATCH_COUNT -gt 0 ]]; then
echo -e "${YELLOW}[Warning]:${NC} ${CYAN}$MISMATCH_COUNT${NC} TODOs did not match the expected pattern. Run with ${RED}\`--verbose\`${NC} to show details."
fi
if [[ $OPEN_COUNT -gt 0 ]]; then
echo -e "${GREEN}[Info]:${NC} ${CYAN}$OPEN_COUNT${NC} TODOs refer to issues that are still open."
echo -e "${GREEN}[Info]:${NC} Open issue details:"
printf "\n${PURPLE}%-50s${NC} ${GREY}|${NC} ${GREEN}%-55s${NC} ${GREY}|${NC} ${YELLOW}%-30s${NC}\n" "Repository & Issue" "Title" "Location"
echo -e "$GREY$(printf '%0.s-' {1..51})+$(printf '%0.s-' {1..57})+$(printf '%0.s-' {1..31})$NC"
for issue in "${OPEN_ISSUES[@]}"; do
REPO_ISSUE="https://github.com/${issue%%|*}" # up to the first |
REMAINING="${issue#*|}" # after the first |
TITLE="${REMAINING%%|*}" # up to the second |
LOC="${REMAINING#*|}" # after the second |

# Truncate if necessary
if [ ${#REPO_ISSUE} -gt 47 ]; then
REPO_ISSUE=$(printf "%.47s..." "$REPO_ISSUE")
fi
if [ ${#TITLE} -gt 47 ]; then
TITLE=$(printf "%.52s..." "$TITLE")
fi
if [ ${#LOC} -gt 27 ]; then
LOC=$(printf "%.24s..." "$LOC")
fi

printf "${CYAN}%-50s${NC} ${GREY}|${NC} %-55s ${GREY}|${NC} ${YELLOW}%-30s${NC}\n" "$REPO_ISSUE" "$TITLE" "$LOC"
done
fi

echo -e "${GREEN}[Info]:${NC} Done checking issues."
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"bindings": "nx bindings @eth-optimism/contracts-bedrock",
"build": "npx nx run-many --target=build",
"test": "npx nx run-many --target=test",
"issues": "./ops/scripts/todo-checker.sh",
"lint": "npx nx run-many --target=lint",
"test:coverage": "npx nx run-many --target=test:coverage",
"lint:ts:check": "npx nx run-many --target=lint:ts:check",
Expand Down