Skip to content

Commit 2ced461

Browse files
authored
Merge pull request #1 from cs-internship/feature/add-CICD
Feature/add cicd
2 parents 276af51 + db2b4c3 commit 2ced461

36 files changed

+10992
-3376
lines changed

.github/workflows/ci.yml

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
- feature/*
9+
pull_request:
10+
branches:
11+
- main
12+
- master
13+
14+
jobs:
15+
test:
16+
name: 🧪 Run Tests and Coverage
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
23+
- name: Setup Node.js 18
24+
uses: actions/setup-node@v4
25+
with:
26+
node-version: 18
27+
cache: 'npm'
28+
29+
- name: Install dependencies
30+
run: npm ci
31+
32+
- name: Run tests
33+
run: npm test --silent
34+
35+
- name: Check whether running under act (set output)
36+
id: check_act_test
37+
run: |
38+
if [ "${IS_ACT}" = "true" ]; then
39+
echo "is_act=true" >> $GITHUB_OUTPUT
40+
else
41+
echo "is_act=false" >> $GITHUB_OUTPUT
42+
fi
43+
44+
- name: Upload coverage report
45+
if: ${{ always() && steps.check_act_test.outputs.is_act != 'true' }}
46+
uses: actions/upload-artifact@v4
47+
with:
48+
name: jest-coverage
49+
path: coverage/
50+
51+
- name: Generate test summary
52+
if: always()
53+
run: |
54+
echo "### ✅ Test Results" >> $GITHUB_STEP_SUMMARY
55+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
56+
npm test --silent >> $GITHUB_STEP_SUMMARY || true
57+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
58+
59+
release:
60+
name: 🚀 Version & Release
61+
runs-on: ubuntu-latest
62+
needs: test
63+
64+
steps:
65+
- name: Checkout repository
66+
uses: actions/checkout@v4
67+
with:
68+
fetch-depth: 0
69+
70+
- name: Check whether running under act (set output)
71+
id: check_act_release
72+
run: |
73+
if [ "${IS_ACT}" = "true" ]; then
74+
echo "is_act=true" >> $GITHUB_OUTPUT
75+
else
76+
echo "is_act=false" >> $GITHUB_OUTPUT
77+
fi
78+
79+
- name: Setup Node.js
80+
if: ${{ steps.check_act_release.outputs.is_act != 'true' }}
81+
uses: actions/setup-node@v4
82+
with:
83+
node-version: 18
84+
cache: 'npm'
85+
86+
- name: Install dependencies
87+
if: ${{ steps.check_act_release.outputs.is_act != 'true' }}
88+
run: npm ci
89+
90+
- name: Semantic Release
91+
if: ${{ steps.check_act_release.outputs.is_act != 'true' }}
92+
uses: cycjimmy/semantic-release-action@v4
93+
with:
94+
extra_plugins: |
95+
@semantic-release/changelog
96+
@semantic-release/git
97+
@semantic-release/github
98+
env:
99+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
100+
101+
deploy:
102+
name: 📦 Deploy to Render
103+
runs-on: ubuntu-latest
104+
needs: release
105+
106+
steps:
107+
- name: Checkout repository
108+
uses: actions/checkout@v4
109+
with:
110+
fetch-depth: 0
111+
112+
- name: Check whether running under act (set output)
113+
id: check_act_deploy
114+
run: |
115+
if [ "${IS_ACT}" = "true" ]; then
116+
echo "is_act=true" >> $GITHUB_OUTPUT
117+
else
118+
echo "is_act=false" >> $GITHUB_OUTPUT
119+
fi
120+
121+
- name: Setup Node.js
122+
if: ${{ steps.check_act_deploy.outputs.is_act != 'true' }}
123+
uses: actions/setup-node@v4
124+
with:
125+
node-version: 18
126+
cache: 'npm'
127+
128+
- name: Install dependencies
129+
if: ${{ steps.check_act_deploy.outputs.is_act != 'true' }}
130+
run: npm ci
131+
132+
- name: Deploy to Render
133+
if: ${{ steps.check_act_deploy.outputs.is_act != 'true' }}
134+
env:
135+
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
136+
RENDER_SERVICE_ID: ${{ secrets.RENDER_SERVICE_ID }}
137+
run: |
138+
curl -X POST "https://api.render.com/v1/services/${RENDER_SERVICE_ID}/deploys" \
139+
-H "Accept: application/json" \
140+
-H "Authorization: Bearer ${RENDER_API_KEY}" \
141+
-d ''
142+
143+
- name: Send Telegram notification
144+
if: ${{ always() && steps.check_act_deploy.outputs.is_act != 'true' }}
145+
run: |
146+
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || git rev-parse --short HEAD)
147+
BRANCH=$(git rev-parse --abbrev-ref HEAD)
148+
COMMIT=$(git rev-parse --short HEAD)
149+
REPO_URL="https://github.com/$GITHUB_REPOSITORY"
150+
LAST_AUTHOR=$(git log -1 --pretty=format:'%an')
151+
LAST_COMMIT_MSG=$(git log -1 --pretty=format:'%s')
152+
153+
MESSAGE="✅ Deployment completed successfully on Render!
154+
🕓 $(date)
155+
🏷️ Version/Tag: $VERSION
156+
🌿 Branch: $BRANCH
157+
🔀 Commit: $COMMIT
158+
👤 Last Commit Author: $LAST_AUTHOR
159+
💬 Last Commit Msg: $LAST_COMMIT_MSG
160+
🔗 Repo: $REPO_URL"
161+
162+
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
163+
-d "chat_id=${{ secrets.TELEGRAM_CHAT_ID }}" \
164+
-d "text=$MESSAGE" \
165+
-d "parse_mode=Markdown"
166+

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ yarn-debug.log*
2323
yarn-error.log*
2424

2525
.env
26+
.env.act
2627
initial-users.js
2728
node_modules

.releaserc.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"branches": ["main"],
3+
"plugins": [
4+
["@semantic-release/commit-analyzer"],
5+
["@semantic-release/release-notes-generator"],
6+
["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" }],
7+
["@semantic-release/github"],
8+
[
9+
"@semantic-release/git",
10+
{
11+
"assets": ["package.json", "CHANGELOG.md"],
12+
"message": "🔖 release(version): ${nextRelease.version}\n\n${nextRelease.notes}"
13+
}
14+
]
15+
]
16+
}

README.md

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,39 @@
11
# CS-Queue-Bot
22

3+
![CI/CD](https://github.com/cs-internship/CS-Queue-Bot/actions/workflows/ci.yml/badge.svg)
4+
35
An automated Telegram bot designed to manage the CS Internship Program queue group. It streamlines onboarding, prevents spam, simplifies admin tasks, and integrates seamlessly with Azure DevOps to track candidates and manage group operations efficiently.
46

57
![photo_2025-08-05_00-41-50](https://github.com/user-attachments/assets/abba91a6-9b22-42ab-b5c9-1718fbe7ae20)
68

7-
89
## Project Overview
910

1011
**CS-Queue-Bot** is a Node.js-based Telegram bot built to streamline the management of the CS Internship Program's queue group. It automates new member onboarding, enforces anti-spam measures, provides admin tools, and integrates with Azure DevOps to efficiently track candidate progress and activity.
1112

1213
## Features
1314

14-
- **Automated Onboarding:** Welcomes new members, checks for required usernames, and guides them through the process.
15-
- **Spam Protection:** Detects and blocks users who send excessive messages in a short period.
16-
- **Admin Commands:** Includes commands for version checking, user management (ban/unban), and adding users to the Azure DevOps queue.
17-
- **Azure DevOps Integration:** Automatically creates and links work items for new users in Azure DevOps.
18-
- **Error Handling & Logging:** Notifies admins of errors and provides links to logs for debugging.
19-
- **Express Health Check:** Exposes a simple HTTP endpoint for deployment health monitoring.
15+
- **Automated Onboarding:** Welcomes new members, checks for required usernames, and guides them through the process.
16+
- **Spam Protection:** Detects and blocks users who send excessive messages in a short period.
17+
- **Admin Commands:** Includes commands for version checking, user management (ban/unban), and adding users to the Azure DevOps queue.
18+
- **Azure DevOps Integration:** Automatically creates and links work items for new users in Azure DevOps.
19+
- **Error Handling & Logging:** Notifies admins of errors and provides links to logs for debugging.
20+
- **Express Health Check:** Exposes a simple HTTP endpoint for deployment health monitoring.
2021

2122
## Technologies Used
2223

23-
- **Node.js** — JavaScript runtime for server-side logic
24-
- **Telegraf** — Modern Telegram Bot Framework for Node.js
25-
- **Express** — Lightweight web server for health checks and deployment
26-
- **Axios** — Promise-based HTTP client for API requests (Azure DevOps)
27-
- **dotenv** — Loads environment variables from `.env` files
28-
- **Azure DevOps REST API** — For work item and candidate management
24+
- **Node.js** — JavaScript runtime for server-side logic
25+
- **Telegraf** — Modern Telegram Bot Framework for Node.js
26+
- **Express** — Lightweight web server for health checks and deployment
27+
- **Axios** — Promise-based HTTP client for API requests (Azure DevOps)
28+
- **dotenv** — Loads environment variables from `.env` files
29+
- **Azure DevOps REST API** — For work item and candidate management
2930

3031
## Installation Instructions
3132

3233
### Prerequisites
3334

34-
- Node.js (v16 or higher recommended)
35-
- npm (Node package manager)
35+
- Node.js (v16 or higher recommended)
36+
- npm (Node package manager)
3637

3738
### Steps
3839

@@ -65,12 +66,11 @@ Create a `.env` file in the `bot/` directory with the following variables:
6566

6667
**Other configuration values** (set in `config.js`):
6768

68-
- `GROUP_ID`: Main group chat ID
69-
- `ORGANIZATION`: Azure DevOps organization name
70-
- `PROJECT`: Azure DevOps project name
71-
- `PARENT_ID`, `WORKITEM_ID`: Work item IDs for Azure DevOps integration
72-
- `SPAM_THRESHOLD`, `SPAM_TIME_WINDOW`: Anti-spam settings
73-
69+
- `GROUP_ID`: Main group chat ID
70+
- `ORGANIZATION`: Azure DevOps organization name
71+
- `PROJECT`: Azure DevOps project name
72+
- `PARENT_ID`, `WORKITEM_ID`: Work item IDs for Azure DevOps integration
73+
- `SPAM_THRESHOLD`, `SPAM_TIME_WINDOW`: Anti-spam settings
7474

7575
## Bot Commands
7676

@@ -86,14 +86,14 @@ Below is a complete list of available bot commands, with details on their usage
8686

8787
**Other Bot Behaviors:**
8888

89-
- **Spam Protection:** If a user sends too many messages in a short time, they are automatically blocked and notified. Admins are alerted with an option to unblock.
90-
- **New Member Onboarding:** When a new user joins, the bot:
91-
- Welcomes them
92-
- Checks for a username
93-
- Guides them to set a username if missing
94-
- Registers them in Azure DevOps if eligible
95-
- **Unban via Inline Button:** Admins can unblock users via an inline button in the admin group.
96-
- **Error Handling:** All errors are reported to the admin group with details and log links.
89+
- **Spam Protection:** If a user sends too many messages in a short time, they are automatically blocked and notified. Admins are alerted with an option to unblock.
90+
- **New Member Onboarding:** When a new user joins, the bot:
91+
- Welcomes them
92+
- Checks for a username
93+
- Guides them to set a username if missing
94+
- Registers them in Azure DevOps if eligible
95+
- **Unban via Inline Button:** Admins can unblock users via an inline button in the admin group.
96+
- **Error Handling:** All errors are reported to the admin group with details and log links.
9797

9898
## Folder/File Structure
9999

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
jest.resetModules();
2+
3+
test("requiring bot index does not crash when Telegraf is mocked", () => {
4+
const mockUse = jest.fn();
5+
const mockOn = jest.fn();
6+
const mockCatch = jest.fn();
7+
const mockCommand = jest.fn();
8+
const mockLaunch = jest.fn();
9+
const mockStop = jest.fn();
10+
const mockTelegram = { sendMessage: jest.fn(), callApi: jest.fn() };
11+
12+
const MockTelegraf = function () {
13+
return {
14+
use: mockUse,
15+
start: mockOn,
16+
on: mockOn,
17+
catch: mockCatch,
18+
command: mockCommand,
19+
launch: mockLaunch,
20+
stop: mockStop,
21+
telegram: mockTelegram,
22+
};
23+
};
24+
25+
jest.doMock("telegraf", () => ({ Telegraf: MockTelegraf }));
26+
// mock the same module id that index.js requires
27+
jest.doMock("../../bot/config/config", () => ({
28+
TELEGRAM_BOT_TOKEN: "x",
29+
PORT: 3000,
30+
}));
31+
// avoid starting an express server or scheduling jobs
32+
jest.doMock("../../bot/server", () => ({ startServer: jest.fn() }));
33+
jest.doMock("../../bot/utils/scheduleMessage", () => ({
34+
scheduleAdminMessage: jest.fn(),
35+
}));
36+
jest.doMock("../../bot/commands/registerCommands", () => jest.fn());
37+
38+
// require the bot module directly to avoid executing the top-level launcher in index.js
39+
const mod = require("../../bot");
40+
expect(mod.bot).toBeDefined();
41+
});

0 commit comments

Comments
 (0)