Skip to content
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
204 changes: 204 additions & 0 deletions .github/scripts/dapr_bot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// list of owner who can control dapr-bot workflow.
// TODO: Read owners from OWNERS file.
const owners = [
"yaron2",
"youngbupark",
"Haishi2016",
"lukekim",
"amanbha",
"msfussell",
"shalabhms",
"LMWF",
"artursouza",
"vinayada1",
"mukundansundar",
"wcs1only",
"orizohar",
"pruthvidhodda",
"mchmarny",
"tcnghia",
"berndverst",
"halspang",
"tanvigour",
"dmitsh",
"pkedy",
"CodeMonkeyLeet",
"XavierGeerinck",
"amulyavarote",
"shubham1172"
];

/**
* Execute fn if label exists on an issue.
* @param {*} github GitHub object reference
* @param {*} issue GitHub issue reference
* @param {*} label label name
* @param {*} fn async function
*/
async function executeIfIssueHasLabel(github, issue, label, fn) {
const response = await github.issues.listLabelsOnIssue({
issue_number: issue.number,
owner: issue.owner,
repo: issue.repo,
});

const labelNames = response.data.map((i) => i.name);
if (labelNames.indexOf(label) > -1) {
await fn();
}
}

/**
* Assign an issue to assignee.
* @param {*} github GitHub object reference
* @param {*} context GitHub action context
* @param {boolean} isPullRequest is the workflow triggered by a pull request?
*/
async function executeAssign(github, context, isPullRequest) {
const issue = context.issue;

if (isPullRequest) {
console.log("[executeAssign] pull requests unsupported, skipping command execution.");
return;
} else if (issue.assignees && issue.assignees.length !== 0) {
console.log("[executeAssign] issue already has assignees, skipping command execution.");
return;
}

await github.issues.addAssignees({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
assignees: [context.actor],
});
}

/**
* Add a label to the issue indicating that it needs the author's feedback.
* @param {*} github GitHub object reference
* @param {*} context GitHub action context
* @param {boolean} isPullRequest is the workflow triggered by a pull request?
* @returns
*/
async function executePingAuthor(github, context, isPullRequest) {
const issue = context.issue;

if (isPullRequest) {
console.log("[executePingAuthor] pull requests unsupported, skipping command execution.");
return;
} else if (owners.indexOf(context.actor) < 0) {
console.log("[executePingAuthor] user does not have privilege, skipping command execution.");
return;
}

// if there is a 'needs-team-attention' label, remove it.
await executeIfIssueHasLabel(github, issue, 'needs-team-attention', async () => {
await github.issues.removeLabel({
issue_number: issue.number,
owner: issue.owner,
repo: issue.repo,
name: 'needs-team-attention'
});
});

// Add new label
await github.issues.addLabels({
issue_number: issue.number,
owner: issue.owner,
repo: issue.repo,
labels: ['needs-author-feedback']
});
}

/**
* Trigger e2e tests for pull request
* @param {*} github GitHub object reference
* @param {*} context GitHub action context
* @param {boolean} isPullRequest is the workflow triggered by a pull request?
*/
async function executeEndToEndTests(github, context, isPullRequest) {
const issue = context.issue;

if (!isPullRequest) {
console.log("[executeEndToEndTests] issues unsupported, skipping command execution.");
return;
} else if (owners.indexOf(context.actor) < 0) {
console.log("[executeEndToEndTests] user does not have privilege, skipping command execution.");
return;
}

// Get pull request
const pull = await github.pulls.get({
owner: issue.owner,
repo: issue.repo,
pull_number: issue.number
});

if (pull && pull.data) {
// Get commit id and repo from pull head
const clientPayload = {
pull_head_ref: pull.data.head.sha,
pull_head_repo: pull.data.head.repo.full_name,
command: "ok-to-e2e-test",
issue: issue,
};

// Fire repository_dispatch event to trigger e2e test
await github.repos.createDispatchEvent({
owner: issue.owner,
repo: issue.repo,
event_type: "e2e-test",
client_payload: clientPayload,
});

console.log(`[executeEndToEndTests] triggered E2E tests for ${JSON.stringify(clientPayload)}.`);
}
}


