Thank you for your interest in contributing to IssueAgent! This document provides guidelines and instructions for developing and testing this GitHub Action.
- .NET 9.0 SDK
- Docker (for building and testing the action image)
- VS Code with Dev Containers extension (recommended)
This repository includes a VS Code Dev Container that provides a complete development environment with:
- .NET 9.0 SDK
- Docker-in-Docker support
- GitHub spec-kit tooling (
specify-cli) - Common VS Code extensions for .NET development
- GitHub Copilot MCP Servers (MS Docs, NuGet)
To use the Dev Container:
- Install the Dev Containers extension in VS Code
- Open the repository and select Reopen in Container when prompted (or use Command Palette:
Dev Containers: Reopen in Container) - The container will build and install all dependencies automatically
The devcontainer automatically verifies the installation by running dotnet --version and installs the specify-cli tool from the GitHub spec-kit repository.
This repository is configured to use Model Context Protocol (MCP) servers with GitHub Copilot:
- MS Docs MCP Server - Provides access to Microsoft documentation
- NuGet MCP Server - Provides access to NuGet package information
The MCP servers are configured in .vscode/github-copilot/mcp.json and are automatically available when using GitHub Copilot in this repository.
Run the full test suite:
dotnet testRun specific test categories:
# Unit tests only
dotnet test --filter "FullyQualifiedName~UnitTests"
# Contract tests only
dotnet test --filter "FullyQualifiedName~ContractTests"
# Integration tests (including Docker)
dotnet test --filter "FullyQualifiedName~IntegrationTests"
# Docker integration tests only
dotnet test --filter "FullyQualifiedName~Docker"The Docker integration tests validate the complete end-to-end functionality against the real GitHub API. They require:
Environment Variables:
TEST_PAT: A GitHub Personal Access Token withreposcopeTEST_REPO: Target repository in formatowner/repo(e.g.,mattdot/issueagent-test)
export TEST_PAT="your_github_token_here"
export TEST_REPO="owner/repo"
dotnet test --filter "FullyQualifiedName~Docker"Tests will skip gracefully if these variables are not set. See tests/IssueAgent.IntegrationTests/Docker/README.md for detailed documentation.
Build the Docker image locally:
docker build -f Dockerfile -t issueagent:local .The build uses a multi-stage Dockerfile:
- Build stage: Compiles with .NET 9 AOT (Ahead-of-Time) compilation
- Runtime stage: Minimal Alpine Linux image with the compiled binary
Test the action locally with Docker:
# Create a sample event file
cat > event.json << 'EOF'
{
"action": "opened",
"issue": {
"number": 1
},
"repository": {
"name": "test-repo",
"full_name": "owner/test-repo",
"owner": {
"login": "owner"
}
}
}
EOF
# Run the container
docker run --rm \
-e GITHUB_TOKEN="your_token_here" \
-e GITHUB_REPOSITORY="owner/repo" \
-e GITHUB_EVENT_NAME="issues" \
-e GITHUB_EVENT_PATH="/app/event.json" \
-v $(pwd)/event.json:/app/event.json \
issueagent:local.
├── src/
│ ├── IssueAgent.Agent/ # Core agent logic and GraphQL client
│ ├── IssueAgent.Action/ # Action host (entrypoint)
│ └── IssueAgent.Shared/ # Shared models and contracts
├── tests/
│ ├── IssueAgent.UnitTests/ # Unit tests
│ ├── IssueAgent.ContractTests/ # GraphQL contract tests
│ └── IssueAgent.IntegrationTests/
│ └── Docker/ # End-to-end Docker integration tests
├── docs/
│ ├── operations/ # Operations runbook
│ └── releases/ # Release checklist
├── Dockerfile # Multi-stage Docker build
├── action.yml # GitHub Action metadata
└── .devcontainer/ # Dev Container configuration
The action is designed for fast startup using .NET 9 AOT compilation:
- Startup time: < 1 second (cold start on GitHub-hosted runners)
- Total execution: < 30 seconds (GitHub Actions requirement)
- Binary size: ~15MB (AOT-compiled, trimmed)
The StartupDurationMs metric is logged by the agent. If startup times regress above 1 second, investigate:
- Docker layer caching
- Publish trimming configuration
- Runtime initialization
The project uses Native AOT compilation for maximum performance:
- Configuration:
Directory.Build.propssetsPublishAot=truefor Agent and Action projects - Compatibility: All dependencies must be AOT-compatible (no reflection or dynamic code generation)
- Size optimization: Uses
PublishTrimmed=trueandInvariantGlobalization=true
- Warnings as Errors: The build treats all warnings as errors (
TreatWarningsAsErrors=true) - Analysis Level: Latest (
AnalysisLevel=latest) - Nullable Reference Types: Enabled (
Nullable=enable)
All code changes must:
- Include tests: Unit tests for logic, integration tests for end-to-end scenarios
- Pass all tests:
dotnet testmust succeed with 100% pass rate - Maintain performance: Docker integration tests validate startup time < 5s
- Handle errors gracefully: Include negative test cases
Important: We use a custom HttpClient-based GraphQL client instead of Octokit.GraphQL due to a bug in version 0.4.0-beta that sends malformed requests to GitHub's API.
Our implementation:
- Properly wraps queries in JSON:
{"query": "..."} - Uses manual JSON escaping for AOT compatibility
- Minimizes dependencies and binary size
See src/IssueAgent.Agent/GraphQL/GitHubGraphQLClient.cs for the implementation.
- Fork the repository
- Create a branch for your changes (
git checkout -b feature/my-feature) - Make your changes following the coding standards
- Run tests:
dotnet test(all tests must pass) - Commit with clear, descriptive messages
- Push to your fork
- Open a Pull Request with a clear description of the changes
- Operations Runbook:
docs/operations/issue-context-runbook.md - Release Checklist:
docs/releases/issue-context-checklist.md
Open an issue or discussion in the repository for questions about contributing.