Skip to content

Commit

Permalink
21.5기 토이프로젝트 3일 간격 대시보드 (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
JuTaK97 authored Jan 13, 2024
1 parent 60ee937 commit ad7dfc5
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 0 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/toyproject-21.5-three-days-dashboard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: toyproject-21.5-send-three-days-dashboard

on:
schedule:
- cron: '20 2 * * *' # 한국 시간대, 매일 11시 20분에 실행

jobs:
cron:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]

steps:
- name: Check out code
uses: actions/checkout@v3
with:
fetch-depth: 2

- name: Setup Node.js environment
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'yarn'

# cron job을 실행합니다.
- name: run script
run: |
yarn install
SLACK_WEEKLY_CHANNEL_ID=C06BH14TZK6 \
SLACK_AUTH_TOKEN=${{ secrets.SLACK_AUTH_TOKEN }} \
GHP_ACCESS_TOKEN=${{ secrets.GHP_ACCESS_TOKEN }} \
GITHUB_ORGANIZATION=wafflestudio21-5 \
yarn send:toyproject-21.5-three-days-dashboard
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"start:server": "node dist/src/server.js",
"dev:server": "ts-node src/server.ts",
"send:weekly-dashboard": "ts-node src/weekly-dashboard.ts",
"send:toyproject-21.5-three-days-dashboard": "ts-node src/toyproject-21.5-three-days-dashboard.ts",
"deploy-server": "scripts/deploy.sh",
"test:unit": "jest",
"lint": "eslint ./src"
Expand Down
123 changes: 123 additions & 0 deletions src/infrastructures/implementDashboardService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type SlackClient } from '../clients/SlackClient';
import { type Repository } from '../entities/GitHub';
import { type GithubApiRepository } from '../repositories/GithubApiRepository';
import { type DashboardService } from '../services/DashboardService';

Expand Down Expand Up @@ -67,6 +68,128 @@ export const implementDashboardService = ({
.join('\n\n');
await slackClient.sendMessage([divider, title, divider, repositories].join('\n'));
},
sendGithubTopRepositoriesPerTeamLastThreeDays: async (organization: string) => {
const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
const repos = await githubApiRepository.listOrganizationRepositories(organization, {
sort: 'pushed',
perPage: 30,
});

const reposGroupByTeam = new Map<
number,
{ teamNumber: number; serverRepo: Repository | undefined; clientRepo: Repository | undefined }
>();
repos.forEach((repo) => {
console.log(repo.name);
const extractedNumbers = repo.name.match(/\d+/);
if (extractedNumbers) {
const teamNumber = parseInt(extractedNumbers[0], 10);
const isServer = repo.name.endsWith('server');

const data = reposGroupByTeam.has(teamNumber)
? reposGroupByTeam.get(teamNumber)!
: { teamNumber: teamNumber, serverRepo: undefined, clientRepo: undefined };
if (isServer) {
data.serverRepo = repo;
} else {
data.clientRepo = repo;
}
reposGroupByTeam.set(teamNumber, data);
}
});

console.log(reposGroupByTeam.size);

const repoWithDetails = await Promise.all(
Array.from(reposGroupByTeam.values()).map(async ({ teamNumber, serverRepo, clientRepo }) => {
if (!serverRepo || !clientRepo) return [];

const recentMergedPullRequests = (
await githubApiRepository.listRepositoryPullRequests(organization, serverRepo.name, {
perPage: 100,
sort: 'updated',
state: 'closed',
direction: 'desc',
})
)
.concat(
await githubApiRepository.listRepositoryPullRequests(organization, clientRepo.name, {
perPage: 100,
sort: 'updated',
state: 'closed',
direction: 'desc',
}),
)
.filter((pr) => pr.merged_at && new Date(pr.merged_at) > threeDaysAgo);

const recentCreatedComments = (
await githubApiRepository.listRepositoryComments(organization, serverRepo.name, {
perPage: 100,
sort: 'created_at',
direction: 'desc',
})
)
.concat(
await githubApiRepository.listRepositoryComments(organization, clientRepo.name, {
perPage: 100,
sort: 'created_at',
direction: 'desc',
}),
)
.filter((c) => new Date(c.created_at) > threeDaysAgo);

const score = recentMergedPullRequests.length * 5 + recentCreatedComments.length * 1;

if (score === 0) return [];

return [
{
serverRepo: serverRepo,
clientRepo: clientRepo,
teamName: `team${teamNumber}`,
score,
details: {
pullRequestCount: recentMergedPullRequests.length,
commentCount: recentCreatedComments.length,
},
},
];
}),
);

const topRepositories = repoWithDetails.flat().sort((a, b) => b.score - a.score);
const topRepositoriesLength = 3;

const data = topRepositories.slice(0, topRepositoriesLength);
const divider = '---------------------------------------------';
const title = `*:github: Top ${topRepositoriesLength} Teams Last 3 Days* :blob-clap:`;
const maxPointStringLength = `${Math.max(...data.map((item) => item.score))}`.length;

const repositories = data
.map(
(
{
teamName,
serverRepo: { html_url: server_html_url, name: server_name },
clientRepo: { html_url: client_html_url, name: client_name },
score,
details: { commentCount, pullRequestCount },
},
i,
) => {
const scoreString = `${score}`.padStart(maxPointStringLength, ' ');
const serverEmoji =
server_name[4] == '2' || server_name[4] == '3' || server_name[4] == '5' ? ':spring:' : ':django:';
let clientEmoji: string;
if (client_name[4] == '1') clientEmoji = ':apple_mac:';
else if (client_name[4] == '2' || client_name[4] == '3' || client_name[4] == '4') clientEmoji = ':android:';
else clientEmoji = ':react:';
return `${rankEmojis[i]} [${scoreString}p] *${teamName}* (${pullRequestCount} pull requests, ${commentCount} comments)\n\n\t\t${serverEmoji} <${server_html_url}|*${server_name}*>\t${clientEmoji} <${client_html_url}|*${client_name}*>`;
},
)
.join('\n\n');
await slackClient.sendMessage([divider, title, divider, repositories].join('\n'));
},
};
};

