### Basic Usage Example for GitHub Adapter with ActiveProject Source: https://github.com/seuros/active_project/blob/master/README.md This snippet provides a basic usage example for the GitHub adapter within the ActiveProject gem. It demonstrates how to initialize the adapter and perform common GitHub operations. The code is intended as a starting point for developers looking to integrate ActiveProject with GitHub. ```ruby ```ruby # Example for GitHub adapter (placeholder) # github_adapter = ActiveProject.adapter(:github) # # ... further operations ... ``` ``` -------------------------------- ### Install ActiveProject Gem Source: https://github.com/seuros/active_project/blob/master/README.md Instructions for adding the ActiveProject gem to your application's Gemfile and installing it using Bundler, or installing it directly via the command line. ```ruby gem 'activeproject' ``` ```bash $ bundle install ``` ```bash $ gem install activeproject ``` -------------------------------- ### Configure GitHub Adapter for Webhooks Source: https://context7.com/seuros/active_project/llms.txt Configures the GitHub adapter with necessary parameters for processing webhooks, including repository details and webhook secret for verification. This setup is done via the ActiveProject.configure block. ```ruby # Configure adapter with webhook secret ActiveProject.configure do |config| config.add_adapter(:github, owner: "octocat", repo: "hello-world", access_token: ENV['GITHUB_ACCESS_TOKEN'], webhook_secret: ENV['GITHUB_WEBHOOK_SECRET'] ) end ``` -------------------------------- ### Enable Asynchronous I/O with ActiveProject Gem Source: https://github.com/seuros/active_project/blob/master/README.md This section explains how to enable non-blocking, asynchronous I/O in the ActiveProject gem by setting the `AP_DEFAULT_ADAPTER` environment variable to `async_http` before the process boots. It then provides a Ruby code example using `ActiveProject::Async.run` to perform parallel API calls to Jira, fetching issues from multiple boards concurrently using Ruby fibers. ```bash AP_DEFAULT_ADAPTER=async_http ``` ```ruby ActiveProject::Async.run do |task| jira = ActiveProject.adapter(:jira) boards = %w[ACME DEV OPS] tasks = boards.map do |key| task.async { jira.list_issues(key, max_results: 100) } end issues = tasks.flat_map(&:wait) puts "Fetched #{issues.size} issues in parallel." end ``` -------------------------------- ### Rails Async Scheduler Configuration and Usage Source: https://context7.com/seuros/active_project/llms.txt Demonstrates automatic async scheduler configuration for Rails applications using ActiveProject's Railtie. It shows how to opt out globally or via environment variables, and provides examples of using ActiveProject's async capabilities within Rails controllers for concurrent data fetching and within background jobs for data synchronization. ```ruby class Application < Rails::Application config.active_project.use_async_scheduler = false end # Or opt out via environment variable # ENV['AP_NO_ASYNC_SCHEDULER'] = '1' # Use in Rails controllers class IssuesController < ApplicationController def sync_all # Async operations work automatically in Rails ActiveProject::Async.run do |task| adapters = [:jira, :github, :basecamp].map { |p| ActiveProject.adapter(p) } tasks = adapters.map do |adapter| task.async { adapter.list_projects } end @all_projects = tasks.flat_map(&:wait) end render json: @all_projects end end # Background job integration class SyncIssuesJob < ApplicationJob def perform(project_key) adapter = ActiveProject.adapter(:jira) issues = adapter.list_issues(project_key, max_results: 1000) issues.each do |issue| LocalIssue.find_or_initialize_by(external_id: issue.id).update( key: issue.key, title: issue.title, status: issue.status, updated_at: issue.updated_at ) end end end ``` -------------------------------- ### Access Basecamp Platform-Specific Features Source: https://context7.com/seuros/active_project/llms.txt Demonstrates adding a comment with HTML-formatted content to Basecamp and accessing the raw data of the created comment. This example highlights the ability to work with rich text content specific to Basecamp. ```ruby # Basecamp-specific: Access HTML content basecamp = ActiveProject.adapter(:basecamp) comment = basecamp.add_comment( "123456", "

HTML formatted content

