Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .cursor/cloud-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Cloud agent Build: prepare Demonator15 (idempotent — safe on every Build).
set -euo pipefail
cd "$(dirname "$0")/.."
chmod +x gradlew
# Unit tests use Java 17 via Gradle toolchain (build.gradle). Full roboRIO cross-build runs in GitHub Actions CI.
./gradlew test --no-daemon
3 changes: 3 additions & 0 deletions .cursor/environment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"install": "bash .cursor/cloud-install.sh"
}
20 changes: 20 additions & 0 deletions .cursor/rules/frc-commands-subsystems.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
description: Command-based structure for FRC robot Java
globs: src/main/java/**/*.java
alwaysApply: false
---

# Subsystems vs commands

- **Subsystems** (`subsystems/**`): hardware, `periodic()`, pose/closed-loop APIs (`drive()`, `stop()`, setpoints). No Xbox bindings or `Command` factories on subsystems when avoidable — use `commands/**` factories (e.g. `DriveCommands`).
- **RobotContainer:** wire default commands, triggers, and `NamedCommands.registerCommand` only; keep binding logic thin.
- **Commands:** use `run` / `runOnce` / `runEnd` / `Commands.sequence` with subsystem requirements. Name commands with `.withName(...)` for Shuffleboard and debugging.
- **Constants:** season field poses and practice coordinates in `constants/FieldConstants`, not buried in subsystems.
- **Autos:** PathPlanner uses `SwerveDrive` via `AutoBuilder` (pose, reset, chassis speeds). Do not break those method signatures without updating PathPlanner integration.

```java
// Prefer: factory in commands/, subsystem API stays imperative
DriveCommands.driveWithXboxController(swerve, controller, () -> true, deadband, sensitivity);

// Avoid: long teleop runEnd blocks inside SwerveDrive
```
13 changes: 13 additions & 0 deletions .cursor/rules/frc-project.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
description: Demonator15 FRC repo conventions (WPILib, Gradle, CI, safety)
alwaysApply: true
---

# Demonator15 — project

- **Stack:** WPILib 2026, GradleRIO, Java **17** for compile and tests. Run `./gradlew test` or `./gradlew build` (CI uses the WPILib cross container).
- **Layout:** `src/main/java/frc/robot/` — `Robot`, `RobotContainer`, `subsystems/`, `commands/`, `constants/`, `hid/`, `util/`. CAN IDs in `RobotMap`; mechanism tuning in subsystem `*Config` classes.
- **Scope:** Prefer small, reviewable diffs. Do not refactor unrelated subsystems in the same change unless asked.
- **Secrets:** Never commit API keys, tokens, or `.env`. Use Cursor/GitHub secrets for cloud only when needed.
- **PathPlanner:** Autos and paths live under `src/main/deploy/pathplanner/`. Named command strings in Java must **exactly** match the PathPlanner GUI.
- **Docs:** [WPILib command-based](https://docs.wpilib.org/en/stable/docs/software/commandbased/index.html), [GradleRIO CI](https://docs.wpilib.org/en/stable/docs/software/advanced-gradlerio/robot-code-ci.html).
13 changes: 13 additions & 0 deletions .cursor/rules/frc-unit-tests.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
description: JUnit and WPILib simulation tests for robot code
globs: src/test/**/*.java
alwaysApply: false
---

# Unit tests

- **Runner:** JUnit 5 (`org.junit.jupiter`). Use **Arrange / Act / Assert** comments in non-trivial tests.
- **Pure logic:** test helpers and math without HAL (`SwerveDynamics`, `SwerveModuleOptimization`, `SwerveTeleopInputs` package helpers, `AngleUtils`, `HIDUtils`).
- **HAL / vendor sim:** `@ExtendWith(WpilibSimulationExtension.class)` for Xbox sim, SparkMaxSim, etc. Use isolated CAN IDs in tests; call `SwerveModule.close()` in `@AfterEach` when constructing real modules.
- **Do not** instantiate full `Robot` or `SwerveDrive` in unit tests unless building a dedicated test fixture — prefer testing extracted pure functions.
- After changes, run `./gradlew test` (Java 17 toolchain from `build.gradle`).
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Builds robot code and runs unit tests on push/PR to main.
# https://docs.wpilib.org/en/stable/docs/software/advanced-gradlerio/robot-code-ci.html
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-22.04
# 2025 image is correct for 2026 per WPILib CI docs (JDK + roboRIO toolchains unchanged).
container: wpilib/roborio-cross-ubuntu:2025-22.04
env:
LANG: C.UTF-8
JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

steps:
- uses: actions/checkout@v6

- name: Add repository to git safe directories
run: git config --global --add safe.directory $GITHUB_WORKSPACE

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Compile and run tests on robot code
run: ./gradlew build
25 changes: 25 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Agent instructions (Demonator15)

## Build and verify

```bash
chmod +x gradlew
./gradlew test # local / Cursor Cloud install script
./gradlew build # full compile + tests (matches GitHub Actions CI)
```

Cloud environment config: `.cursor/environment.json` (runs `cloud-install.sh` → `./gradlew test`).

## Architecture

- WPILib **command-based** robot. Subsystems own hardware; `frc.robot.commands` holds command factories; `RobotContainer` binds controls and PathPlanner **named commands**.
- Swerve: `subsystems/drive/`, teleop commands in `commands/drive/` when present on branch.

## Cursor rules

See `.cursor/rules/*.mdc` for FRC-specific conventions.

## PR expectations

- Keep robot behavior changes scoped and describe driver/auto impact in the PR.
- Ensure CI (`build`) passes before merge.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# Demonator15

[![CI](https://github.com/KHS-Robotics/Demonator15/actions/workflows/ci.yml/badge.svg)](https://github.com/KHS-Robotics/Demonator15/actions/workflows/ci.yml)

Code repository for Demon Robotics' 2026 robot
9 changes: 7 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ dependencies {
test {
useJUnitPlatform()
systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
// WPILib vendor JNI is validated on Java 17 (WPILib installer JDK).
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(17)
}
}

// Simulation configuration (e.g. environment variables).
Expand All @@ -101,7 +105,8 @@ deployArtifact.jarTask = jar
wpi.java.configureExecutableTasks(jar)
wpi.java.configureTestTasks(test)

// Configure string concat to always inline compile
tasks.withType(JavaCompile) {
// Configure string concat to always inline compile; UTF-8 for CI/Linux (US-ASCII breaks on Unicode in comments).
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
options.compilerArgs.add '-XDstringConcat=inline'
}
9 changes: 8 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import org.gradle.internal.os.OperatingSystem

pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
mavenLocal()
String frcYear = '2026'
File frcHome
if (OperatingSystem.current().isWindows()) {
Expand All @@ -24,6 +24,13 @@ pluginManagement {
url = frcHomeMaven
}
}
plugins {
id "org.gradle.toolchains.foojay-resolver-convention" version "0.9.0"
}
}

plugins {
id "org.gradle.toolchains.foojay-resolver-convention"
}

Properties props = System.getProperties();
Expand Down