export default async ({ github, context }) => {
const payload = context.payload;
const issue = context.issue;
const isFromPulls = !!payload.issue.pull_request;
const commentBody = payload.comment.body;

if (!commentBody) {
console.log("[main] comment body not found, exiting.");
return;
}

// the author of this issue is interacting with it
if (!isFromPulls && context.actor == issue.owner) {
// if there is a 'needs-author-feedback' label,
// replace it with 'needs-team-attention' label.
await executeIfIssueHasLabel(github, issue, 'needs-author-feedback', async () => {
await github.issues.removeLabel({
issue_number: issue.number,
owner: issue.owner,
repo: issue.repo,
name: 'needs-author-feedback'
});
await github.issues.addLabels({
issue_number: issue.number,
owner: issue.owner,
repo: issue.repo,
labels: ['needs-team-attention']
});
});
}

switch (commentBody) {
case "/assign":
executeAssign(github, context, isFromPulls);
break;
case "/ping-author":
executePingAuthor(github, context, isFromPulls);
break;
case "/ok-to-e2e-test":
executeEndToEndTests(github, context, isFromPulls);
break;
default:
console.log(`[main] command ${commentBody} not found, exiting.`);
break;
}
};
54 changes: 54 additions & 0 deletions .github/workflows/dapr-bot-schedule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# Copyright 2022 The Dapr Authors
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: dapr-bot-schedule

on:
schedule:
- cron: '*/10 * * * *'
workflow_dispatch:
jobs:
prune_stale:
name: Prune Stale
runs-on: ubuntu-latest
steps:
- name: Prune Stale
uses: actions/stale@v5.0.0
with:
repo-token: ${{ secrets.DAPR_BOT_TOKEN }}
days-before-issue-stale: 60
days-before-pr-stale: 30
days-before-close: 7
stale-issue-message: >
This issue has been automatically marked as stale because it has not had activity in the
last 60 days. It will be closed in the next 7 days unless it is tagged (pinned, good first issue, help wanted or triaged/resolved) or other activity
occurs. Thank you for your contributions.
close-issue-message: >
This issue has been automatically closed because it has not had activity in the
last 67 days. If this issue is still valid, please ping a maintainer and ask them to label it as pinned, good first issue, help wanted or triaged/resolved.
Thank you for your contributions.
stale-pr-message: >
This pull request has been automatically marked as stale because it has not had
activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please
feel free to give a status update now, ping for review, or re-open when it's ready.
Thank you for your contributions!
close-pr-message: >
This pull request has been automatically closed because it has not had
activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready.
Thank you for your contributions!
stale-issue-label: 'stale'
exempt-issue-labels: 'pinned,good first issue,help wanted,triaged/resolved,triaged/unresolved'
stale-pr-label: 'stale'
exempt-pr-labels: 'pinned'
operations-per-run: 500
ascending: true
20 changes: 4 additions & 16 deletions .github/workflows/dapr-bot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,11 @@ jobs:
name: bot-processor
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2 # to make the JS script available for the next step
- name: Comment analyzer
uses: actions/github-script@v1
uses: actions/github-script@v4
with:
github-token: ${{secrets.DAPR_BOT_TOKEN}}
script: |
const payload = context.payload;
const issue = context.issue;
const isFromPulls = !!payload.issue.pull_request;
const commentBody = payload.comment.body;
if (!isFromPulls && commentBody && commentBody.indexOf("/assign") == 0) {
if (!issue.assignees || issue.assignees.length === 0) {
await github.issues.addAssignees({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
assignees: [context.actor],
})
}
return;
}
const script = require('./.github/scripts/dapr_bot.js')
await script({github, context})
5 changes: 5 additions & 0 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ on:
branches:
- master
- release-*
# Manual trigger
workflow_dispatch:
# Dispatch on external events
repository_dispatch:
types: [e2e-test]

jobs:
test-e2e:
Expand Down