", { project_id: "98765" } ) puts "Raw HTML: #{comment.raw_data['content']}" ``` -------------------------------- ### Configure Rails Auto-Scheduler in ActiveProject Source: https://github.com/seuros/active_project/blob/master/README.md This documentation explains how ActiveProject integrates with Rails applications by automatically installing `Async::Scheduler` before Zeitwerk boots. It provides instructions on how to opt out of this behavior either globally for the entire application in `config/application.rb` or on a per-environment basis using the `AP_NO_ASYNC_SCHEDULER` environment variable. It also mentions that ActiveProject detects and avoids interfering with schedulers already set up by other gems. ```ruby # config/application.rb config.active_project.use_async_scheduler = false ``` ```bash AP_NO_ASYNC_SCHEDULER=1 ``` -------------------------------- ### Process Jira Webhook Source: https://context7.com/seuros/active_project/llms.txt Handles incoming Jira webhooks by parsing the raw POST request body. This example focuses on the 'issue_created' event and accesses actor information. It does not include signature verification. ```ruby # Jira webhook example (no signature verification) def jira_webhook adapter = ActiveProject.adapter(:jira) webhook_event = adapter.parse_webhook(request.raw_post) if webhook_event && webhook_event.type == :issue_created issue_key = webhook_event.data[:object_key] actor = webhook_event.actor puts "#{actor.name} created issue #{issue_key}" end status 200 end ``` -------------------------------- ### Access Resources via Factories (Jira Adapter) Source: https://context7.com/seuros/active_project/llms.txt Demonstrates using fluent factory patterns to access resources like projects and issues via the Jira adapter. Includes methods for retrieving all resources and finding specific ones by ID or key. ```ruby adapter = ActiveProject.adapter(:jira) # Projects factory projects_factory = adapter.projects all_projects = projects_factory.all # => [#, ...] first_project = projects_factory.find("ACME") # => # # Issues factory issues_factory = adapter.issues all_issues = issues_factory.all # Lists all issues specific_issue = issues_factory.find("ACME-123") # Access issues through project association project = adapter.find_project("ACME") project_issues = project.issues.all # => [#, ...] ``` -------------------------------- ### Access ActiveProject Adapters Source: https://github.com/seuros/active_project/blob/master/README.md Shows how to retrieve configured adapter instances for various project management platforms. Allows fetching default adapters or specifically named instances for different configurations. ```ruby jira_primary = ActiveProject.adapter(:jira) # defaults to :primary jira_secondary = ActiveProject.adapter(:jira, :secondary) basecamp = ActiveProject.adapter(:basecamp) # defaults to :primary trello = ActiveProject.adapter(:trello) # defaults to :primary github = ActiveProject.adapter(:github) # defaults to :primary github_project = ActiveProject.adapter(:github_project) # defaults to :primary ``` -------------------------------- ### Configure ActiveProject Adapters Source: https://github.com/seuros/active_project/blob/master/README.md Demonstrates how to configure different project management adapters (Jira, Basecamp, Trello, GitHub) within the ActiveProject gem using environment variables for sensitive credentials. Supports named instances for multiple configurations of the same adapter. ```ruby ActiveProject.configure do |config| config.add_adapter :jira, site_url: ENV["JIRA_SITE_URL"], username: ENV["JIRA_USERNAME"], api_token: ENV["JIRA_API_TOKEN"] config.add_adapter :basecamp, account_id: ENV["BASECAMP_ACCOUNT_ID"], access_token: ENV["BASECAMP_ACCESS_TOKEN"] config.add_adapter :trello, key: ENV["TRELLO_KEY"], token: ENV["TRELLO_TOKEN"] # GitHub Projects – real Issues/PRs only config.add_adapter :github_project, access_token: ENV["GITHUB_TOKEN"] # GitHub primary instance config.add_adapter :github, owner: ENV["GITHUB_OWNER"], repo: ENV["GITHUB_REPO"], access_token: ENV["GITHUB_ACCESS_TOKEN"], webhook_secret: ENV["GITHUB_WEBHOOK_SECRET"] end ``` -------------------------------- ### Jira Adapter: List, Create, Update, and Comment on Issues Source: https://github.com/seuros/active_project/blob/master/README.md This Ruby snippet demonstrates fetching the Jira adapter, listing projects, retrieving issues, creating a new issue, updating an existing one, and adding a comment. It includes robust error handling for common Jira API issues like authentication, not found, validation, and general API errors. ```ruby jira_adapter = ActiveProject.adapter(:jira) begin # List projects projects = jira_adapter.list_projects puts "Found #{projects.count} projects." first_project = projects.first if first_project puts "Listing issues for project: #{first_project.key}" # List issues in the first project issues = jira_adapter.list_issues(first_project.key, max_results: 5) puts "- Found #{issues.count} issues (showing max 5)." # Find a specific issue (replace 'PROJ-1' with a valid key) # issue_key_to_find = 'PROJ-1' # issue = jira_adapter.find_issue(issue_key_to_find) # puts "- Found issue: #{issue.key} - #{issue.title}" # Create a new issue puts "Creating a new issue..." new_issue_attributes = { project: { key: first_project.key }, summary: "New task from ActiveProject Gem #{Time.now}", issue_type: { name: 'Task' }, # Ensure 'Task' is a valid issue type name description: "This issue was created via the ActiveProject gem." } created_issue = jira_adapter.create_issue(first_project.key, new_issue_attributes) puts "- Created issue: #{created_issue.key} - #{created_issue.title}" # Update the issue puts "Updating issue #{created_issue.key}..." updated_issue = jira_adapter.update_issue(created_issue.key, { summary: "[Updated] #{created_issue.title}" }) puts "- Updated summary: #{updated_issue.title}" # Add a comment puts "Adding comment to issue #{updated_issue.key}..." comment = jira_adapter.add_comment(updated_issue.key, "This is a comment added via the ActiveProject gem.") puts "- Comment added with ID: #{comment.id}" end rescue ActiveProject::AuthenticationError => e puts "Error: Jira Authentication Failed - #{e.message}" rescue ActiveProject::NotFoundError => e puts "Error: Resource Not Found - #{e.message}" rescue ActiveProject::ValidationError => e puts "Error: Validation Failed - #{e.message} (Details: #{e.errors})" rescue ActiveProject::ApiError => e puts "Error: Jira API Error (#{e.status_code}) - #{e.message}" rescue => e puts "An unexpected error occurred: #{e.message}" end ``` -------------------------------- ### Configure ActiveProject Adapters Source: https://context7.com/seuros/active_project/llms.txt Configures various project management API adapters (Jira, Basecamp, Trello, GitHub Projects, GitHub Repositories) with their respective credentials. Supports named instances for multiple accounts of the same service. Accesses configured adapters using `ActiveProject.adapter`. ```ruby ActiveProject.configure do |config| # Jira Cloud or Server (REST v3) config.add_adapter :jira, site_url: "https://yourcompany.atlassian.net", username: "user@example.com", api_token: "your_jira_api_token" # Basecamp (REST v3+) config.add_adapter :basecamp, account_id: "1234567", access_token: "your_basecamp_access_token" # Trello (REST API) config.add_adapter :trello, key: "your_trello_api_key", token: "your_trello_token" # GitHub Projects V2 (GraphQL v4) config.add_adapter :github_project, access_token: "ghp_your_github_token" # GitHub Repository (REST v3) config.add_adapter :github, owner: "octocat", repo: "hello-world", access_token: "ghp_your_github_token", webhook_secret: "your_webhook_secret_optional" # Named instances for multiple accounts config.add_adapter :jira, :secondary, site_url: "https://other-jira.atlassian.net", username: "other@example.com", api_token: "other_jira_token" end # Access configured adapters jira_adapter = ActiveProject.adapter(:jira) # defaults to :primary secondary_jira = ActiveProject.adapter(:jira, :secondary) github_adapter = ActiveProject.adapter(:github) ``` -------------------------------- ### Persist and Update Resources (Jira Adapter) Source: https://context7.com/seuros/active_project/llms.txt Shows how to create, save, update, and delete resources like issues using an ActiveRecord-like API with the Jira adapter. New resources are created locally first and then persisted to the remote API. ```ruby adapter = ActiveProject.adapter(:jira) # Create new issue without immediate persistence issue = ActiveProject::Resources::Issue.new(adapter, { project_id: "ACME", title: "New feature request", description: "Add export functionality" }) # Persist to remote API issue.save # => true # Now issue.id and issue.key are populated # Update attributes and save issue.title = "Updated feature request" issue.description = "Add export to CSV and JSON" issue.save # => true # Update with hash issue.update({ title: "Export feature - Phase 1" }) # => true # Delete remote record issue.delete # => true (issue is now frozen) ``` -------------------------------- ### Manage GitHub Repository Issues with ActiveProject Gem Source: https://github.com/seuros/active_project/blob/master/README.md This Ruby code snippet demonstrates how to interact with a GitHub repository using the ActiveProject gem's GitHub adapter. It covers listing projects (repositories), listing, finding, creating, updating, adding comments to, and closing issues. Error handling for common GitHub API issues is also included. ```ruby github_adapter = ActiveProject.adapter(:github) begin # List projects (will return the configured repository) projects = github_adapter.list_projects puts "Found #{projects.count} GitHub repository." repo = projects.first if repo puts "Working with repository: #{repo.key} (#{repo.name})" # List issues in the repository issues = github_adapter.list_issues(repo.key) puts "- Found #{issues.count} issues." # Find a specific issue (replace '1' with a valid issue number) # issue_number = 1 # issue = github_adapter.find_issue(issue_number.to_s) # puts "- Found issue: ##{issue.key} - #{issue.title}" # Create a new issue puts "Creating a new issue..." new_issue_attributes = { title: "New issue from ActiveProject Gem #{Time.now}", description: "This issue was created via the ActiveProject gem.", assignees: [{ name: "username" }] # Optional: Provide GitHub usernames for assignees } created_issue = github_adapter.create_issue(repo.key, new_issue_attributes) puts "- Created issue: ##{created_issue.key} - #{created_issue.title}" # Update the issue puts "Updating issue ##{created_issue.key}..." updated_issue = github_adapter.update_issue(created_issue.key, { title: "[Updated] #{created_issue.title}" }) puts "- Updated title: #{updated_issue.title}" # Add a comment puts "Adding comment to issue ##{updated_issue.key}..." comment = github_adapter.add_comment(updated_issue.key, "This is a comment added via the ActiveProject gem.") puts "- Comment added with ID: #{comment.id}" # Close the issue puts "Closing issue ##{updated_issue.key}..." closed_issue = github_adapter.update_issue(updated_issue.key, { state: "closed" }) puts "- Issue closed, status: #{closed_issue.status}" end rescue ActiveProject::AuthenticationError => e puts "Error: GitHub Authentication Failed - #{e.message}" rescue ActiveProject::NotFoundError => e puts "Error: Resource Not Found - #{e.message}" rescue ActiveProject::ValidationError => e puts "Error: Validation Failed - #{e.message}" rescue ActiveProject::RateLimitError => e puts "Error: GitHub Rate Limit Exceeded - #{e.message}" rescue ActiveProject::ApiError => e puts "Error: GitHub API Error (#{e.status_code}) - #{e.message}" rescue => e puts "An unexpected error occurred: #{e.message}" end ``` -------------------------------- ### Interact with Basecamp API using ActiveProject Gem Source: https://github.com/seuros/active_project/blob/master/README.md This Ruby code snippet demonstrates how to configure and use the Basecamp adapter to list projects and issues. It includes error handling for common Basecamp API issues such as authentication failures, not found resources, validation errors, rate limits, and general API errors. It also shows how to create a new issue (To-do) but notes that finding, updating, and commenting on issues currently requires project_id context and may raise NotImplementedError. ```ruby basecamp_adapter = ActiveProject.adapter(:basecamp) try # List projects projects = basecamp_adapter.list_projects puts "Found #{projects.count} Basecamp projects." first_project = projects.first if first_project puts "Listing issues (To-dos) for project: #{first_project.name} (ID: #{first_project.id})" # List issues (To-dos) in the first project # Note: This lists across all to-do lists in the project issues = basecamp_adapter.list_issues(first_project.id) puts "- Found #{issues.count} To-dos." # Create a new issue (To-do) # IMPORTANT: You need a valid todolist_id for the target project. # You might need another API call to find a todolist_id first. # todolist_id_for_test = 1234567 # Replace with a real ID # puts "Creating a new To-do..." # new_issue_attributes = { # todolist_id: todolist_id_for_test, # title: "New BC To-do from ActiveProject Gem #{Time.now}", # description: "HTML description for the to-do." # } # created_issue = basecamp_adapter.create_issue(first_project.id, new_issue_attributes) # puts "- Created To-do: #{created_issue.id} - #{created_issue.title}" # --- Operations requiring project_id context (Currently raise NotImplementedError) --- # puts "Finding, updating, and commenting require project_id context and are currently not directly usable via the base interface." # # # Find a specific issue (To-do) - Requires project_id context # # todo_id_to_find = created_issue.id # # issue = basecamp_adapter.find_issue(todo_id_to_find) # Raises NotImplementedError # # # Update the issue (To-do) - Requires project_id context # # updated_issue = basecamp_adapter.update_issue(created_issue.id, { title: "[Updated] #{created_issue.title}" }) # Raises NotImplementedError # # # Add a comment - Requires project_id context # # comment = basecamp_adapter.add_comment(created_issue.id, "This is an HTML comment.") # Raises NotImplementedError end rescue ActiveProject::AuthenticationError => e puts "Error: Basecamp Authentication Failed - #{e.message}" rescue ActiveProject::NotFoundError => e puts "Error: Basecamp Resource Not Found - #{e.message}" rescue ActiveProject::ValidationError => e puts "Error: Basecamp Validation Failed - #{e.message}" rescue ActiveProject::RateLimitError => e puts "Error: Basecamp Rate Limit Exceeded - #{e.message}" rescue ActiveProject::ApiError => e puts "Error: Basecamp API Error (#{e.status_code}) - #{e.message}" rescue NotImplementedError => e puts "Error: Method requires project_id context which is not yet implemented: #{e.message}" rescue => e puts "An unexpected error occurred: #{e.message}" end ``` -------------------------------- ### Process GitHub Webhooks with ActiveProject Gem Source: https://github.com/seuros/active_project/blob/master/README.md This Ruby code demonstrates how to configure and process GitHub webhooks using the ActiveProject gem. It includes verifying webhook signatures and parsing incoming events like issue creation, updates, and comments into a standardized format for further processing. ```ruby # Configure the adapter with a webhook secret (same secret used in GitHub webhook settings) ActiveProject.configure do |config| config.add_adapter(:github, owner: ENV.fetch('GITHUB_OWNER'), repo: ENV.fetch('GITHUB_REPO'), access_token: ENV.fetch('GITHUB_ACCESS_TOKEN'), webhook_secret: ENV.fetch('GITHUB_WEBHOOK_SECRET', nil) ) end # In your webhook endpoint (e.g., in a Rails controller) def github_webhook adapter = ActiveProject.adapter(:github) # Get the raw request body and signature header request_body = request.raw_post signature = request.headers['X-Hub-Signature-256'] # Verify the webhook signature (if webhook_secret is configured) if adapter.verify_webhook_signature(request_body, signature) # Parse the webhook payload into a standardized WebhookEvent event_headers = { 'X-GitHub-Event' => request.headers['X-GitHub-Event'], 'X-GitHub-Delivery' => request.headers['X-GitHub-Delivery'] } webhook_event = adapter.parse_webhook(request_body, event_headers) if webhook_event # Process different event types case webhook_event.type when :issue_created issue = webhook_event.data[:issue] puts "New issue created: ##{issue.key} - #{issue.title}" when :issue_updated, :issue_closed, :issue_reopened issue = webhook_event.data[:issue] puts "Issue ##{issue.key} was #{webhook_event.type.to_s.sub('issue_', '')}" when :comment_created comment = webhook_event.data[:comment] issue = webhook_event.data[:issue] puts "New comment on issue ##{issue.key}: #{comment.body.truncate(50)}" end # The webhook was successfully processed head :ok else # The webhook payload couldn't be parsed head :unprocessable_entity end else # The webhook signature verification failed head :forbidden end end ``` -------------------------------- ### ActiveProject Projects API - Manage Projects Source: https://context7.com/seuros/active_project/llms.txt Provides unified CRUD operations for projects across different platforms. Includes listing all projects, finding a specific project by key, accessing project attributes, creating new projects with platform-specific details, and deleting projects. Requires an adapter instance. ```ruby # List all projects (Jira Projects, Basecamp Projects, Trello Boards, GitHub Repos) adapter = ActiveProject.adapter(:jira) projects = adapter.list_projects # => [#, ...] # Find a specific project project = adapter.find_project("ACME") # => # # Access project attributes puts "Project: #{project.name} (#{project.key})" puts "Adapter source: #{project.adapter_source}" # => :jira # Create a new project (platform-specific attributes) new_project = adapter.create_project({ key: "NEWPROJ", name: "New Project", project_type_key: "software", lead_account_id: "557058:abc123..." }) # Delete a project (use with caution) adapter.delete_project("NEWPROJ") # => true ``` -------------------------------- ### Test Adapter Connectivity Source: https://context7.com/seuros/active_project/llms.txt Verifies adapter connectivity and authentication for various platforms. Includes checking connection status, retrieving the currently authenticated user, and iterating through multiple platforms to report connection success or failure. ```ruby # Check if adapter can authenticate adapter = ActiveProject.adapter(:jira) if adapter.connected? puts "Successfully connected to Jira" current_user = adapter.get_current_user puts "Authenticated as: #{current_user.name} (#{current_user.email})" else puts "Failed to connect - check credentials" end # Test multiple adapters [:jira, :github, :basecamp, :trello].each do |platform| begin adapter = ActiveProject.adapter(platform) if adapter.connected? user = adapter.get_current_user puts "✓ #{platform}: #{user.name}" else puts "✗ #{platform}: Authentication failed" end rescue ActiveProject::Error => e puts "✗ #{platform}: #{e.message}" end end ``` -------------------------------- ### Perform Asynchronous API Calls with Fibers Source: https://context7.com/seuros/active_project/llms.txt Enables parallel API calls using fiber-based concurrency by setting the AP_DEFAULT_ADAPTER environment variable to 'async_http'. Demonstrates running tasks in parallel and collecting results. ```ruby # Enable async adapter via environment variable before process boots # ENV['AP_DEFAULT_ADAPTER'] = 'async_http' ActiveProject::Async.run do |task| jira = ActiveProject.adapter(:jira) project_keys = %w[ACME BETA GAMMA DELTA] # Create async tasks for parallel execution tasks = project_keys.map do |key| task.async { jira.list_issues(key, max_results: 100) } end # Wait for all tasks to complete all_issues = tasks.flat_map(&:wait) puts "Fetched #{all_issues.size} issues from #{project_keys.size} projects in parallel" # No threads, no mutexes - just Ruby fibers end # Parallel operations with error handling ActiveProject::Async.run do |task| adapters = { jira: ActiveProject.adapter(:jira), github: ActiveProject.adapter(:github), basecamp: ActiveProject.adapter(:basecamp) } results = adapters.map do |name, adapter| task.async do begin { name: name, projects: adapter.list_projects } rescue ActiveProject::Error => e { name: name, error: e.message } end end end.map(&:wait) results.each do |result| if result[:error] puts "#{result[:name]}: ERROR - #{result[:error]}" else puts "#{result[:name]}: #{result[:projects].size} projects" end end end ``` -------------------------------- ### Interact with Basecamp Adapter Source: https://context7.com/seuros/active_project/llms.txt Adds a comment to a Basecamp to-do item. Requires project_id context. The adapter is initialized using ActiveProject.adapter(:basecamp). ```ruby basecamp_adapter = ActiveProject.adapter(:basecamp) comment = basecamp_adapter.add_comment( "123456789", # todo_id "Great work! Let's deploy this.", { project_id: "98765" } ) ``` -------------------------------- ### ActiveProject Architecture Diagram Source: https://github.com/seuros/active_project/blob/master/README.md Visual representation of the ActiveProject's architectural structure, highlighting the main gem and its adapter sub-components for different platforms like Jira, Basecamp, Trello, and GitHub. ```text ActiveProject └── Adapters ├── JiraAdapter ├── BasecampAdapter ├── TrelloAdapter ├── GithubProjectAdapter └── GithubAdapter ``` -------------------------------- ### Normalize Jira Statuses Source: https://context7.com/seuros/active_project/llms.txt Demonstrates how to manage and normalize status information for Jira projects. Includes checking status validity, retrieving all valid statuses, converting platform-specific statuses to standard symbols, and converting standard symbols back to platform formats. Status normalization is also automatic when fetching issues. ```ruby adapter = ActiveProject.adapter(:jira) # Check if a status is valid for the platform adapter.status_known?("ACME", :in_progress) # => true # Get all valid statuses for a project statuses = adapter.valid_statuses("ACME") # => [:open, :in_progress, :blocked, :on_hold, :closed] # Normalize platform-specific status to standard symbol normalized = adapter.normalize_status("In Development", project_id: "ACME") # => :in_progress # Convert normalized status back to platform format platform_status = adapter.denormalize_status(:closed, project_id: "ACME") # => "Done" (for Jira) or "closed" (for GitHub) # Status is automatically normalized when fetching issues issue = adapter.find_issue("ACME-123") case issue.status when :open puts "Ready to start" when :in_progress puts "Work in progress" when :closed puts "Completed" end ``` -------------------------------- ### Process GitHub Webhook in Rails/Sinatra Source: https://context7.com/seuros/active_project/llms.txt Handles incoming GitHub webhooks by verifying the signature, parsing the payload into a standardized event, and processing different event types like issue creation or updates. Requires the raw request body and signature header. ```ruby def github_webhook adapter = ActiveProject.adapter(:github) # Verify webhook signature (prevents spoofing) request_body = request.raw_post signature = request.headers['X-Hub-Signature-256'] unless adapter.verify_webhook_signature(request_body, signature) halt 403, "Invalid signature" end # Parse webhook payload into standardized event event_headers = { 'X-GitHub-Event' => request.headers['X-GitHub-Event'], 'X-GitHub-Delivery' => request.headers['X-GitHub-Delivery'] } webhook_event = adapter.parse_webhook(request_body, event_headers) if webhook_event # Process different event types case webhook_event.type when :issue_created issue = webhook_event.data[:issue] notify_team("New issue: ##{issue.key} - #{issue.title}") when :issue_updated issue = webhook_event.data[:issue] changes = webhook_event.data[:changes] || {} log_audit("Issue #{issue.key} updated", changes) when :issue_closed issue = webhook_event.data[:issue] update_metrics(issue) when :comment_created comment = webhook_event.data[:comment] issue = webhook_event.data[:issue] notify_subscribers(issue, comment) end # Access webhook metadata puts "Event type: #{webhook_event.type}" puts "Resource: #{webhook_event.resource_type} (#{webhook_event.resource_id})" puts "Project: #{webhook_event.project_id}" puts "Source adapter: #{webhook_event.source}" status 200 else status 422 # Unprocessable webhook end end ``` -------------------------------- ### Access Trello Platform-Specific Features Source: https://context7.com/seuros/active_project/llms.txt Shows how to retrieve Trello-specific information such as labels and board ID from a card's raw data. This involves accessing arrays and nested objects within the `raw_data` hash. ```ruby # Trello-specific: Access labels and board info trello = ActiveProject.adapter(:trello) issue = trello.find_issue("abc123") # Trello card labels = issue.raw_data["labels"].map { |l| l["name"] } board_id = issue.raw_data["idBoard"] puts "Labels: #{labels.join(', ')}" puts "Board ID: #{board_id}" ``` -------------------------------- ### Access Jira Platform-Specific Features Source: https://context7.com/seuros/active_project/llms.txt Illustrates accessing Jira-specific data, including custom fields like 'Story Points' and 'Sprint'. It uses the `dig` method for safe navigation into nested hash structures within the raw issue data. ```ruby # Jira-specific: Access custom fields jira = ActiveProject.adapter(:jira) issue = jira.find_issue("ACME-123") story_points = issue.raw_data.dig("fields", "customfield_10016") sprint = issue.raw_data.dig("fields", "customfield_10020") puts "Story points: #{story_points}" puts "Sprint: #{sprint&.first&.dig('name')}" ``` -------------------------------- ### ActiveProject Issues API - Manage Issues Source: https://context7.com/seuros/active_project/llms.txt Enables unified CRUD operations for issues, tasks, or cards across supported platforms. Allows listing issues within a project, finding a specific issue by its key, retrieving issue details (key, title, status, assignees, reporter, creation date), creating new issues with detailed attributes, updating existing issues, and deleting issues. Requires an adapter instance. ```ruby adapter = ActiveProject.adapter(:jira) # List issues in a project issues = adapter.list_issues("ACME", max_results: 10) # => [#, ...] # Find a specific issue by key issue = adapter.find_issue("ACME-123") puts "#{issue.key}: #{issue.title}" puts "Status: #{issue.status}" # => :open, :in_progress, :closed puts "Assignees: #{issue.assignees.map(&:name).join(', ')}" puts "Reporter: #{issue.reporter.name}" puts "Created: #{issue.created_at}" # Create a new issue new_issue = adapter.create_issue("ACME", { project: { key: "ACME" }, summary: "Implement dark mode feature", issue_type: { name: "Task" }, description: "Add dark mode toggle to user settings", assignee_id: "557058:abc123...", due_on: Date.today + 7, priority: { name: "High" } }) # => # # Update an issue updated_issue = adapter.update_issue("ACME-456", { summary: "[Updated] Implement dark mode feature", description: "Add dark mode toggle with persistence" }) # Delete an issue adapter.delete_issue("ACME-456") # => true ``` -------------------------------- ### Access GitHub Platform-Specific Features Source: https://context7.com/seuros/active_project/llms.txt Demonstrates how to access GitHub-specific data, such as pull request details and merged status, by accessing the raw data of an issue object. Requires the issue object obtained from the GitHub adapter. ```ruby # GitHub-specific: Access pull request data github = ActiveProject.adapter(:github) issue = github.find_issue("123") # Could be a PR if issue.raw_data["pull_request"] pr_url = issue.raw_data["pull_request"]["html_url"] puts "This is a pull request: #{pr_url}" puts "Merged: #{issue.raw_data['merged']}" end ``` -------------------------------- ### Handle API Errors with Unified Exception Hierarchy Source: https://context7.com/seuros/active_project/llms.txt Illustrates robust error handling for API interactions using a unified exception hierarchy. Catches specific errors like AuthenticationError, NotFoundError, ValidationError, RateLimitError, NotImplementedError, and general ApiError. ```ruby adapter = ActiveProject.adapter(:jira) begin issue = adapter.find_issue("INVALID-KEY") rescue ActiveProject::AuthenticationError => e puts "Authentication failed: #{e.message}" # Handle expired credentials, invalid tokens, 401/403 errors rescue ActiveProject::NotFoundError => e puts "Resource not found: #{e.message}" # Handle 404 errors for missing projects, issues, comments rescue ActiveProject::ValidationError => e puts "Validation failed: #{e.message}" puts "Field errors: #{e.errors.inspect}" puts "Status code: #{e.status_code}" puts "Response body: #{e.response_body}" # Handle 400/422 validation errors with field-level details rescue ActiveProject::RateLimitError => e puts "Rate limit exceeded: #{e.message}" # Handle 429 rate limit errors, implement backoff rescue ActiveProject::ApiError => e puts "API error: #{e.message}" puts "Status: #{e.status_code}" puts "Response: #{e.response_body}" puts "Original error: #{e.original_error}" # Handle general API errors (5xx, connection issues) rescue ActiveProject::NotImplementedError => e puts "Feature not supported: #{e.message}" # Handle adapter-specific unsupported operations end ``` -------------------------------- ### ActiveProject Comments API - Manage Comments Source: https://context7.com/seuros/active_project/llms.txt Facilitates adding and managing comments on issues across supported platforms. Includes adding a new comment with body text to a specific issue, and retrieving comment details such as author, creation timestamp, and comment ID. Requires an adapter instance. ```ruby adapter = ActiveProject.adapter(:jira) # Add a comment to an issue comment = adapter.add_comment("ACME-123", "This has been fixed in the latest release.") # => # puts "Comment by: #{comment.author.name}" puts "Created at: #{comment.created_at}" puts "Comment ID: #{comment.id}" ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.