Browse Source

ci(stale): create `stale.yml` workflow (#7053)

* ci(stale): create `stale.yml` workflow

- Treat issues and PRs separately
- At the end, generate a cross-linked summary with all processed issues/PRs

* chore: apply suggested interval ratio 60/30

* chore: cron every 6 hours o'clock...

at 0:00am 6:00am 12:00pm 18:00pm

* chore: multiline string for messages posted by bot

* fix: concurrency and job atomicity

* format: remove the superfluous newlines

Co-authored-by: ImVector <59611597+LuigiImVector@users.noreply.github.com>

* security: limit access to contents

* feat: `blocked,must,should,keep` exempt labels

* fix: report not work since job outputs aren't exported from their respective jobs

* chore: cron every 1 hour o'clock

* fix: filter outputs to exempt share secrets between jobs

* chore: use emoji text instead its icon

* chore: cron back again every 6 hours o'clock...

Reverts commit dc44e45b274082fcb7fec956c4528ba347765234

* chore: refactor workflow to have only one job but one step for issues and other for PRs

New features:
- run on push over this workflow
- run manually have debug option to make a dry-run execution
- run scheduled is every 6 hours at o'clock
- Summary report is in table format instead of list items

* chore: cron back again once a day at 00:00 UTC

Co-authored-by: ImVector <59611597+LuigiImVector@users.noreply.github.com>
David Ordás 3 years ago
parent
commit
88454860d6
1 changed files with 201 additions and 0 deletions
  1. 201 0
      .github/workflows/stale.yml

+ 201 - 0
.github/workflows/stale.yml

@@ -0,0 +1,201 @@
+name: Stale handler
+
+on:
+  push:                               # when push this files to branches....
+    branches:
+      - 'main'
+      - 'gh-actions/test'
+    paths:
+      - '.github/workflows/stale.yml' #    - this workflow
+  workflow_dispatch:                  # manually
+    inputs:
+      debug-only:
+        type: boolean
+        description: 'If enabled, debug mode is on and then API calls that can alter your issues will not happen'
+        required: true
+        default: true
+  schedule:                           # or
+    - cron: "0 0 * * *"               # once a day at 00:00 o'clock
+
+permissions:
+  # no checkout/branching needed
+  contents: none
+
+# This allows a subsequently queued workflow run to interrupt/wait for previous runs
+concurrency:
+  group: '${{ github.workflow }}'
+  cancel-in-progress: false  # true: interrupt, false = wait for
+
+jobs:
+  stale:
+    name: Staler job
+    runs-on: ubuntu-latest
+    outputs:
+      # "XXX-len": the length of the "XXX" output object
+      staled-issues:     ${{ steps.set-staled.outputs.issues }}
+      staled-issues-len: ${{ steps.set-staled.outputs.issues-len }}
+      staled-prs:     ${{ steps.set-staled.outputs.prs }}
+      staled-prs-len: ${{ steps.set-staled.outputs.prs-len }}
+      closed-issues:     ${{ steps.set-closed.outputs.issues }}
+      closed-issues-len: ${{ steps.set-closed.outputs.issues-len }}
+      closed-prs:     ${{ steps.set-closed.outputs.prs }}
+      closed-prs-len: ${{ steps.set-closed.outputs.prs-len }}
+    # enable write access rights to allow bot comments and labeling
+    permissions:
+      issues: write
+      pull-requests: write
+    steps:
+      - name: Stale issues
+        uses: actions/stale@v5
+        id: stale-issues
+        with:
+          debug-only: ${{ github.event.inputs.debug-only == 'true' }}
+          operations-per-run: 30
+          days-before-stale: 60
+          days-before-close: 30
+          ignore-updates: false
+          remove-stale-when-updated: true
+          stale-issue-label: "stale"
+          close-issue-label: "stale: closed"
+          stale-issue-message: |
+            This issue has been automatically marked as stale because it has not had recent activity during last 60 days :sleeping:
+
+            It will be closed in 30 days if no further activity occurs. To unstale this issue, remove stale label or add a comment with a detailed explanation.
+
+            There can be many reasons why some specific issue has no activity. The most probable cause is lack of time, not lack of interest.
+
+            Thank you for your patience :heart:
+          close-issue-message: |
+            This issue has been automatically closed because it has been inactive during the last 30 days since being marked as stale.
+
+            As author or maintainer, it can always be reopened if you see that carry on been useful.
+
+            Anyway, thank you for your interest in contribute :heart:
+          close-issue-reason: not_planned
+          exempt-issue-labels: "blocked,must,should,keep,:busts_in_silhouette: discussion,:eyes: Needs Review,:pushpin: pinned"
+          # disable PR processing at all (this step is for treat issues)
+          days-before-pr-stale: -1
+          days-before-pr-close: -1
+          ignore-pr-updates: true
+          remove-pr-stale-when-updated: false
+          stale-pr-label: " "
+
+      - name: Print outputs for issues
+        run: echo ${{ join(steps.stale-issues.outputs.*, ',') }}
+
+      - name: Stale Pull Requests
+        uses: actions/stale@v5
+        id: stale-prs
+        with:
+          debug-only: ${{ github.event.inputs.debug-only == 'true' }}
+          operations-per-run: 30
+          days-before-stale: 60
+          days-before-close: 30
+          ignore-updates: false
+          remove-stale-when-updated: true
+          stale-pr-label: "stale"
+          close-pr-label: "stale: closed"
+          stale-pr-message: |
+            This Pull Request has been automatically marked as stale because it has not had recent activity during last 60 days :sleeping:
+
+            It will be closed in 30 days if no further activity occurs. To unstale this PR, draft it, remove stale label, comment with a detailed explanation or push more commits.
+
+            There can be many reasons why some specific PR has no activity. The most probable cause is lack of time, not lack of interest.
+
+            Thank you for your patience :heart:
+          close-pr-message: |
+            This Pull Request has been automatically closed because it has been inactive during the last 30 days since being marked as stale.
+
+            As author or maintainer, it can always be reopened if you see that carry on been useful.
+
+            Anyway, thank you for your interest in contribute :heart:
+          exempt-draft-pr: true
+          exempt-pr-labels: "blocked,must,should,keep,:busts_in_silhouette: discussion,:eyes: Needs Review"
+          delete-branch: false  # if true, job needs permissions "contents: write"
+          # disable issues processing at all (this step is for treat PRs)
+          days-before-issue-stale: -1
+          days-before-issue-close: -1
+          ignore-issue-updates: true
+          remove-issue-stale-when-updated: false
+          stale-issue-label: " "
+
+      - name: Print outputs for PRs
+        run: echo ${{ join(steps.stale-prs.outputs.*, ',') }}
+
+      ## Removing private properties from each JSON object and compute array length
+      ## TODO: Delete these set-* workarounds when resolve actions/stale#806 ?
+      - name: Set staled
+        id: set-staled
+        run: |
+          echo $INPUT_ISSUES  \
+            | jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])'  \
+            | sed -e 's/^/::set-output name=issues::/'
+          echo $INPUT_ISSUES  \
+            | jq --raw-output '. | length'  \
+            | sed -e 's/^/::set-output name=issues-len::/'
+
+          echo $INPUT_PRS  \
+            | jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])'  \
+            | sed -e 's/^/::set-output name=prs::/'
+          echo $INPUT_PRS  \
+            | jq --raw-output '. | length'  \
+            | sed -e 's/^/::set-output name=prs-len::/'
+        env:
+          INPUT_ISSUES: ${{ steps.stale-issues.outputs.staled-issues-prs }}
+          INPUT_PRS:    ${{ steps.stale-prs.outputs.staled-issues-prs }}
+      - name: Set closed
+        id: set-closed
+        run: |
+          echo $INPUT_ISSUES  \
+            | jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])'  \
+            | sed -e 's/^/::set-output name=issues::/'
+          echo $INPUT_ISSUES  \
+            | jq --raw-output '. | length'  \
+            | sed -e 's/^/::set-output name=issues-len::/'
+
+          echo $INPUT_PRS  \
+            | jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])'  \
+            | sed -e 's/^/::set-output name=prs::/'
+          echo $INPUT_PRS  \
+            | jq --raw-output '. | length'  \
+            | sed -e 's/^/::set-output name=prs-len::/'
+        env:
+          INPUT_ISSUES: ${{ steps.stale-issues.outputs.closed-issues-prs }}
+          INPUT_PRS:    ${{ steps.stale-prs.outputs.closed-issues-prs }}
+
+      - name: Write job summary
+        run: |
+          echo "### Staled issues"  \
+            >> $GITHUB_STEP_SUMMARY
+          # render json array to a Markdown table with an optional "No records" message if empty
+          echo "$STALED_ISSUES"  \
+            | jq --raw-output 'map("| [#\(.number)](\(env.GITHUB_ISSUES_URL)/\(.number)) | \(.title) |") | join("\n") | if (. == "") then "\nNo records.\n" else "\n|    | Title |\n|---:|:------|\n\(.)\n" end'  \
+            >> $GITHUB_STEP_SUMMARY
+
+          echo "### Staled pull requests"  \
+            >> $GITHUB_STEP_SUMMARY
+          # render json array to a Markdown table with an optional "No records" message if empty
+          echo "$STALED_PRS"  \
+            | jq --raw-output 'map("| [#\(.number)](\(env.GITHUB_PULL_URL)/\(.number)) | \(.title) |") | join("\n") | if (. == "") then "\nNo records.\n" else "\n|    | Title |\n|---:|:------|\n\(.)\n" end'  \
+            >> $GITHUB_STEP_SUMMARY
+
+          echo "### Closed issues"  \
+            >> $GITHUB_STEP_SUMMARY
+          # render json array to a Markdown table with an optional "No records" message if empty
+          echo "$CLOSED_ISSUES"  \
+            | jq --raw-output 'map("| [#\(.number)](\(env.GITHUB_ISSUES_URL)/\(.number)) | \(.title) |") | join("\n") | if (. == "") then "\nNo records.\n" else "\n|    | Title |\n|---:|:------|\n\(.)\n" end'  \
+            >> $GITHUB_STEP_SUMMARY
+
+          echo "### Closed pull requests"  \
+            >> $GITHUB_STEP_SUMMARY
+          # render json array to a Markdown table with an optional "No records" message if empty
+          echo "$CLOSED_PRS"  \
+            | jq --raw-output 'map("| [#\(.number)](\(env.GITHUB_PULL_URL)/\(.number)) | \(.title) |") | join("\n") | if (. == "") then "\nNo records.\n" else "\n|    | Title |\n|---:|:------|\n\(.)\n" end'  \
+            >> $GITHUB_STEP_SUMMARY
+        env:
+          GITHUB_ISSUES_URL: ${{ format('{0}/{1}/issues', github.server_url, github.repository) }}
+          GITHUB_PULL_URL:   ${{ format('{0}/{1}/pull', github.server_url, github.repository) }}
+          STALED_ISSUES: ${{ steps.set-staled.outputs.issues }}
+          CLOSED_ISSUES: ${{ steps.set-closed.outputs.issues }}
+          STALED_PRS:    ${{ steps.set-staled.outputs.prs }}
+          CLOSED_PRS:    ${{ steps.set-closed.outputs.prs }}