Skip to content

Commit e0dd32a

Browse files
Improve the aganets.md
1 parent ce1655a commit e0dd32a

File tree

2 files changed

+98
-68
lines changed

2 files changed

+98
-68
lines changed

.claude/settings.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
{
22
"permissions": {
33
"allow": [
4+
"Bash(./mvnw:*)",
5+
"Bash(./scripts/check_dependency_updates.sh:*)",
6+
"Bash(./scripts/install_local.sh:*)",
7+
"Bash(./scripts/run_all_bolt_tests.sh:*)",
8+
"Bash(./scripts/run_all_client_tests.sh:*)",
9+
"Bash(./scripts/run_no_prep_tests.sh:*)",
10+
"Bash(./scripts/set_version.sh:*)",
411
"Bash(gh issue view:*)",
512
"Bash(gh label list:*)",
613
"Bash(gh pr checks:*)",
@@ -18,9 +25,9 @@
1825
"Bash(grep:*)",
1926
"Bash(ls:*)",
2027
"Bash(tree:*)",
21-
"WebFetch(domain:github.com)",
28+
"WebFetch(domain:central.sonatype.com)",
2229
"WebFetch(domain:docs.slack.dev)",
23-
"WebFetch(domain:central.sonatype.com)"
30+
"WebFetch(domain:github.com)"
2431
]
2532
}
2633
}

AGENTS.md

Lines changed: 89 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ There are two main components:
1212
## Build System
1313

1414
- **Build tool**: Apache Maven via Maven Wrapper (`./mvnw`)
15-
- **Java target**: Source and target compatibility is Java 1.8 (OpenJDK 8+)
16-
- **Group ID**: `com.slack.api`
17-
- **Current version**: Check `<version>` in root `pom.xml`
15+
- **Java target**: Source and target compatibility is Java 1.8 (OpenJDK 8+) — see `pom.xml` properties `maven.compiler.source` and `maven.compiler.target`
16+
- **Group ID**: `com.slack.api` — see `pom.xml` `<groupId>`
17+
- **Current version**: See `<version>` in root `pom.xml` (also reflected in `*LibraryVersion.java` files generated by `scripts/set_version.sh`)
1818

1919
### Key Commands
2020

