From 675ace8e6b5e4eff3307a6e012f6098a1487b58d Mon Sep 17 00:00:00 2001 From: Michael Garber Date: Tue, 21 May 2024 15:07:58 -0400 Subject: [PATCH] Automate HIP Management with Number Assignment and Status Updates (#962) Signed-off-by: Michael Garber --- .github/workflows/add-hip-number.yml | 112 ++++++++++++ .../workflows/schedule-last-call-date-end.yml | 167 ++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 .github/workflows/add-hip-number.yml create mode 100644 .github/workflows/schedule-last-call-date-end.yml diff --git a/.github/workflows/add-hip-number.yml b/.github/workflows/add-hip-number.yml new file mode 100644 index 000000000..72ac09a80 --- /dev/null +++ b/.github/workflows/add-hip-number.yml @@ -0,0 +1,112 @@ +name: Assign HIP Number and Rename File + +on: + pull_request: + types: [opened, synchronize] + +defaults: + run: + shell: bash + +permissions: + contents: write + issues: read + pull-requests: write + checks: write + +jobs: + assign-hip-number: + runs-on: [self-hosted, Linux, medium, ephemeral] + steps: + - name: Harden Runner + uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1 + with: + egress-policy: audit + + - name: Check out the code + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + with: + fetch-depth: 0 + + - name: Identify if New HIP + id: check-new + run: | + # Fetch the main branch to have all necessary references + git fetch origin main + + # Get the modified files in the PR against the main branch + MODIFIED_FILES=$(git diff --name-only origin/main...$GITHUB_SHA) + echo "Modified files in PR: $MODIFIED_FILES" + + # Directory path to check for HIP files + HIP_DIRECTORY='HIP' + HIP_FILES=$(echo "$MODIFIED_FILES" | grep "^$HIP_DIRECTORY/.*\.md") + echo "Filtered HIP files: $HIP_FILES" + echo "::set-output name=hip-files::$HIP_FILES" + + # Check if any HIP files were modified + if [ -z "$HIP_FILES" ]; then + echo "No HIP files found in the PR." + echo "::set-output name=new-hip::false" + exit 0 + fi + + # Check each HIP file to see if it exists in the main branch + NEW_HIP=true + for file in $HIP_FILES; do + if git ls-tree -r origin/main --name-only | grep -q "^$file$"; then + echo "This PR modifies an existing HIP: $file" + NEW_HIP=false + break + fi + done + + if [ "$NEW_HIP" = "true" ]; then + echo "This PR creates a new HIP." + echo "::set-output name=new-hip::true" + else + echo "::set-output name=new-hip::false" + fi + + - name: Assign HIP Number + if: steps.check-new.outputs.new-hip == 'true' + run: | + # Extract the current PR number + PR_NUMBER=${{ github.event.pull_request.number }} + HIP_HEADER="hip: $PR_NUMBER" + HIP_FILE=$(echo "${{ steps.check-new.outputs.hip-files }}" | head -n 1) + + echo "Assigning HIP number to file: $HIP_FILE" + + if [ -n "$HIP_FILE" ]; then + sed -i "s/^hip:.*$/$HIP_HEADER/" "$HIP_FILE" + else + echo "No valid HIP file to assign a number." + exit 1 + fi + + - name: Rename HIP File + if: steps.check-new.outputs.new-hip == 'true' + run: | + # Extract PR number + PR_NUMBER=${{ github.event.pull_request.number }} + HIP_FILE=$(echo "${{ steps.check-new.outputs.hip-files }}" | head -n 1) + + if [ -n "$HIP_FILE" ]; then + NEW_HIP_FILE="HIP/hip-$PR_NUMBER.md" + mv "$HIP_FILE" "$NEW_HIP_FILE" + else + echo "No HIP file found to rename." + exit 1 + fi + + - name: Commit Changes + if: steps.check-new.outputs.new-hip == 'true' + run: | + git config --global user.name 'GitHub Action' + git config --global user.email 'action@github.com' + + PR_NUMBER=${{ github.event.pull_request.number }} + git add HIP/ + git commit -m "Assigning HIP $PR_NUMBER and renaming file to hip-$PR_NUMBER.md" + git push origin HEAD:${{ github.head_ref }} diff --git a/.github/workflows/schedule-last-call-date-end.yml b/.github/workflows/schedule-last-call-date-end.yml new file mode 100644 index 000000000..e04063b88 --- /dev/null +++ b/.github/workflows/schedule-last-call-date-end.yml @@ -0,0 +1,167 @@ +name: Schedule Status Update Based on Last Call Time + +permissions: + pull-requests: write + contents: write + packages: write + +defaults: + run: + shell: bash + +on: + pull_request: + types: [closed] + branches: + - main + +jobs: + check-merged-file: + if: github.event.pull_request.merged == true + runs-on: [self-hosted, Linux, medium, ephemeral] + + steps: + - name: Check out the code + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + + - name: Get modified files + id: get-modified-files + run: | + PR_NUMBER=${{ github.event.pull_request.number }} + FILES=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER/files" | jq -r '.[].filename') + + echo "Modified files:" + echo "$FILES" + + echo "modified_files<> $GITHUB_OUTPUT + echo "$FILES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Check if modified files are in the HIP directory and have a .md extension + if: steps.get-modified-files.outputs.modified_files != '' + id: check-hip-files + run: | + HIP_FILES="" + while IFS= read -r file; do + if [[ $file == HIP/*.md ]]; then + HIP_FILES="$HIP_FILES $file" + fi + done <<< "${{ steps.get-modified-files.outputs.modified_files }}" + + if [ -z "$HIP_FILES" ]; then + echo "No modified HIP files found." + else + echo "Modified HIP files: $HIP_FILES" + echo "hip_files=$HIP_FILES" >> $GITHUB_OUTPUT + fi + + - name: Check if modified files are in Last Call + if: steps.check-hip-files.outputs.hip_files != '' + id: check-last-call + run: | + last_call_files="" + for file in ${{ steps.check-hip-files.outputs.hip_files }}; do + if grep -qE '^status: Last Call' "$file"; then + last_call_files="$last_call_files $file" + fi + done + + if [[ -n "$last_call_files" ]]; then + echo "Files in Last Call: $last_call_files" + echo "last_call_files=$last_call_files" >> $GITHUB_OUTPUT + else + echo "No files in Last Call" + fi + + - name: Calculate Delay Until Last Call + if: steps.check-last-call.outputs.last_call_files != '' + id: calculate-delay + run: | + first_last_call_file=$(echo "${{ steps.check-last-call.outputs.last_call_files }}" | awk '{print $1}') + last_call_time=$(grep -oP '(?<=^last-call-date-time: ).*' "$first_last_call_file") + + echo "Last Call Date Time: $last_call_time" + + target_epoch=$(date -d "$last_call_time" +%s) + current_epoch=$(date +%s) + delay_seconds=$((target_epoch - current_epoch)) + + echo "Delay in seconds: $delay_seconds" + + if [[ $delay_seconds -gt 0 ]]; then + echo "Delaying PR creation and automerge for $delay_seconds seconds." + echo "delay_seconds=$delay_seconds" >> $GITHUB_OUTPUT + else + echo "The last-call date-time is in the past. Skipping delay." + exit 1 + fi + + - name: Delay Until Last Call + if: steps.calculate-delay.outputs.delay_seconds != '' + run: | + delay_seconds=${{ steps.calculate-delay.outputs.delay_seconds }} + echo "Sleeping for $delay_seconds seconds" + sleep "$delay_seconds" + + - name: Update HIP status and Add/Update `updated` Date + if: steps.check-last-call.outputs.last_call_files != '' + run: | + current_date=$(date +%Y-%m-%d) + for file in ${{ steps.check-last-call.outputs.last_call_files }}; do + hip_type=$(grep -oP '(?<=^type: ).*' "$file") + hip_category=$(grep -oP '(?<=^category: ).*' "$file") + + echo "Processing file: $file" + echo "Extracted type: $hip_type" + echo "Extracted category: $hip_category" + + new_status="" + if [[ "$hip_type" == "Standards Track" ]]; then + if [[ "$hip_category" == "Core" || "$hip_category" == "Service" || "$hip_category" == "Mirror" ]]; then + new_status="Council Review" + elif [[ "$hip_category" == "Application" ]]; then + new_status="Accepted" + fi + elif [[ "$hip_type" == "Informational" || "$hip_type" == "Process" ]]; then + new_status="Active" + fi + + if [[ -n "$new_status" ]]; then + # Update status + sed -i "s/^status: Last Call/status: $new_status/" "$file" + + # Update or add `updated` property before the final "---" + if grep -q '^updated: ' "$file"; then + sed -i "s/^updated:.*/updated: $current_date/" "$file" + else + sed -i "/^---$/i updated: $current_date" "$file" + fi + echo "Updated status of $file to $new_status and set updated date to $current_date" + else + echo "Unable to determine the new status for $file. Check the type and category fields." + fi + done + + - name: Create PR for status update + if: steps.check-last-call.outputs.last_call_files != '' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + id: create-pr + run: | + git config --global user.name 'GitHub Action' + git config --global user.email 'action@github.com' + git add . + git commit -m "Update HIP status and set updated date" + git push origin HEAD:status-update-${{ github.sha }} + PR_URL=$(gh pr create --title "Update HIP status" --body "Automatically updating the status of HIPs in Last Call and setting the updated date based on the type and category." --base main --head status-update-${{ github.sha }}) + echo "Pull request created at $PR_URL" + echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT + + - name: Auto-merge PR + if: steps.create-pr.outputs.pr_url != '' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(echo "${{ steps.create-pr.outputs.pr_url }}" | grep -oP '\d+$') + echo "Merging PR number: $PR_NUMBER" + gh pr merge $PR_NUMBER --merge --auto --body "Auto-merged via GitHub Actions"