Skip to content

Commit 8845486

Browse files
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 <[email protected]> * 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 dc44e45 * 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 <[email protected]>
1 parent 4d67825 commit 8845486

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

Diff for: .github/workflows/stale.yml

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
name: Stale handler
2+
3+
on:
4+
push: # when push this files to branches....
5+
branches:
6+
- 'main'
7+
- 'gh-actions/test'
8+
paths:
9+
- '.github/workflows/stale.yml' # - this workflow
10+
workflow_dispatch: # manually
11+
inputs:
12+
debug-only:
13+
type: boolean
14+
description: 'If enabled, debug mode is on and then API calls that can alter your issues will not happen'
15+
required: true
16+
default: true
17+
schedule: # or
18+
- cron: "0 0 * * *" # once a day at 00:00 o'clock
19+
20+
permissions:
21+
# no checkout/branching needed
22+
contents: none
23+
24+
# This allows a subsequently queued workflow run to interrupt/wait for previous runs
25+
concurrency:
26+
group: '${{ github.workflow }}'
27+
cancel-in-progress: false # true: interrupt, false = wait for
28+
29+
jobs:
30+
stale:
31+
name: Staler job
32+
runs-on: ubuntu-latest
33+
outputs:
34+
# "XXX-len": the length of the "XXX" output object
35+
staled-issues: ${{ steps.set-staled.outputs.issues }}
36+
staled-issues-len: ${{ steps.set-staled.outputs.issues-len }}
37+
staled-prs: ${{ steps.set-staled.outputs.prs }}
38+
staled-prs-len: ${{ steps.set-staled.outputs.prs-len }}
39+
closed-issues: ${{ steps.set-closed.outputs.issues }}
40+
closed-issues-len: ${{ steps.set-closed.outputs.issues-len }}
41+
closed-prs: ${{ steps.set-closed.outputs.prs }}
42+
closed-prs-len: ${{ steps.set-closed.outputs.prs-len }}
43+
# enable write access rights to allow bot comments and labeling
44+
permissions:
45+
issues: write
46+
pull-requests: write
47+
steps:
48+
- name: Stale issues
49+
uses: actions/stale@v5
50+
id: stale-issues
51+
with:
52+
debug-only: ${{ github.event.inputs.debug-only == 'true' }}
53+
operations-per-run: 30
54+
days-before-stale: 60
55+
days-before-close: 30
56+
ignore-updates: false
57+
remove-stale-when-updated: true
58+
stale-issue-label: "stale"
59+
close-issue-label: "stale: closed"
60+
stale-issue-message: |
61+
This issue has been automatically marked as stale because it has not had recent activity during last 60 days :sleeping:
62+
63+
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.
64+
65+
There can be many reasons why some specific issue has no activity. The most probable cause is lack of time, not lack of interest.
66+
67+
Thank you for your patience :heart:
68+
close-issue-message: |
69+
This issue has been automatically closed because it has been inactive during the last 30 days since being marked as stale.
70+
71+
As author or maintainer, it can always be reopened if you see that carry on been useful.
72+
73+
Anyway, thank you for your interest in contribute :heart:
74+
close-issue-reason: not_planned
75+
exempt-issue-labels: "blocked,must,should,keep,:busts_in_silhouette: discussion,:eyes: Needs Review,:pushpin: pinned"
76+
# disable PR processing at all (this step is for treat issues)
77+
days-before-pr-stale: -1
78+
days-before-pr-close: -1
79+
ignore-pr-updates: true
80+
remove-pr-stale-when-updated: false
81+
stale-pr-label: " "
82+
83+
- name: Print outputs for issues
84+
run: echo ${{ join(steps.stale-issues.outputs.*, ',') }}
85+
86+
- name: Stale Pull Requests
87+
uses: actions/stale@v5
88+
id: stale-prs
89+
with:
90+
debug-only: ${{ github.event.inputs.debug-only == 'true' }}
91+
operations-per-run: 30
92+
days-before-stale: 60
93+
days-before-close: 30
94+
ignore-updates: false
95+
remove-stale-when-updated: true
96+
stale-pr-label: "stale"
97+
close-pr-label: "stale: closed"
98+
stale-pr-message: |
99+
This Pull Request has been automatically marked as stale because it has not had recent activity during last 60 days :sleeping:
100+
101+
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.
102+
103+
There can be many reasons why some specific PR has no activity. The most probable cause is lack of time, not lack of interest.
104+
105+
Thank you for your patience :heart:
106+
close-pr-message: |
107+
This Pull Request has been automatically closed because it has been inactive during the last 30 days since being marked as stale.
108+
109+
As author or maintainer, it can always be reopened if you see that carry on been useful.
110+
111+
Anyway, thank you for your interest in contribute :heart:
112+
exempt-draft-pr: true
113+
exempt-pr-labels: "blocked,must,should,keep,:busts_in_silhouette: discussion,:eyes: Needs Review"
114+
delete-branch: false # if true, job needs permissions "contents: write"
115+
# disable issues processing at all (this step is for treat PRs)
116+
days-before-issue-stale: -1
117+
days-before-issue-close: -1
118+
ignore-issue-updates: true
119+
remove-issue-stale-when-updated: false
120+
stale-issue-label: " "
121+
122+
- name: Print outputs for PRs
123+
run: echo ${{ join(steps.stale-prs.outputs.*, ',') }}
124+
125+
## Removing private properties from each JSON object and compute array length
126+
## TODO: Delete these set-* workarounds when resolve actions/stale#806 ?
127+
- name: Set staled
128+
id: set-staled
129+
run: |
130+
echo $INPUT_ISSUES \
131+
| jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])' \
132+
| sed -e 's/^/::set-output name=issues::/'
133+
echo $INPUT_ISSUES \
134+
| jq --raw-output '. | length' \
135+
| sed -e 's/^/::set-output name=issues-len::/'
136+
137+
echo $INPUT_PRS \
138+
| jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])' \
139+
| sed -e 's/^/::set-output name=prs::/'
140+
echo $INPUT_PRS \
141+
| jq --raw-output '. | length' \
142+
| sed -e 's/^/::set-output name=prs-len::/'
143+
env:
144+
INPUT_ISSUES: ${{ steps.stale-issues.outputs.staled-issues-prs }}
145+
INPUT_PRS: ${{ steps.stale-prs.outputs.staled-issues-prs }}
146+
- name: Set closed
147+
id: set-closed
148+
run: |
149+
echo $INPUT_ISSUES \
150+
| jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])' \
151+
| sed -e 's/^/::set-output name=issues::/'
152+
echo $INPUT_ISSUES \
153+
| jq --raw-output '. | length' \
154+
| sed -e 's/^/::set-output name=issues-len::/'
155+
156+
echo $INPUT_PRS \
157+
| jq --compact-output --raw-output 'del(.[] | .[to_entries[] | .key | select(startswith("_"))])' \
158+
| sed -e 's/^/::set-output name=prs::/'
159+
echo $INPUT_PRS \
160+
| jq --raw-output '. | length' \
161+
| sed -e 's/^/::set-output name=prs-len::/'
162+
env:
163+
INPUT_ISSUES: ${{ steps.stale-issues.outputs.closed-issues-prs }}
164+
INPUT_PRS: ${{ steps.stale-prs.outputs.closed-issues-prs }}
165+
166+
- name: Write job summary
167+
run: |
168+
echo "### Staled issues" \
169+
>> $GITHUB_STEP_SUMMARY
170+
# render json array to a Markdown table with an optional "No records" message if empty
171+
echo "$STALED_ISSUES" \
172+
| 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' \
173+
>> $GITHUB_STEP_SUMMARY
174+
175+
echo "### Staled pull requests" \
176+
>> $GITHUB_STEP_SUMMARY
177+
# render json array to a Markdown table with an optional "No records" message if empty
178+
echo "$STALED_PRS" \
179+
| 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' \
180+
>> $GITHUB_STEP_SUMMARY
181+
182+
echo "### Closed issues" \
183+
>> $GITHUB_STEP_SUMMARY
184+
# render json array to a Markdown table with an optional "No records" message if empty
185+
echo "$CLOSED_ISSUES" \
186+
| 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' \
187+
>> $GITHUB_STEP_SUMMARY
188+
189+
echo "### Closed pull requests" \
190+
>> $GITHUB_STEP_SUMMARY
191+
# render json array to a Markdown table with an optional "No records" message if empty
192+
echo "$CLOSED_PRS" \
193+
| 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' \
194+
>> $GITHUB_STEP_SUMMARY
195+
env:
196+
GITHUB_ISSUES_URL: ${{ format('{0}/{1}/issues', github.server_url, github.repository) }}
197+
GITHUB_PULL_URL: ${{ format('{0}/{1}/pull', github.server_url, github.repository) }}
198+
STALED_ISSUES: ${{ steps.set-staled.outputs.issues }}
199+
CLOSED_ISSUES: ${{ steps.set-closed.outputs.issues }}
200+
STALED_PRS: ${{ steps.set-staled.outputs.prs }}
201+
CLOSED_PRS: ${{ steps.set-closed.outputs.prs }}

0 commit comments

Comments
 (0)