@@ -50,7 +50,7 @@ Some modules are excluded on JDK 8 (Jakarta EE modules, GCF, Helidon, http4k, Mi
5050

5151
## Module Architecture
5252

53-
All published modules use group ID `com.slack.api` and are released to Maven Central simultaneously.
53+
All published modules use group ID `com.slack.api` (see `pom.xml` `<groupId>`) and are released to Maven Central simultaneously. The complete list of modules is defined in root `pom.xml` `<modules>` section.
5454

5555
### Foundation Modules
5656

@@ -131,39 +131,43 @@ All published modules use group ID `com.slack.api` and are released to Maven Cen
131131

132132
## Key Dependencies
133133

134-
| Library | Version Property | Notes |
135-
|---------|-----------------|-------|
136-
| OkHttp | `okhttp.version` (4.x) | HTTP client |
134+
All dependency versions are managed in root `pom.xml` `<properties>` section.
135+
136+
| Library | Version Property | Notes |
137+
|---------|------------------|-------|
138+
| OkHttp | `okhttp.version` | HTTP client |
137139
| Gson | `gson.version` | JSON serialization; uses `LOWER_CASE_WITH_UNDERSCORES` field naming via `GsonFactory.createSnakeCase()` |
138-
| SLF4J | `slf4j.version` (1.7.x) | Logging facade. **Do not upgrade to v2** - see issue #1034 |
140+
| SLF4J | `slf4j.version` | Logging facade. **Do not upgrade to v2** - see issue #1034 |
139141
| Lombok | `lombok.version` | Used extensively for `@Data`, `@Builder`, `@Slf4j` |
140-
| Kotlin | `kotlin.version` (1.9.x) | API/language version pinned to 1.6 for backward compat |
141-
| JUnit | `junit.version` (4.x) | **JUnit 4, not 5** |
142-
| Mockito | `mockito-core.version` (<5.0) | Capped below v5 for Java 8 compatibility |
142+
| Kotlin | `kotlin.version` | Compiler version is 1.9.x; `apiVersion` and `languageVersion` pinned to 1.6 for backward compat |
143+
| JUnit | `junit.version` | **JUnit 4, not 5** |
144+
| Mockito | `mockito-core.version` | Capped below v5 for Java 8 compatibility |
143145
| Hamcrest | `hamcrest.version` | Used for test assertions |
144146

147+
**Note**: Always check `pom.xml` `<properties>` for actual current versions.
148+
145149
## Code Conventions
146150

147151
### Java Style
148152

149-
- **Java 8 compatibility is mandatory**. Do not use Java 9+ APIs (e.g., `List.of()`, `Map.of()`, `var`, `HttpClient`, text blocks).
153+
- **Java 8 compatibility is mandatory** (see `pom.xml` `maven.compiler.source` and `maven.compiler.target` = 1.8). Do not use Java 9+ APIs (e.g., `List.of()`, `Map.of()`, `var`, `HttpClient`, text blocks).
150154
- Lombok annotations are used pervasively: `@Data`, `@Builder`, `@Slf4j`, `@EqualsAndHashCode(callSuper = false)`.
151-
- JSON field naming uses **snake_case** via Gson's `LOWER_CASE_WITH_UNDERSCORES` policy. Java fields are camelCase.
155+
- JSON field naming uses **snake_case** via Gson's `LOWER_CASE_WITH_UNDERSCORES` policy (see `slack-api-client/src/main/java/com/slack/api/util/json/GsonFactory.java`). Java fields are camelCase.
152156
- Logging uses SLF4J via Lombok's `@Slf4j` (gives you a `log` field).
153157
- Checked exceptions: API methods throw `IOException` and `SlackApiException`.
154158

155159
### Naming Conventions
156160

157-
- Request classes: `{MethodName}Request` with `@Data @Builder` and implementing `SlackApiRequest`
158-
- Response classes: `{MethodName}Response` with `@Data` and implementing `SlackApiTextResponse`
159-
- API method constants: `Methods.java` has `public static final String` for each API method (e.g., `USERS_INFO = "users.info"`)
161+
- Request classes: `{MethodName}Request` with `@Data @Builder` and implementing `SlackApiRequest` (see `slack-api-client/src/main/java/com/slack/api/methods/SlackApiRequest.java`)
162+
- Response classes: `{MethodName}Response` with `@Data` and implementing `SlackApiTextResponse` (see `slack-api-client/src/main/java/com/slack/api/methods/SlackApiTextResponse.java`)
163+
- API method constants: `Methods.java` has `public static final String` for each API method (e.g., `USERS_INFO = "users.info"`) — see `slack-api-client/src/main/java/com/slack/api/methods/Methods.java`
160164
- Test packages: `test_locally` for CI-safe tests, `test_with_remote_apis` for integration tests needing tokens
161165

162166
### JSON Serialization
163167

164-
- Use `GsonFactory.createSnakeCase()` for most Slack APIs (snake_case JSON keys)
168+
- Use `GsonFactory.createSnakeCase()` for most Slack APIs (snake_case JSON keys with `LOWER_CASE_WITH_UNDERSCORES` policy)
165169
- Use `GsonFactory.createCamelCase()` for SCIM APIs
166-
- The factory is in `slack-api-client/src/main/java/com/slack/api/util/json/GsonFactory.java`
170+
- The factory implementation is in `slack-api-client/src/main/java/com/slack/api/util/json/GsonFactory.java`
167171

168172
## Model Types (`slack-api-model`)
169173

@@ -219,7 +223,7 @@ public class ChannelCreatedEvent implements Event {
219223

220224
- Use `@Data`, `@Builder`, `@NoArgsConstructor`, `@AllArgsConstructor`, `@EqualsAndHashCode(callSuper = false)` on concrete types.
221225
- Define `public static final String TYPE` (or `TYPE_NAME`) and `private final String type = TYPE;`.
222-
- Java fields are camelCase; Gson's `LOWER_CASE_WITH_UNDERSCORES` policy maps them to snake_case JSON automatically.
226+
- Java fields are camelCase; Gson's `LOWER_CASE_WITH_UNDERSCORES` policy (see `GsonFactory.java`) maps them to snake_case JSON automatically.
223227
- Use `@SerializedName` only when the Slack API field name does not follow snake_case convention.
224228
- Do **not** initialize `List` fields to empty collections — Slack sometimes returns errors with empty arrays, and null vs empty has semantic meaning.
225229

@@ -299,41 +303,13 @@ public class ConversationsRequestSharedInviteApproveRequest implements SlackApiR
299303
}
300304
```
301305

302-
A simpler request class (for `conversations.requestSharedInvite.deny`):
303-
304-
```java
305-
package com.slack.api.methods.request.conversations.request_shared_invite;
306-
307-
import com.slack.api.methods.SlackApiRequest;
308-
import lombok.Builder;
309-
import lombok.Data;
310-
311-
/**
312-
* https://docs.slack.dev/reference/methods/conversations.requestSharedInvite.deny
313-
*/
314-
@Data
315-
@Builder
316-
public class ConversationsRequestSharedInviteDenyRequest implements SlackApiRequest {
317-
318-
private String token;
319-
320-
/**
321-
* ID of the requested shared channel invite to deny.
322-
*/
323-
private String inviteId;
324-
325-
/**
326-
* Optional message explaining why the request to invite was denied.
327-
*/
328-
private String message;
329-
}
330-
```
306+
For simpler methods without nested objects, the same pattern applies but without the inner `@Data` classes (e.g., `ConversationsRequestSharedInviteDenyRequest` has only `token`, `inviteId`, and `message` fields).
331307

332308
### 4. Create the Response class
333309

334310
File: `slack-api-client/src/main/java/com/slack/api/methods/response/conversations/request_shared_invite/ConversationsRequestSharedInviteApproveResponse.java`
335311

336-
The response class implements `SlackApiTextResponse` and uses `@Data`. Every response must include the standard fields (`ok`, `warning`, `error`, `needed`, `provided`, `httpResponseHeaders`). Add any method-specific response fields from the API docs:
312+
The response class implements `SlackApiTextResponse` and uses `@Data`. Every response must include the standard fields defined by the `SlackApiTextResponse` interface (`ok`, `warning`, `error`, `needed`, `provided`, `httpResponseHeaders`). Add any method-specific response fields from the API docs:
337313

338314
```java
339315
package com.slack.api.methods.response.conversations.request_shared_invite;
@@ -463,7 +439,7 @@ public static FormBody.Builder toForm(ConversationsRequestSharedInviteDenyReques
463439

464440
File: `slack-api-client/src/main/java/com/slack/api/methods/MethodsRateLimits.java`
465441

466-
Look up the rate limit tier from the API docs and add a `setRateLimitTier` call in the appropriate alphabetical position:
442+
Look up the rate limit tier from the API docs (or check `metadata/web-api/rate_limit_tiers.json` for existing patterns) and add a `setRateLimitTier` call in the appropriate alphabetical position:
467443

468444
```java
469445
setRateLimitTier(CONVERSATIONS_REQUEST_SHARED_INVITE_APPROVE, Tier2);
@@ -474,18 +450,36 @@ setRateLimitTier(CONVERSATIONS_REQUEST_SHARED_INVITE_DENY, Tier2);
474450

475451
File: `metadata/web-api/rate_limit_tiers.json`
476452

477-
Add the method name and its tier in alphabetical order within the JSON object:
453+
Add the method name and its tier in alphabetical order within the JSON object. This file is the source of truth for rate limit tiers and should match the tier set in `MethodsRateLimits.java`:
478454

479455
```json
480456
"conversations.requestSharedInvite.approve": "Tier2",
481457
"conversations.requestSharedInvite.deny": "Tier2",
482458
```
483459

484-
### 12. Add tests and update `MethodsTest`
460+
### 12. Check mock server JSON fixture
461+
462+
File (new): `json-logs/samples/api/{method.name}.json`
463+
464+
The `MockSlackApiServer` used in tests serves mock responses from JSON files in this directory. Every API method **must** have a corresponding JSON fixture file, or tests will fail with `NoSuchFileException` / HTTP 500. The file name is the full API method name with dots (e.g., `conversations.requestSharedInvite.approve.json`).
465+
466+
The mock server reads these files and replaces `"ok": false,` with `"ok": true,` automatically, so the fixture should always have `"ok": false`. See existing files in this directory for examples:
467+
468+
```json
469+
{
470+
"ok": false,
471+
"error": "",
472+
"needed": "",
473+
"provided": "",
474+
"warning": ""
475+
}
476+
```
477+
478+
### 13. Add tests and update `MethodsTest`
485479

486480
#### Add method-specific tests
487481

488-
File: `slack-api-client/src/test/java/test_locally/api/methods/ConversationsTest.java` (or the relevant existing test file for the API category)
482+
File: `slack-api-client/src/test/java/test_locally/api/methods/{Category}Test.java` (the test file matching the top-level API namespace, e.g., `AppsTest.java` for `apps.*`, `ConversationsTest.java` for `conversations.*`)
489483

490484
Test both sync and async variants using the configurator lambda pattern:
491485

@@ -507,25 +501,54 @@ public void conversationsRequestSharedInviteApprove_async() throws Exception {
507501

508502
File: `slack-api-client/src/test/java/test_locally/api/MethodsTest.java`
509503

510-
This test validates that every known Slack API method has a corresponding `Methods.java` constant and rate limit entry. Update the `methods` string and the endpoint count comment to include the new method names. If the method names are not already in the list, add them in the correct alphabetical position.
504+
This test validates that every known Slack API method has a corresponding constant in `Methods.java` and rate limit entry in `metadata/web-api/rate_limit_tiers.json`. Update the `methods` string and the endpoint count comment to include the new method names. If the method names are not already in the list, add them in the correct alphabetical position.
505+
506+
### 14. Add imports to all modified files
507+
508+
Each file that references the new Request and Response classes needs corresponding import statements. When modifying the following files, add imports for both the new Request and Response classes:
509+
510+
- `MethodsClient.java` — import both `request` and `response` classes
511+
- `AsyncMethodsClient.java` — import both `request` and `response` classes
512+
- `MethodsClientImpl.java` — import both `request` and `response` classes
513+
- `AsyncMethodsClientImpl.java` — import both `request` and `response` classes
514+
- `RequestFormBuilder.java` — import the `request` class only
515+
516+
Place each new import adjacent to the existing imports from the same `apps.*` (or equivalent) package, in alphabetical order.
517+
518+
### 15. Verify
519+
520+
Before considering the work complete, run the tests. The `slack-api-client` module depends on `slack-api-model`, so you must install all modules locally first if they haven't been built yet:
521+
522+
```bash
523+
# Install all modules locally (required before running single-module tests)
524+
./scripts/install_local.sh
525+
526+
# Run the specific tests for the new method and the coverage test
527+
./mvnw test -pl slack-api-client '-Dtest=test_locally.api.methods.AppsTest,test_locally.api.MethodsTest'
528+
```
529+
530+
Note: `install_local.sh` may fail on unrelated example modules (e.g., `bolt-quarkus-examples`). This is fine as long as `slack-api-client` and its dependencies (`slack-api-model`) install successfully.
511531

512532
### Summary checklist
513533

514534
When adding a new Slack API method, make sure you have:
515535

516536
- [ ] Looked up the method docs at `https://docs.slack.dev/reference/methods/{method.name}`
517-
- [ ] Added the method constant in `Methods.java`
518-
- [ ] Created the Request class in `request/{category}/`
519-
- [ ] Created the Response class in `response/{category}/`
520-
- [ ] Added two overloads in `MethodsClient.java`
521-
- [ ] Added two overloads in `AsyncMethodsClient.java`
522-
- [ ] Implemented both overloads in `MethodsClientImpl.java`
523-
- [ ] Implemented both overloads in `AsyncMethodsClientImpl.java`
524-
- [ ] Added `toForm()` in `RequestFormBuilder.java`
525-
- [ ] Added rate limit tier in `MethodsRateLimits.java`
537+
- [ ] Added the method constant in `slack-api-client/src/main/java/com/slack/api/methods/Methods.java`
538+
- [ ] Created the Request class in `slack-api-client/src/main/java/com/slack/api/methods/request/{category}/`
539+
- [ ] Created the Response class in `slack-api-client/src/main/java/com/slack/api/methods/response/{category}/`
540+
- [ ] Added two overloads in `slack-api-client/src/main/java/com/slack/api/methods/MethodsClient.java`
541+
- [ ] Added two overloads in `slack-api-client/src/main/java/com/slack/api/methods/AsyncMethodsClient.java`
542+
- [ ] Implemented both overloads in `slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java`
543+
- [ ] Implemented both overloads in `slack-api-client/src/main/java/com/slack/api/methods/impl/AsyncMethodsClientImpl.java`
544+
- [ ] Added `toForm()` in `slack-api-client/src/main/java/com/slack/api/methods/RequestFormBuilder.java`
545+
- [ ] Added rate limit tier in `slack-api-client/src/main/java/com/slack/api/methods/MethodsRateLimits.java`
526546
- [ ] Added rate limit entry in `metadata/web-api/rate_limit_tiers.json`
527-
- [ ] Added sync and async tests in `test_locally/api/methods/`
528-
- [ ] Updated the endpoint list and count in `MethodsTest.java`
547+
- [ ] Created mock server JSON fixture in `json-logs/samples/api/{method.name}.json`
548+
- [ ] Added sync and async tests in `slack-api-client/src/test/java/test_locally/api/methods/{Category}Test.java`
549+
- [ ] Updated the endpoint list and count in `slack-api-client/src/test/java/test_locally/api/MethodsTest.java`
550+
- [ ] Added import statements for the new Request/Response classes in all modified files
551+
- [ ] Verified tests pass: `./mvnw test -pl slack-api-client '-Dtest=test_locally.api.methods.{Category}Test,test_locally.api.MethodsTest'`
529552

530553
## Testing
531554

@@ -587,7 +610,7 @@ Releases publish all modules simultaneously to Maven Central via Sonatype.
587610

588611
- **Snapshot**: Version must end with `-SNAPSHOT`. Run `scripts/set_version.sh 1.x.y-SNAPSHOT` then `scripts/release.sh`
589612
- **Stable**: Run `scripts/set_version.sh 1.x.y` then `scripts/release.sh`. Requires JDK 17, GPG signing, and Sonatype credentials in `~/.m2/settings.xml`
590-
- Version is set across all `pom.xml` files AND three generated version classes:
613+
- Version is set across all `pom.xml` files AND three generated version classes (generated by `scripts/set_version.sh`):
591614
- `slack-api-model/src/main/java/com/slack/api/meta/SlackApiModelLibraryVersion.java`
592615
- `slack-api-client/src/main/java/com/slack/api/meta/SlackApiClientLibraryVersion.java`
593616
- `bolt/src/main/java/com/slack/api/bolt/meta/BoltLibraryVersion.java`

0 commit comments

Comments
 (0)