{"id":31605386,"url":"https://github.com/AbelHristodor/octofer","last_synced_at":"2025-10-06T08:06:39.001Z","repository":{"id":315551836,"uuid":"1057249956","full_name":"AbelHristodor/octofer","owner":"AbelHristodor","description":"🤖 Rust framework for easily building GitHub Apps ","archived":false,"fork":false,"pushed_at":"2025-09-19T09:21:19.000Z","size":1551,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-19T09:37:30.509Z","etag":null,"topics":["framework","github","github-apps","probot","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AbelHristodor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-15T13:27:05.000Z","updated_at":"2025-09-19T08:59:01.000Z","dependencies_parsed_at":"2025-09-19T09:37:33.588Z","dependency_job_id":"b0a6749f-ffb7-46b4-ac54-41fd0fd3190a","html_url":"https://github.com/AbelHristodor/octofer","commit_stats":null,"previous_names":["abelhristodor/octofer"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/AbelHristodor/octofer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelHristodor%2Foctofer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelHristodor%2Foctofer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelHristodor%2Foctofer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelHristodor%2Foctofer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AbelHristodor","download_url":"https://codeload.github.com/AbelHristodor/octofer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AbelHristodor%2Foctofer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278577929,"owners_count":26009703,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["framework","github","github-apps","probot","rust"],"created_at":"2025-10-06T08:02:15.359Z","updated_at":"2025-10-06T08:06:38.996Z","avatar_url":"https://github.com/AbelHristodor.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"#\"\u003e\u003cimg src=\"https://github.com/AbelHristodor/octofer/blob/main/.github/assets/logo.PNG?raw=true\" width=\"160\" alt=\"Octofer's logo\" /\u003e\u003c/a\u003e\n\n\u003c/p\u003e\n\u003ch3 align=\"center\"\u003e\u003ca href=\"#\"\u003eOctofer\u003c/a\u003e\u003c/h3\u003e\n\u003cp align=\"center\"\u003eA framework for building GitHub Apps, in Rust \u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg alt=\"Crates.io Version\" src=\"https://img.shields.io/crates/v/octofer\"\u003e\n\u003cimg alt=\"GitHub Actions Workflow Status\" src=\"https://img.shields.io/github/actions/workflow/status/AbelHristodor/octofer/tests.yaml\"\u003e\n\u003cimg alt=\"GitHub License\" src=\"https://img.shields.io/github/license/AbelHristodor/octofer\"\u003e\n\u003cimg alt=\"GitHub top language\" src=\"https://img.shields.io/github/languages/top/AbelHristodor/octofer\"\u003e\n\u003c/p\u003e\n\n---\n\n\u003e ⚠️ **Under Development** - This framework is currently in active development and not yet ready for production use.\n\nA framework for building GitHub Apps in Rust, inspired by [Probot](https://github.com/probot/probot). Octofer provides a clean, type-safe way to build GitHub Apps with minimal boilerplate and automatic webhook handling.\n\n## What is Octofer?\n\nOctofer simplifies GitHub App development by:\n\n- **Handling webhook events** - Automatically receives and routes GitHub webhook events\n- **Managing authentication** - Handles GitHub App authentication and installation tokens\n- **Providing type safety** - Full Rust type safety for GitHub API interactions\n- **Offering simple APIs** - Clean, intuitive event handler registration\n\n\u003e 🛠️ Looking for a **full production-ready** example? Check out [AbelHristodor/frezze](https://github.com/AbelHristodor/frezze)! A bot that you\ncan use to schedule \"freeze\" periods for your repo, blocking all PR merges for specific periods of time!\n\n## Available Event Handlers\n\nCurrently supported GitHub webhook events:\n\n- `on_issue_comment()` - Issue comment events (created, edited, deleted)\n- `on_issue()` - Issue events (opened, closed, edited, etc.)\n- `on_pull_request()` - Pull request events (opened, closed, merged, etc.)\n- `on_pull_request_review()` - Pull request review events\n- `on_pull_request_review_comment()` - Pull request review comment events\n- `on_pull_request_review_thread()` - Pull request review thread events\n\n## Quick Example\n\n```rust\nuse std::sync::Arc;\nuse octofer::{Octofer, Config};\n\n#[tokio::main]\nasync fn main() -\u003e anyhow::Result\u003c()\u003e {\n    let config = Config::from_env().unwrap_or_default();\n    config.init_logging();\n    \n    let mut app = Octofer::new(config).await.unwrap_or_else(|_| {\n        Octofer::new_default()\n    });\n\n    // Handle issue comments\n    app.on_issue_comment(\n        |context, _| async move {\n            println!(\"Issue comment event received!\");\n            println!(\"Event type: {}\", context.kind());\n            \n            if let Some(client) = \u0026context.github_client {\n                // Use GitHub API client here\n                println!(\"GitHub client available for API calls\");\n            }\n            \n            Ok(())\n        },\n        Arc::new(()),\n    ).await;\n    \n    app.start().await?;\n    Ok(())\n}\n```\n\n## Configuration\n\nOctofer uses a centralized configuration system that loads from environment variables:\n\n```bash\n# Required for GitHub App authentication\nexport GITHUB_APP_ID=your_app_id\nexport GITHUB_PRIVATE_KEY_PATH=path/to/private-key.pem\n# OR\nexport GITHUB_PRIVATE_KEY_BASE64=base64_encoded_key\n\n# Webhook\nexport GITHUB_WEBHOOK_SECRET=your_webhook_secret\n\n# Server configuration (optional)\nexport OCTOFER_HOST=127.0.0.1  # Default: 127.0.0.1\nexport OCTOFER_PORT=8000       # Default: 8000\n\n# Logging configuration (optional)\nexport OCTOFER_LOG_LEVEL=info               # Default: info (trace, debug, info, warn, error)\nexport OCTOFER_LOG_FORMAT=compact           # Default: compact (compact, pretty, json)\nexport OCTOFER_LOG_WITH_TARGET=false        # Default: false (show target module)\nexport OCTOFER_LOG_WITH_FILE=false          # Default: false (show file and line info)\nexport OCTOFER_LOG_WITH_THREAD_IDS=false    # Default: false (show thread IDs)\n```\n\nYou can also create configuration programmatically:\n\n```rust\nuse octofer::Config;\n\nlet config = Config::new(\n    123456,                                    // app_id\n    Some(\"path/to/private-key.pem\".to_string()), // private_key_path\n    None,                                      // private_key_base64\n    \"your-webhook-secret\".to_string(),         // webhook_secret\n    std::net::Ipv4Addr::LOCALHOST,            // host\n    8000,                                      // port\n)?;\n\n// Initialize logging with the configuration\nconfig.init_logging();\n```\n\n## Development\n\nBuild all components:\n\n```bash\ncargo build\n```\n\nRun tests:\n\n```bash\ncargo test\n```\n\n## Code Quality\n\nFormat code:\n\n```bash\ncargo fmt\n```\n\nRun linting:\n\n```bash\ncargo clippy -- -D warnings\n```\n\n## Features\n\n- **Centralized Configuration**: All configuration managed through a single `Config` struct\n- **Environment Variable Support**: Automatic loading from environment variables\n- **GitHub Client Access**: Direct access to authenticated GitHub clients from event handlers\n- **Modular Architecture**: Clean separation of concerns across modules\n- **Type Safety**: Full Rust type safety for GitHub API interactions\n- **Automatic Token Management**: GitHub App installation token caching and refresh\n- **Middleware Support**: HMAC verification and event processing middleware\n\n## Event Handler Context\n\nEvent handlers receive a `Context` object that provides access to:\n\n- **Event data**: `context.payload()` - The full GitHub webhook payload\n- **Event**: `context.event()` - The full GitHub webhook event\n- **Event type**: `context.kind()` - The type of event (e.g., \"issues\", \"issue_comment\")  \n- **Installation ID**: `context.installation_id()` - GitHub App installation ID\n- **GitHub client**: `context.github()` - Authenticated GitHub API client\n- **Installation client**: `context.installation_client()` - Installation-specific authenticated client\n\n## Examples\n\nThe repository includes several examples:\n\n- `basic.rs` - Simple GitHub App with event handlers.\n- `github_client.rs` - Direct GitHub API client usage\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAbelHristodor%2Foctofer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAbelHristodor%2Foctofer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAbelHristodor%2Foctofer/lists"}