Expand Down
1 change: 1 addition & 0 deletions src/services/DashboardService.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export type DashboardService = {
sendGithubTopRepositoriesLastWeek: (organization: string) => Promise<void>;
sendGithubTopRepositoriesPerTeamLastThreeDays: (organization: string) => Promise<void>;
};
36 changes: 36 additions & 0 deletions src/toyproject-21.5-three-days-dashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import dotenv from 'dotenv';

import { implementDashboardService } from './infrastructures/implementDashboardService';
import { implementGithubApiRepository } from './infrastructures/implementGithubApiRepository';
import { implementGithubHttpClient } from './infrastructures/implementGithubHttpClient';
import { implementSlackHttpClient } from './infrastructures/implementSlackHttpClient';

dotenv.config({ path: '.env.local' });

const slackAuthToken = process.env.SLACK_AUTH_TOKEN;
const githubAccessToken = process.env.GHP_ACCESS_TOKEN;
const slackWeeklyChannelId = process.env.SLACK_WEEKLY_CHANNEL_ID;
const githubOrganization = process.env.GITHUB_ORGANIZATION;

if (!slackAuthToken) throw new Error('Missing Slack Auth Token');
if (!githubAccessToken) throw new Error('Missing Github Access Token');
if (!slackWeeklyChannelId) throw new Error('Missing Slack Weekly Channel ID');
if (!githubOrganization) throw new Error('Missing Github Organization');

/**
██████╗ ███████╗██████╗ ███████╗███╗ ██╗██████╗ ███████╗███╗ ██╗ ██████╗██╗███████╗███████╗
██╔══██╗██╔════╝██╔══██╗██╔════╝████╗ ██║██╔══██╗██╔════╝████╗ ██║██╔════╝██║██╔════╝██╔════╝
██║ ██║█████╗ ██████╔╝█████╗ ██╔██╗ ██║██║ ██║█████╗ ██╔██╗ ██║██║ ██║█████╗ ███████╗
██║ ██║██╔══╝ ██╔═══╝ ██╔══╝ ██║╚██╗██║██║ ██║██╔══╝ ██║╚██╗██║██║ ██║██╔══╝ ╚════██║
██████╔╝███████╗██║ ███████╗██║ ╚████║██████╔╝███████╗██║ ╚████║╚██████╗██║███████╗███████║
╚═════╝ ╚══════╝╚═╝ ╚══════╝╚═╝ ╚═══╝╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝╚═╝╚══════╝╚══════╝
*/
const slackClient = implementSlackHttpClient({
external: { slackAuthToken },
channelId: slackWeeklyChannelId,
});
const githubClient = implementGithubHttpClient({ githubAccessToken });
const githubApiRepository = implementGithubApiRepository({ githubClient });
const dashboardService = implementDashboardService({ githubApiRepository, slackClient });

dashboardService.sendGithubTopRepositoriesPerTeamLastThreeDays(githubOrganization).catch(console.error);

0 comments on commit ad7dfc5

Please sign in to comment.