Skip to content

Commit bea124e

Browse files
committed
Add Copilot instructions for development
Includes build/test/lint commands, architecture overview, and key conventions specific to this codebase.
1 parent 581176b commit bea124e

1 file changed

Lines changed: 139 additions & 0 deletions

File tree

.github/copilot-instructions.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Copilot Instructions for lcc-slack-bot
2+
3+
A Slack bot for automating show notes creation for _Les Cast Codeurs_ podcast. Built with Quarkus, the bot collects messages from Slack channels and publishes formatted show notes to GitHub.
4+
5+
## Build, Test, and Lint
6+
7+
### Prerequisites
8+
9+
- Java 17 (Eclipse Temurin)
10+
- Gradle (see `.tool-versions` for exact version)
11+
- Quarkus CLI (optional but recommended)
12+
13+
Use asdf to install dependencies: `asdf install`
14+
15+
### Build Commands
16+
17+
```bash
18+
# Development mode with live reload
19+
quarkus dev
20+
21+
# Production build
22+
quarkus build
23+
24+
# Or with Gradle
25+
gradle build
26+
27+
# Run the built application
28+
java -jar build/quarkus-app/quarkus-run.jar
29+
```
30+
31+
### Testing
32+
33+
```bash
34+
# Run all tests
35+
gradle test
36+
37+
# Run a single test class
38+
gradle test --tests com.lescastcodeurs.bot.ShowNotesTest
39+
40+
# Run a single test method
41+
gradle test --tests com.lescastcodeurs.bot.ShowNotesTest.testMethodName
42+
```
43+
44+
### Code Formatting
45+
46+
Code is automatically formatted during build using google-java-format (Google Java Style).
47+
48+
```bash
49+
# Manually format code
50+
gradle spotlessApply
51+
52+
# Check formatting (without auto-fixing)
53+
gradle spotlessCheck
54+
```
55+
56+
**Important**: Code is auto-formatted on local builds but only checked on CI. Install the google-java-format IDE plugin if available.
57+
58+
## Architecture Overview
59+
60+
### High-Level Flow
61+
62+
1. **Slack Integration**: Bot listens for mentions using Socket Mode (no webhook required)
63+
2. **Command Processing**: Commands are parsed via `SlackBotAction` enum which uses keyword matching
64+
3. **Show Notes Generation**: Slack threads are converted to show notes using Qute templates
65+
4. **GitHub Publishing**: Formatted markdown is committed to a GitHub repository
66+
67+
### Key Components
68+
69+
- **`SlackBotAction` (enum)**: Defines all bot commands with keywords, responses, and handlers. Commands are matched by normalizing input and checking keywords in `guessOrder` priority.
70+
- **`ShowNotes`**: Main domain model that aggregates `ShowNote` objects by category. Episode number is extracted from channel name using regex.
71+
- **`ShowNoteCategory` (enum)**: Categories mapped to custom Slack emoji reactions (e.g., `lcc_lang`, `lcc_lib`). Uses `INCLUDE`/`EXCLUDE` for inclusion/exclusion logic.
72+
- **`SlackThread`**: Represents a Slack message thread with reactions and replies. First message is the show note, replies are comments.
73+
- **`GitHubClient`**: Publishes show notes to GitHub repository using GitHub API.
74+
- **Qute Templates** (`src/main/resources/templates/`): Generate markdown from show notes data.
75+
76+
### Package Structure
77+
78+
```
79+
com.lescastcodeurs.bot/
80+
├── github/ # GitHub API integration
81+
├── slack/ # Slack API integration and message handling
82+
├── conferences/ # Conference data retrieval
83+
└── internal/ # Utility classes (StringUtils, etc.)
84+
```
85+
86+
### Show Note Processing Logic
87+
88+
- Threads are considered show notes if:
89+
- First message is from a user (not a bot)
90+
- Has a categorization reaction OR contains a link with no mentions
91+
- Not explicitly excluded with `:lcc_exclude:` reaction
92+
- Replies are included if:
93+
- Written by a user (not a bot)
94+
- No `:lcc_exclude:` reaction
95+
- Has `:lcc_include:` reaction OR contains no mentions
96+
- Ordering: Custom reactions `:lcc_1:` through `:lcc_9:` control sort order, otherwise chronological
97+
98+
## Key Conventions
99+
100+
### Enum-Driven Command Pattern
101+
102+
Commands are defined as enum values in `SlackBotAction`. Each action has:
103+
- `keywords`: List of normalized keywords to match
104+
- `response`: Default response message
105+
- `handlerAddress`: Optional Vert.x event bus address for async processing
106+
- `canReplyTo()`: Override for custom matching logic
107+
108+
New commands: Add a new enum value with appropriate `guessOrder` (determines evaluation priority).
109+
110+
### Reaction-Based Categorization
111+
112+
Categories use custom Slack emojis (all prefixed `lcc_`):
113+
- Category reactions: `lcc_lang`, `lcc_lib`, `lcc_infra`, etc.
114+
- Special reactions: `lcc_include`, `lcc_exclude` (inclusion/exclusion)
115+
- Ordering reactions: `lcc_1` through `lcc_9`
116+
117+
The last reaction added wins (except `:lcc_exclude:` which is always prioritized).
118+
119+
### Configuration via Environment Variables
120+
121+
Runtime configuration uses environment variables (not `application.properties`):
122+
- `SLACK_BOT_TOKEN`, `SLACK_APP_TOKEN`: Slack credentials
123+
- `GITHUB_TOKEN`, `GITHUB_REPOSITORY`: GitHub publishing
124+
- `CONFERENCES_JSON_URL`, `CONFERENCES_SELECTION_CRITERIA`: Conference list filtering
125+
- `LCC_RECORD_DATE_CRITERION`: String to identify record date messages
126+
127+
Default values in `application.properties` are for local development only.
128+
129+
### Quarkus Dependency Injection
130+
131+
Uses Quarkus CDI (`@ApplicationScoped`, `@Inject`). Avoid manual instantiation of services; let the container manage lifecycle.
132+
133+
### Vert.x Event Bus for Async Processing
134+
135+
Commands requiring heavy processing (e.g., `GENERATE_SHOW_NOTES`) publish events to Vert.x event bus addresses. Handlers are registered with `@ConsumeEvent`.
136+
137+
## Publishing
138+
139+
Releases are triggered by creating a GitHub release with tag `x.y.z`. The `publish.yml` workflow publishes to GitHub Packages (Maven repository). Update `CHANGELOG.md` before creating the release.

0 commit comments

Comments
 (0)