Skip to content

Commit fb0f221

Browse files
committed
Initial release: Top-tier GitHub issue management bot
0 parents  commit fb0f221

11 files changed

Lines changed: 4076 additions & 0 deletions

File tree

.github/workflows/anti-hoarder.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: "Anti-Hoarder Stale Check"
2+
on:
3+
schedule:
4+
- cron: '0 0 * * *' # Runs every day at midnight UTC
5+
workflow_dispatch: # Allows manual trigger from the Actions tab
6+
7+
jobs:
8+
stale-check:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
issues: write
12+
steps:
13+
- name: Unassign stale issues
14+
uses: actions/github-script@v7
15+
with:
16+
script: |
17+
const daysToStale = 14; // Number of days before unassigning
18+
const msInDay = 24 * 60 * 60 * 1000;
19+
const thresholdDate = new Date(Date.now() - (daysToStale * msInDay));
20+
21+
// Find open issues with the 'in-progress' label
22+
const { data: issues } = await github.rest.issues.listForRepo({
23+
owner: context.repo.owner,
24+
repo: context.repo.repo,
25+
state: 'open',
26+
labels: 'in-progress'
27+
});
28+
29+
for (const issue of issues) {
30+
const updatedAt = new Date(issue.updated_at);
31+
if (updatedAt < thresholdDate && issue.assignees.length > 0) {
32+
// Issue is stale! Unassign everyone
33+
const assignees = issue.assignees.map(a => a.login);
34+
35+
await github.rest.issues.removeAssignees({
36+
owner: context.repo.owner,
37+
repo: context.repo.repo,
38+
issue_number: issue.number,
39+
assignees: assignees
40+
});
41+
42+
try {
43+
await github.rest.issues.removeLabel({
44+
owner: context.repo.owner,
45+
repo: context.repo.repo,
46+
issue_number: issue.number,
47+
name: 'in-progress'
48+
});
49+
} catch (e) {
50+
// Ignore if label doesn't exist
51+
}
52+
53+
await github.rest.issues.addLabels({
54+
owner: context.repo.owner,
55+
repo: context.repo.repo,
56+
issue_number: issue.number,
57+
labels: ['help wanted']
58+
});
59+
60+
await github.rest.issues.createComment({
61+
owner: context.repo.owner,
62+
repo: context.repo.repo,
63+
issue_number: issue.number,
64+
body: `🚨 This issue has been inactive for over ${daysToStale} days. I am automatically unassigning the current assignees so someone else can pick this up. If you are still working on this, feel free to \`/claim\` it again!`
65+
});
66+
}
67+
}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
.env
3+
*.log

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Orbit-btw-bot
2+
3+
A top-tier GitHub App built with [Probot](https://github.com/probot/probot) that beautifully automates and manages issues for the `Orbit-btw` organization.
4+
5+
## Features & Automation
6+
- **Single Issue Limit:** Prevents contributors from hoarding tasks. A user can only claim 1 open issue at a time per repository.
7+
- **Auto-Labeling:** Automatically adds `in-progress` and removes `help wanted` labels when an issue is claimed.
8+
- **Smart Reactions:** Reduces comment spam by reacting to commands with emojis (🚀, 👀, ❤️) instead of posting new comments.
9+
- **Welcome Wagon:** Greets first-time issue creators and commenters to the organization.
10+
11+
## Available Commands
12+
13+
| Command | Description | Access Level |
14+
|---------|-------------|--------------|
15+
| `/claim` or `/assign` | Claims the issue. Fails if you already have an active issue. Adds labels and reacts with 🚀 | Anyone |
16+
| `/unclaim` or `/unassign` | Drops your claim on the issue. Reverts labels to `help wanted`. | Assignees |
17+
| `/close` | Instantly closes the issue. | Org Members |
18+
| `/label <name>` | Quickly adds a specific label to the issue (e.g. `/label bug`). | Org Members |
19+
| `/unlabel <name>`| Quickly removes a specific label from the issue. | Org Members |
20+
21+
## Setup & Deployment
22+
See [SETUP.md](./SETUP.md) for instructions on how to configure, run, and host this bot 24/7.

SETUP.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Orbit-btw-bot Setup Guide
2+
3+
Follow these concise steps to set up, register, and run your GitHub App.
4+
5+
## 1. Setup Local Webhook Proxy (Smee)
6+
GitHub needs a public URL to send events to your local machine.
7+
1. Go to [https://smee.io/](https://smee.io/) and click **"Start a new channel"**.
8+
2. Copy the **Webhook Proxy URL** (e.g., `https://smee.io/AbCdEfG...`).
9+
3. In your `orbit-bot` folder, ensure your `.env` file contains:
10+
```env
11+
WEBHOOK_PROXY_URL=https://smee.io/your_channel_id
12+
```
13+
14+
## 2. Auto-Register the App (Recommended)
15+
Probot can automatically create the App in GitHub and download its keys.
16+
1. Open your terminal in the `orbit-bot` folder and run `npm run dev`.
17+
2. Open [http://localhost:3000](http://localhost:3000) in your web browser.
18+
3. Click **"Register GitHub App"**.
19+
4. Select the **Orbit-btw** organization.
20+
5. GitHub will redirect you back, and automatically populate your `.env` file with your `APP_ID`, `PRIVATE_KEY`, and `WEBHOOK_SECRET`.
21+
22+
*(If this works, skip to Step 4!)*
23+
24+
---
25+
26+
## 3. Manual Registration (Only if Auto-Register Fails)
27+
If the button fails, you must create the App on GitHub manually.
28+
1. Go to **GitHub -> Orbit-btw (Org) -> Settings -> Developer Settings -> GitHub Apps -> New GitHub App**.
29+
2. **App Name**: `orbit-btw-bot` (must be unique).
30+
3. **Homepage URL**: `https://github.com/Orbit-btw`
31+
4. **Webhook URL**: Paste your Smee proxy URL here.
32+
5. **Webhook Secret**: Create a random password (e.g., `my_secret_123`).
33+
6. **Permissions**:
34+
- Set **Issues** to `Read & write`.
35+
- Set **Pull requests** to `Read & write`.
36+
7. **Subscribe to events**:
37+
- Check the boxes for `Issues`, `Issue comment`, and `Pull request`.
38+
8. Click **Create GitHub App**.
39+
9. On the next page, click **Generate a private key**. A `.pem` file will download to your computer.
40+
10. Update your `.env` file manually:
41+
```env
42+
WEBHOOK_PROXY_URL=https://smee.io/your_channel_id
43+
APP_ID=123456 (Find this on the GitHub App page)
44+
WEBHOOK_SECRET=my_secret_123
45+
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nYourKeyHere\n-----END RSA PRIVATE KEY-----"
46+
```
47+
48+
## 4. Run and Test Locally
49+
1. Restart your server: Press `Ctrl + C` in the terminal, then run `npm run dev` again.
50+
2. Go to any issue in your GitHub repositories.
51+
3. Comment `/claim` or `/assign` on the issue.
52+
4. Your bot will automatically assign the issue to you!
53+
54+
## 5. Deployment (Production)
55+
Once you are ready to run the bot 24/7 without keeping your computer on:
56+
1. Push this repository to GitHub.
57+
2. Connect the repository to a hosting provider like [Render](https://render.com/).
58+
3. Set the start command to `npm start`.
59+
4. Add the following **Environment Variables** to your hosting provider (copy values from your local `.env` file):
60+
- `APP_ID`
61+
- `WEBHOOK_SECRET`
62+
- `PRIVATE_KEY` (Include the entire `-----BEGIN...` block)
63+
*(Note: You do NOT need the `WEBHOOK_PROXY_URL` variable in production)*
64+
5. **Crucial Final Step:** Once deployed, go back to your **GitHub App Settings**. Change the **Webhook URL** from your `smee.io` link to your new live URL appended with `/api/github/webhooks`.
65+
- Example: `https://your-app-name.onrender.com/api/github/webhooks`

app.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name: orbit-btw-bot
2+
description: "A GitHub App to manage issues via comments"
3+
url: "https://github.com/Orbit-btw"
4+
public: false
5+
default_permissions:
6+
issues: write
7+
pull_requests: write
8+
default_events:
9+
- issue_comment
10+
- issues
11+
- pull_request

index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* @param {import('probot').Probot} app
3+
*/
4+
module.exports = (app) => {
5+
app.log.info("Orbit-btw-bot was loaded!");
6+
7+
// Load modules
8+
require('./src/welcome')(app);
9+
require('./src/commands')(app);
10+
};

0 commit comments

Comments
 (0)