From 09f1cafc50c8728f3cf0c61695aa0554f71bc833 Mon Sep 17 00:00:00 2001 From: Viktor Kram <92625690+ViktorKram@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:09:09 +0300 Subject: [PATCH] [CI] Add an action to notify about "freezed" PRs. (#83) Signed-off-by: Viktor Kramarenko --- .github/scripts/fetch_prs.mjs | 83 +++++++++++++++++++++++++++++++ .github/scripts/package.json | 11 ++++ .github/workflows/prs-summary.yml | 47 +++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 .github/scripts/fetch_prs.mjs create mode 100644 .github/scripts/package.json create mode 100644 .github/workflows/prs-summary.yml diff --git a/.github/scripts/fetch_prs.mjs b/.github/scripts/fetch_prs.mjs new file mode 100644 index 00000000..9209b057 --- /dev/null +++ b/.github/scripts/fetch_prs.mjs @@ -0,0 +1,83 @@ +// Copyright 2024 Flant JSC +// +// 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. + +import { Octokit } from '@octokit/core'; +import axios from 'axios'; +import moment from 'moment'; + +const owner = 'deckhouse'; +const repo = 'sds-node-configurator'; +const project = 'SNC' + +const octokit = new Octokit({ auth: process.env.PR_SUMMARY_TOKEN }); + + +async function fetchPullRequests() { + const pulls = await octokit.request('GET /repos/{owner}/{repo}/pulls', { + owner, + repo, + state: 'all' + }); + return pulls.data.filter(pr => !pr.draft); +} + +const recentDays = 2; + +function generateSummary(prs) { + const now = moment(); + const reviewRequired = prs.filter(pr => pr.state === 'open' && pr.requested_reviewers.length > 0); + const recent = reviewRequired.filter(pr => moment().diff(moment(pr.created_at), 'days') <= recentDays); + const lasting = reviewRequired.filter(pr => moment().diff(moment(pr.created_at), 'days') > recentDays); + + let summary = `## ${project} PRs ${now.format('YYYY-MM-DD')}\n\n`; + + if (reviewRequired.length == 0) { + summary += `:tada: No review required for today\n`; + return summary; + } + + if (recent.length > 0) { + summary += `### Recent PRs requiring review +${recent.map(pr => `- [${pr.title}](${pr.html_url}) (Created: ${moment(pr.created_at).fromNow()})`).join('\n')} +`; + } + + if (lasting.length > 0) { + summary += `### PRs requiring review +${lasting.map(pr => `- [${pr.title}](${pr.html_url}) (Created: ${moment(pr.created_at).fromNow()})`).join('\n')} +`; + } + + return summary +} + +async function sendSummaryToLoop(summary) { + const url = process.env.LOOP_WEBHOOK_URL; + await axios.post(url, { + text: summary + }); +} + +async function run() { + try { + const prs = await fetchPullRequests(); + const summary = generateSummary(prs); + await sendSummaryToLoop(summary); + } catch (error) { + console.error(error); + process.exit(1); + } +} + +run(); \ No newline at end of file diff --git a/.github/scripts/package.json b/.github/scripts/package.json new file mode 100644 index 00000000..a0006b0f --- /dev/null +++ b/.github/scripts/package.json @@ -0,0 +1,11 @@ +{ + "name": "github-action-pr-summary", + "version": "1.0.0", + "main": ".github/scripts/fetch_prs.mjs", + "dependencies": { + "@octokit/core": "^3.2.5", + "axios": "^0.24.0", + "moment": "^2.29.1" + }, + "type": "module" +} \ No newline at end of file diff --git a/.github/workflows/prs-summary.yml b/.github/workflows/prs-summary.yml new file mode 100644 index 00000000..6a5138e2 --- /dev/null +++ b/.github/workflows/prs-summary.yml @@ -0,0 +1,47 @@ +# Copyright 2024 Flant JSC +# +# 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: PR Summary + +on: + schedule: + - cron: "0 7 * * 1-5" # Runs on every day-of-week from Monday through Friday at 7 AM UTC (10 AM MSK) + workflow_dispatch: + +defaults: + run: + shell: bash + +jobs: + pr_summary: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: "18" # Use Node.js 18 + + - name: Install dependencies + run: npm install -S .github/scripts + + - name: Fetch PR Data and Send Summary + run: | + node ./.github/scripts/fetch_prs.mjs + env: + GITHUB_TOKEN: ${{ secrets.PR_SUMMARY_TOKEN }} + LOOP_WEBHOOK_URL: ${{ secrets.LOOP_WEBHOOK_URL }} \ No newline at end of file