-
Notifications
You must be signed in to change notification settings - Fork 306
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6376 from payara/ramya-automate
Github action to automate additional Community Supporting Processes
- Loading branch information
Showing
5 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
name: Monitor Inactive Open Issues | ||
#Runs every Monday and Thursday at 9:00 A.M | ||
on: | ||
schedule: | ||
- cron: "0 9 * * 1,4" | ||
env: | ||
inactiveIntervalDays: ${{ vars.MONITORING_INACTIVE_INTERVAL_DAYS }} | ||
jobs: | ||
retrieve-inactive-issues: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
issues: write | ||
outputs: | ||
issues: ${{ steps.filter-inactive-issues.outputs.result }} | ||
steps: | ||
- name: Check environment | ||
run: | | ||
if [ -z $inactiveIntervalDays ]; then | ||
echo "::error::'MONITORING_INACTIVE_INTERVAL_DAYS' environment variable is not set" | ||
exit 1 | ||
fi | ||
- uses: actions/checkout@v3 | ||
if: success() | ||
- name: Filter inactive issues | ||
id: filter-inactive-issues | ||
uses: actions/github-script@v6 | ||
with: | ||
script: | | ||
const script = require('./.github/workflows/scripts/filterInactiveIssues.js'); | ||
return await script({github, context, core}); | ||
notify-inactive-issues: | ||
runs-on: ubuntu-latest | ||
needs: retrieve-inactive-issues | ||
if: ${{ needs.retrieve-inactive-issues.outputs.issues }} | ||
strategy: | ||
matrix: | ||
issues: ${{ fromJSON(needs.retrieve-inactive-issues.outputs.issues) }} | ||
steps: | ||
- name: Notify MS Teams channel | ||
id: notify-ms-teams | ||
uses: simbo/msteams-message-card-action@latest | ||
with: | ||
webhook: ${{ secrets.COMMUNITY_EVENTS_WEBHOOK_URL }} | ||
title: Inactive Issue Detected | ||
message: | | ||
It's been <i>${{ env.inactiveIntervalDays }} days</i> since issue number <code>${{ matrix.issues.number }}</code> has received an update. <strong>${{ matrix.issues.assignee }}</strong>, please provide an update soon. | ||
buttons: | | ||
View Issue on GitHub ${{ matrix.issues.url }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
name: Monitor issues on voting status | ||
#Runs the first day of each month at 10 A.M | ||
on: | ||
schedule: | ||
- cron: "0 10 1 * *" | ||
|
||
jobs: | ||
select-top-voted-issue: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
issues: write | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Select the most voted enhancement | ||
id: select-top-voted-issue | ||
uses: actions/github-script@v6 | ||
with: | ||
script: | | ||
const script = require('./.github/workflows/scripts/selectMostVotedIssue.js') | ||
return await script({github, context, core}) | ||
- name: Notify MS Teams channel | ||
id: notify-ms-teams | ||
if: ${{ success() && steps.select-top-voted-issue.outputs.result }} | ||
uses: simbo/msteams-message-card-action@latest | ||
env: | ||
issueTitle: ${{ fromJSON(steps.select-top-voted-issue.outputs.result).title }} | ||
issueURL: ${{ fromJSON(steps.select-top-voted-issue.outputs.result).url }} | ||
assignee: ${{ fromJSON(steps.select-top-voted-issue.outputs.result).assignee }} | ||
with: | ||
webhook: ${{ secrets.COMMUNITY_EVENTS_WEBHOOK_URL }} | ||
title: An Enhancement Proposal Issue has been selected the top-voted issue! | ||
message: <code>${{ env.issueTitle }}</code> assigned to <strong>${{ env.assignee }}</strong> | ||
buttons: | | ||
View Issue on GitHub ${{ env.issueURL }} | ||
close-forgotten-voting-issues: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
issues: write | ||
needs: select-top-voted-issue | ||
env: | ||
maximumVotingThreshold: ${{ vars.MAX_VOTING_THRESHOLD_DAYS }} | ||
steps: | ||
- name: Check environment | ||
run: | | ||
if [ -z $maximumVotingThreshold ]; then | ||
echo "::error::'MAX_VOTING_THRESHOLD_DAYS' environment variable is not set" | ||
exit 1 | ||
fi | ||
- uses: actions/checkout@v3 | ||
if: success() | ||
- name: Close "forgotten" enhancement requests | ||
id: close-forgotten-enhancements | ||
if: success() | ||
uses: actions/github-script@v6 | ||
with: | ||
script: | | ||
const script = require('./.github/workflows/scripts/closeForgottenEnhancements.js') | ||
script({github, context, core}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
module.exports = async ({github, context, core}) => { | ||
const {owner, repo} = context.repo; | ||
// Query all GH issues for Voting | ||
|
||
const votingLabel = "Status: Voting"; | ||
let response = await github.rest.issues.listForRepo({ | ||
owner, | ||
repo, | ||
labels: votingLabel, | ||
state: 'open', | ||
}); | ||
if (response.data.length === 0) { | ||
core.debug('No issues marked for voting found. Exiting.'); | ||
return; | ||
} | ||
const votingThreshold = process.env.maximumVotingThreshold; | ||
const parsedDays = parseFloat(votingThreshold); | ||
|
||
let now = new Date().getTime(); | ||
for (let issue of response.data) { | ||
core.debug(`Processing issue #${issue.number}`); | ||
core.debug(`Issue was created ${issue.created_at}`); | ||
|
||
let createdDate = new Date(issue.created_at).getTime(); | ||
let daysSinceCreated = (now - createdDate) / 1000 / 60 / 60 / 24; | ||
let reactions = issue.reactions['+1']; | ||
|
||
core.debug(`Issue +1 reactions count is ${reactions}`); | ||
|
||
if (reactions < 2 && daysSinceCreated > parsedDays) { | ||
core.debug(`Closing #${issue.number} because it hasn't received enough votes after ${parsedDays} days`); | ||
|
||
const message = `Greetings, | ||
This issue has been open for community voting for more than ${parsedDays} days and sadly it hasn't received enough votes to be considered for its implementation according to our community policies. | ||
As there is not enough interest from the community we'll proceed to close this issue.`; | ||
|
||
await github.rest.issues.createComment({ | ||
owner : owner, | ||
repo : repo, | ||
issue_number: issue.number, | ||
body: message | ||
}); | ||
|
||
await github.rest.issues.update({ | ||
owner: owner, | ||
repo: repo, | ||
issue_number: issue.number, | ||
labels: [], | ||
state: 'closed' | ||
}); | ||
|
||
await github.rest.issues.lock({ | ||
owner : owner, | ||
repo : repo, | ||
issue_number : issue.number, | ||
lock_reason : 'resolved' | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
module.exports = async ({github, context, core}) => { | ||
const { owner, repo } = context.repo; | ||
const openLabel = "Status: Open"; | ||
|
||
const parsedDays = process.env.inactiveIntervalDays; | ||
const thresholdInMillis = parsedDays * 24 * 60 * 60 * 1000; | ||
|
||
// Query all GH issues that are open | ||
const response = await github.rest.issues.listForRepo({ | ||
owner, | ||
repo, | ||
labels: openLabel, | ||
state: "open", | ||
}); | ||
core.debug(`Inactive interval days is set to ${parsedDays}`); | ||
|
||
let inactiveIssues = []; | ||
for(let issue of response.data){ | ||
//Get issue events, which are returned by creation date in descending order | ||
const eventResponse = await github.rest.issues.listEvents({ | ||
owner, | ||
repo, | ||
issue_number : issue.number | ||
}); | ||
//Filter which events correspond to the 'labeled' event in which the `Status: Open` label was added | ||
let lastOpenEvent = eventResponse.data.filter((event) => event.event === 'labeled' && event.label.name === openLabel)[0]; | ||
|
||
//If the event date is beyond the threshold date, the issue is added to the result array | ||
if((new Date().getTime() - new Date(lastOpenEvent.created_at).getTime()) > thresholdInMillis){ | ||
inactiveIssues.push({ | ||
number : issue.number, | ||
title : issue.title, | ||
url: issue.html_url, | ||
assignee: issue.assignees.length ? issue.assignees[0].login : '???' | ||
}); | ||
} | ||
} | ||
|
||
core.debug(`${inactiveIssues.length} issues detected to be inactive`); | ||
if (inactiveIssues.length > 0) { | ||
return inactiveIssues; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
module.exports = async ({github, context, core}) => { | ||
let { owner, repo } = context.repo; | ||
|
||
const openLabel = "Status: Open"; | ||
const votingLabel = "Status: Voting"; | ||
|
||
// Query all GH issues for Voting | ||
const response = await github.rest.issues.listForRepo({ | ||
owner, | ||
repo, | ||
labels: votingLabel, | ||
state: 'open', | ||
direction: 'desc', | ||
}); | ||
|
||
//response has all the issues labeled with Voting. | ||
if (response.data.length === 0) { | ||
core.debug('No issues marked for voting found. Exiting.'); | ||
return; | ||
} | ||
//filter issues with at least 2 votes. | ||
response.data = response.data.filter((issue) => issue.reactions['+1'] > 1) | ||
if (response.data.length === 0) { | ||
core.debug('No issues with more than 2 votes found. Exiting'); | ||
return; | ||
} | ||
|
||
let mostVotes = 0; | ||
let selectedIssue = 0; | ||
let oldestDate = null; | ||
|
||
for (const issue of response.data) { | ||
core.debug(`Processing issue #${issue.number}`); | ||
core.debug(`Number of +1 reactions ${issue.reactions['+1']}`); | ||
core.debug(`Issue was created ${issue.created_at}`); | ||
|
||
let votes = issue.reactions['+1']; | ||
let createdDate = new Date(issue.created_at).getTime(); | ||
|
||
if (oldestDate === null) { | ||
oldestDate = createdDate; | ||
selectedIssue = issue; | ||
mostVotes = votes; | ||
} | ||
if ((votes >= mostVotes) && (createdDate < oldestDate)) { | ||
mostVotes = votes; | ||
selectedIssue = issue; | ||
} | ||
} | ||
core.debug(`Highest votes is ${mostVotes}`); | ||
core.debug(`Final issue selected for enhancement is #${selectedIssue.number} created on ${selectedIssue.created_at}`); | ||
|
||
let message = `Greetings, | ||
This enhancement request has been selected by the Payara Community as the most voted enhancement of this month and | ||
thus will be escalated to our product development backlog.`; | ||
|
||
await github.rest.issues.createComment({ | ||
owner : owner, | ||
repo : repo, | ||
issue_number: selectedIssue.number, | ||
body: message | ||
}); | ||
await github.rest.issues.update({ | ||
owner : owner, | ||
repo : repo, | ||
issue_number: selectedIssue.number, | ||
labels : [openLabel] | ||
}); | ||
|
||
return { | ||
number : selectedIssue.number, | ||
title : selectedIssue.title, | ||
url: selectedIssue.html_url, | ||
assignee: selectedIssue.assignees.length ? selectedIssue.assignees[0].login : null | ||
}; | ||
} |