From cd2e6fa25a5aca282ea447efbfd6b8133bcba3d8 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 01:24:15 +0000 Subject: [PATCH 1/2] Add Devin Playbook Sync GitHub Action - Create composite action with full Devin API integration - Support all 5 playbook operations (create, list, get, update, delete) - Add comprehensive README with usage examples - Add deployment documentation - Include test playbooks and test workflow - Integrate with Devin API endpoints for playbook management - Add dry-run mode for testing without API calls - Implement recursive directory scanning for .md files Features: - Automatic discovery of .md files in directories - Full API support for all Devin playbook operations - Secure API key handling via GitHub secrets - Detailed outputs (playbook IDs, counts, results) - Comprehensive error handling and validation Documentation includes: - Usage examples for all operations - Input/output reference - API documentation links - Troubleshooting guide - Deployment and release process Co-Authored-By: Sam Fertig --- .github/workflows/test-action.yml | 59 ++++ DEPLOYMENT.md | 342 ++++++++++++++++++++++++ LICENSE | 21 ++ README.md | 302 ++++++++++++++++++++- action.yml | 132 +++++++++ scripts/sync-playbooks.sh | 311 +++++++++++++++++++++ test-playbooks/code-review-checklist.md | 54 ++++ test-playbooks/example-setup.md | 58 ++++ 8 files changed, 1278 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test-action.yml create mode 100644 DEPLOYMENT.md create mode 100644 LICENSE create mode 100644 action.yml create mode 100755 scripts/sync-playbooks.sh create mode 100644 test-playbooks/code-review-checklist.md create mode 100644 test-playbooks/example-setup.md diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml new file mode 100644 index 0000000..edc3a97 --- /dev/null +++ b/.github/workflows/test-action.yml @@ -0,0 +1,59 @@ +name: Test Action + +on: + push: + branches: [main, 'devin/**'] + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + test-dry-run: + name: Test Dry Run Mode + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Test sync operation (dry run) + uses: ./ + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY || 'test-key' }} + directory: './test-playbooks' + dry-run: 'true' + recursive: 'true' + + test-validation: + name: Test Input Validation + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Test with missing API key (should fail) + id: test-fail + continue-on-error: true + uses: ./ + with: + devin-api-key: '' + directory: './test-playbooks' + + - name: Verify failure + if: steps.test-fail.outcome != 'failure' + run: | + echo "Action should have failed with missing API key" + exit 1 + + test-list: + name: Test List Operation (Dry Run) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Test list operation + uses: ./ + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY || 'test-key' }} + operation: 'list' + dry-run: 'true' diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..0caa5fb --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,342 @@ +# Deployment Guide + +This guide explains how to deploy and publish the Devin Playbook Sync GitHub Action. + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Local Testing](#local-testing) +- [Publishing to GitHub Marketplace](#publishing-to-github-marketplace) +- [Versioning Strategy](#versioning-strategy) +- [Release Process](#release-process) +- [Update Process](#update-process) + +## Prerequisites + +Before deploying the action, ensure you have: + +1. **Repository Access**: Write access to the `samfert-codeium/DEVIN-GITHUB-ACTIONS` repository +2. **Devin API Key**: For testing purposes +3. **Git Configured**: Your local git is set up with proper credentials + +## Local Testing + +### Method 1: Using act (Recommended) + +[act](https://github.com/nektos/act) allows you to run GitHub Actions locally: + +1. Install act: + ```bash + # macOS + brew install act + + # Linux + curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash + + # Windows + choco install act-cli + ``` + +2. Create a test workflow: + ```bash + mkdir -p .github/workflows + cat > .github/workflows/test.yml << 'EOF' + name: Test Action + on: push + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./ + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + directory: './test-playbooks' + dry-run: 'true' + EOF + ``` + +3. Create test markdown files: + ```bash + mkdir -p test-playbooks + echo "# Test Playbook\nThis is a test playbook." > test-playbooks/test.md + ``` + +4. Run the action locally: + ```bash + act push -s DEVIN_API_KEY=your-api-key-here + ``` + +### Method 2: Testing in a Fork + +1. Fork the repository to your personal account +2. Add your Devin API key to the fork's secrets +3. Create a test workflow and push changes +4. Monitor the Actions tab to see results + +### Method 3: Direct Testing in Repository + +1. Create a feature branch: + ```bash + git checkout -b test/action-validation + ``` + +2. Add a test workflow: + ```bash + mkdir -p .github/workflows + cat > .github/workflows/test-action.yml << 'EOF' + name: Test Action + on: + push: + branches: [test/*] + jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Test sync operation + uses: ./ + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + directory: './test-playbooks' + dry-run: 'true' + - name: Test list operation + uses: ./ + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + operation: 'list' + EOF + ``` + +3. Push and verify the action runs correctly + +## Publishing to GitHub Marketplace + +### Step 1: Prepare for Release + +1. Ensure all files are in the repository: + - `action.yml` (metadata) + - `scripts/sync-playbooks.sh` (main script) + - `README.md` (documentation) + - `LICENSE` (if not already present) + +2. Make the script executable: + ```bash + chmod +x scripts/sync-playbooks.sh + ``` + +3. Commit all changes: + ```bash + git add action.yml scripts/ README.md DEPLOYMENT.md + git commit -m "Prepare action for initial release" + git push origin main + ``` + +### Step 2: Create a Release + +1. Create and push a version tag: + ```bash + git tag -a v1.0.0 -m "Initial release of Devin Playbook Sync Action" + git push origin v1.0.0 + ``` + +2. Create a major version tag for easier updates: + ```bash + git tag -a v1 -m "Version 1.x" + git push origin v1 + ``` + +3. Go to GitHub repository โ†’ Releases โ†’ Draft a new release + +4. Fill in the release details: + - **Tag**: Select `v1.0.0` + - **Title**: `v1.0.0 - Initial Release` + - **Description**: Include release notes (see template below) + - Check "Publish this Action to the GitHub Marketplace" + - Select primary category: "Automation" + - Add secondary category: "Publishing" + +5. Click "Publish release" + +### Release Notes Template + +```markdown +## ๐ŸŽ‰ Initial Release + +### Features +- โœจ Scan directories for Markdown files +- ๐Ÿ“ค Sync files as Devin playbooks via API +- ๐Ÿ”„ Support for all 5 Devin playbook operations (Create, List, Get, Update, Delete) +- ๐Ÿงช Dry-run mode for testing +- ๐Ÿ“Š Detailed outputs (playbook IDs, counts, results) +- ๐Ÿ”’ Secure API key handling via GitHub secrets + +### Supported Operations +- `sync` - Create playbooks from markdown files +- `list` - List all team playbooks +- `get` - Retrieve specific playbook +- `update` - Update existing playbook +- `delete` - Delete a playbook + +### Usage +See [README.md](./README.md) for complete usage instructions. + +### API Documentation +- [Devin API Reference](https://docs.devin.ai/api-reference/overview) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) +``` + +## Versioning Strategy + +Follow [Semantic Versioning](https://semver.org/): + +- **MAJOR** (v2.0.0): Breaking changes +- **MINOR** (v1.1.0): New features, backward compatible +- **PATCH** (v1.0.1): Bug fixes, backward compatible + +### Version Tags + +Users can reference the action in three ways: + +```yaml +# Specific version (recommended for production) +uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1.0.0 + +# Major version (gets latest v1.x.x) +uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + +# Latest (not recommended for production) +uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@main +``` + +## Release Process + +### For New Features (Minor Version) + +1. Develop feature in a feature branch +2. Update README.md with new capabilities +3. Test thoroughly +4. Merge to main +5. Create new tags: + ```bash + git checkout main + git pull + git tag -a v1.1.0 -m "Add [feature name]" + git push origin v1.1.0 + + # Update major version tag + git tag -fa v1 -m "Update v1 to v1.1.0" + git push origin v1 --force + ``` +6. Create GitHub release with changelog + +### For Bug Fixes (Patch Version) + +1. Fix bug in a bugfix branch +2. Update tests if needed +3. Merge to main +4. Create new tags: + ```bash + git checkout main + git pull + git tag -a v1.0.1 -m "Fix [bug description]" + git push origin v1.0.1 + + # Update major version tag + git tag -fa v1 -m "Update v1 to v1.0.1" + git push origin v1 --force + ``` +5. Create GitHub release with bugfix notes + +### For Breaking Changes (Major Version) + +1. Plan and document breaking changes +2. Update README.md with migration guide +3. Test extensively +4. Merge to main +5. Create new tags: + ```bash + git checkout main + git pull + git tag -a v2.0.0 -m "Major version 2 with breaking changes" + git push origin v2.0.0 + git tag -a v2 -m "Version 2.x" + git push origin v2 + ``` +6. Create GitHub release with detailed migration guide + +## Update Process + +### Updating the Action Code + +1. Make changes to `action.yml` or `scripts/sync-playbooks.sh` +2. Update README.md if behavior changes +3. Test changes locally or in a feature branch +4. Follow the release process above + +### Updating Dependencies + +This action is self-contained and has minimal dependencies: +- **bash**: System default +- **curl**: Pre-installed on GitHub runners +- **jq**: Pre-installed on GitHub runners + +If you need to add dependencies: +1. Update the action to install them in a setup step +2. Document the new requirement in README.md +3. Test on all supported runner types (ubuntu-latest, macos-latest, windows-latest) + +## Best Practices + +### Before Publishing + +- [ ] Test all operation modes (sync, list, get, update, delete) +- [ ] Test with various directory structures +- [ ] Test error handling (invalid API key, network issues, etc.) +- [ ] Verify dry-run mode works correctly +- [ ] Check documentation is up-to-date +- [ ] Ensure scripts have proper permissions (`chmod +x`) +- [ ] Verify branding icons display correctly + +### After Publishing + +- [ ] Test the action using the marketplace version +- [ ] Monitor GitHub Issues for bug reports +- [ ] Update documentation based on user feedback +- [ ] Keep the action up-to-date with Devin API changes + +## Monitoring + +After deployment, monitor: + +1. **GitHub Insights**: Track action usage and popularity +2. **Issues & Discussions**: Respond to user questions and bug reports +3. **Devin API Changes**: Update action when API changes +4. **Security Advisories**: Address any security vulnerabilities promptly + +## Rolling Back + +If a release has critical issues: + +1. Update major version tag to previous working version: + ```bash + git tag -fa v1 -m "Rollback to v1.0.0" + git push origin v1 --force + ``` + +2. Create a new release explaining the rollback +3. Fix the issue and release a new patch version + +## Support + +For questions or issues: +- Open an issue in the repository +- Check existing documentation +- Review GitHub Actions logs for debugging + +## References + +- [GitHub Actions: Creating Actions](https://docs.github.com/en/actions/creating-actions) +- [Publishing Actions to Marketplace](https://docs.github.com/en/actions/creating-actions/publishing-actions-in-github-marketplace) +- [Devin API Documentation](https://docs.devin.ai/api-reference/overview) +- [Semantic Versioning](https://semver.org/) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eb2815e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Sam Fertig + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 061f289..d931f79 100644 --- a/README.md +++ b/README.md @@ -1 +1,301 @@ -# DEVIN-GITHUB-ACTIONS +# Devin Playbook Sync Action + +A GitHub Action that scans directories for Markdown files and syncs them as Devin playbooks using the [Devin API](https://docs.devin.ai/api-reference/overview). This action supports all Devin playbook operations including create, list, get, update, and delete. + +## Features + +- ๐Ÿ“ **Automatic Discovery**: Scans directories for `.md` files +- ๐Ÿ”„ **Full API Support**: Supports all 5 Devin playbook API operations +- ๐ŸŽฏ **Flexible Operations**: Create, list, get, update, and delete playbooks +- ๐Ÿ”’ **Secure**: Uses GitHub secrets for API key management +- ๐Ÿš€ **Easy to Use**: Simple configuration with sensible defaults +- ๐Ÿงช **Dry Run Mode**: Test without making actual API calls +- ๐Ÿ“Š **Detailed Output**: Returns playbook IDs and operation results + +## Supported Operations + +- **sync** (default): Scan directory for `.md` files and create playbooks +- **list**: List all team playbooks +- **get**: Retrieve a specific playbook +- **update**: Update an existing playbook +- **delete**: Delete a playbook + +## Usage + +### Prerequisites + +1. Get your Devin API key from [Devin Settings](https://app.devin.ai/settings) +2. Add the API key to your repository secrets as `DEVIN_API_KEY` + +### Basic Usage - Sync Markdown Files + +Create a workflow file (e.g., `.github/workflows/sync-playbooks.yml`): + +```yaml +name: Sync Playbooks + +on: + push: + branches: [main] + paths: + - 'playbooks/**/*.md' + workflow_dispatch: + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Sync playbooks to Devin + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + directory: './playbooks' + operation: 'sync' +``` + +### List All Playbooks + +```yaml +- name: List all playbooks + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + operation: 'list' +``` + +### Get a Specific Playbook + +```yaml +- name: Get playbook + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + operation: 'get' + playbook-id: 'your-playbook-id' +``` + +### Update a Playbook + +```yaml +- name: Update playbook + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + operation: 'update' + playbook-id: 'your-playbook-id' + playbook-title: 'Updated Title' + playbook-body: 'Updated content...' + playbook-macro: '!deploy' +``` + +### Delete a Playbook + +```yaml +- name: Delete playbook + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + operation: 'delete' + playbook-id: 'your-playbook-id' +``` + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `devin-api-key` | Devin API key for authentication | Yes | - | +| `operation` | Operation to perform: `sync`, `list`, `get`, `update`, `delete` | No | `sync` | +| `directory` | Directory to scan for `.md` files (used with `sync`) | No | `.` | +| `playbook-id` | Playbook ID (required for `get`, `update`, `delete`) | No | - | +| `playbook-title` | Title for the playbook (used with `update`) | No | - | +| `playbook-body` | Body/content for the playbook (used with `update`) | No | - | +| `playbook-macro` | Optional macro shortcut (e.g., `!deploy`) | No | - | +| `api-base-url` | Base URL for the Devin API | No | `https://api.devin.ai` | +| `recursive` | Recursively scan subdirectories | No | `true` | +| `dry-run` | Run without making actual API calls | No | `false` | + +## Outputs + +| Output | Description | +|--------|-------------| +| `playbook-ids` | Comma-separated list of created/updated playbook IDs | +| `playbooks-count` | Number of playbooks processed | +| `operation-result` | Result of the operation in JSON format | + +## Advanced Examples + +### Sync with Custom Configuration + +```yaml +- name: Sync playbooks with custom settings + id: sync + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + directory: './docs/playbooks' + recursive: 'true' + playbook-macro: '!auto' + +- name: Display results + run: | + echo "Created playbooks: ${{ steps.sync.outputs.playbook-ids }}" + echo "Total count: ${{ steps.sync.outputs.playbooks-count }}" +``` + +### Dry Run Before Syncing + +```yaml +- name: Test sync (dry run) + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + directory: './playbooks' + dry-run: 'true' +``` + +### Complete Workflow Example + +```yaml +name: Playbook Management + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + inputs: + operation: + description: 'Operation to perform' + required: true + type: choice + options: + - sync + - list + default: 'list' + +jobs: + manage-playbooks: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Dry run on PR + if: github.event_name == 'pull_request' + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + directory: './playbooks' + dry-run: 'true' + + - name: Sync on push to main + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + directory: './playbooks' + + - name: Manual operation + if: github.event_name == 'workflow_dispatch' + uses: samfert-codeium/DEVIN-GITHUB-ACTIONS@v1 + with: + devin-api-key: ${{ secrets.DEVIN_API_KEY }} + operation: ${{ github.event.inputs.operation }} + directory: './playbooks' +``` + +## Markdown File Format + +Your markdown files should contain the playbook content. The filename (without `.md` extension) will be used as the playbook title. + +Example file structure: +``` +playbooks/ +โ”œโ”€โ”€ setup-dev-environment.md +โ”œโ”€โ”€ deploy-to-production.md +โ””โ”€โ”€ code-review-checklist.md +``` + +Example `setup-dev-environment.md`: +```markdown +# Development Environment Setup + +This playbook guides you through setting up the development environment. + +## Prerequisites +- Node.js 18+ +- Docker installed +- Git configured + +## Steps +1. Clone the repository +2. Install dependencies: `npm install` +3. Configure environment variables +4. Start development server: `npm run dev` +``` + +## API Documentation + +This action integrates with the following Devin API endpoints: + +- **POST /v1/playbooks** - Create a new playbook +- **GET /v1/playbooks** - List all playbooks +- **GET /v1/playbooks/{id}** - Get a specific playbook +- **PUT /v1/playbooks/{id}** - Update a playbook +- **DELETE /v1/playbooks/{id}** - Delete a playbook + +For detailed API documentation, visit: https://docs.devin.ai/api-reference/overview + +## Error Handling + +The action will fail if: +- Invalid API key provided +- Required inputs are missing +- API requests fail (network issues, authentication, etc.) +- No markdown files found in the specified directory (warning only) + +Check the action logs for detailed error messages and troubleshooting information. + +## Security + +- Always store your Devin API key in GitHub secrets, never commit it to the repository +- Use repository secrets: Settings โ†’ Secrets and variables โ†’ Actions โ†’ New repository secret +- The API key is passed securely to the action through environment variables + +## Troubleshooting + +### Action fails with "unauthorized" +- Verify your API key is correct +- Ensure the secret name matches what's used in the workflow + +### No playbooks created +- Check that `.md` files exist in the specified directory +- Verify the `directory` path is correct +- Enable `dry-run: 'true'` to test without API calls + +### API rate limiting +- The Devin API may have rate limits +- Consider adding delays between bulk operations +- Contact Devin support for rate limit information + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +MIT License - see LICENSE file for details + +## Support + +- [Devin Documentation](https://docs.devin.ai/) +- [Devin API Reference](https://docs.devin.ai/api-reference/overview) +- [GitHub Actions Documentation](https://docs.github.com/en/actions) + +## Author + +Created by Sam Fertig ([@samfert-codeium](https://github.com/samfert-codeium)) diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..873d2a3 --- /dev/null +++ b/action.yml @@ -0,0 +1,132 @@ +name: 'Devin Playbook Sync' +description: 'Scans a directory for Markdown files and syncs them as Devin playbooks using the Devin API' +author: 'Sam Fertig (@samfert-codeium)' + +branding: + icon: 'book-open' + color: 'blue' + +inputs: + devin-api-key: + description: 'Devin API key for authentication. Can also be provided via DEVIN_API_KEY environment variable.' + required: true + + operation: + description: 'Operation to perform: sync, list, get, update, delete' + required: false + default: 'sync' + + directory: + description: 'Directory to scan for .md files (used with sync operation)' + required: false + default: '.' + + playbook-id: + description: 'Playbook ID (required for get, update, delete operations)' + required: false + default: '' + + playbook-title: + description: 'Title for the playbook (used with update operation)' + required: false + default: '' + + playbook-body: + description: 'Body/content for the playbook (used with update operation)' + required: false + default: '' + + playbook-macro: + description: 'Optional macro shortcut for the playbook (e.g., !deploy)' + required: false + default: '' + + api-base-url: + description: 'Base URL for the Devin API' + required: false + default: 'https://api.devin.ai' + + recursive: + description: 'Recursively scan subdirectories for .md files' + required: false + default: 'true' + + dry-run: + description: 'Run in dry-run mode without making actual API calls' + required: false + default: 'false' + +outputs: + playbook-ids: + description: 'Comma-separated list of created/updated playbook IDs' + value: ${{ steps.sync-playbooks.outputs.playbook-ids }} + + playbooks-count: + description: 'Number of playbooks processed' + value: ${{ steps.sync-playbooks.outputs.playbooks-count }} + + operation-result: + description: 'Result of the operation (JSON format)' + value: ${{ steps.sync-playbooks.outputs.operation-result }} + +runs: + using: 'composite' + steps: + - name: Validate inputs + shell: bash + run: | + echo "::group::Validating inputs" + + if [ -z "${{ inputs.devin-api-key }}" ]; then + echo "::error::devin-api-key is required" + exit 1 + fi + + OPERATION="${{ inputs.operation }}" + if [[ ! "$OPERATION" =~ ^(sync|list|get|update|delete)$ ]]; then + echo "::error::Invalid operation: $OPERATION. Must be one of: sync, list, get, update, delete" + exit 1 + fi + + if [[ "$OPERATION" =~ ^(get|update|delete)$ ]] && [ -z "${{ inputs.playbook-id }}" ]; then + echo "::error::playbook-id is required for $OPERATION operation" + exit 1 + fi + + if [[ "$OPERATION" == "update" ]] && [ -z "${{ inputs.playbook-title }}" ] && [ -z "${{ inputs.playbook-body }}" ]; then + echo "::error::Either playbook-title or playbook-body is required for update operation" + exit 1 + fi + + echo "โœ“ All inputs validated successfully" + echo "::endgroup::" + + - name: Setup environment + shell: bash + run: | + echo "::group::Setting up environment" + + # Create output directory for temporary files + mkdir -p "${{ runner.temp }}/devin-playbooks" + + echo "โœ“ Environment setup complete" + echo "::endgroup::" + + - name: Sync playbooks + id: sync-playbooks + shell: bash + env: + DEVIN_API_KEY: ${{ inputs.devin-api-key }} + API_BASE_URL: ${{ inputs.api-base-url }} + OPERATION: ${{ inputs.operation }} + DIRECTORY: ${{ inputs.directory }} + PLAYBOOK_ID: ${{ inputs.playbook-id }} + PLAYBOOK_TITLE: ${{ inputs.playbook-title }} + PLAYBOOK_BODY: ${{ inputs.playbook-body }} + PLAYBOOK_MACRO: ${{ inputs.playbook-macro }} + RECURSIVE: ${{ inputs.recursive }} + DRY_RUN: ${{ inputs.dry-run }} + TEMP_DIR: ${{ runner.temp }}/devin-playbooks + run: | + # Source the main script + "${{ github.action_path }}/scripts/sync-playbooks.sh" diff --git a/scripts/sync-playbooks.sh b/scripts/sync-playbooks.sh new file mode 100755 index 0000000..8af2a8c --- /dev/null +++ b/scripts/sync-playbooks.sh @@ -0,0 +1,311 @@ +#!/bin/bash + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { + echo -e "${BLUE}โ„น${NC} $1" +} + +log_success() { + echo -e "${GREEN}โœ“${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}โš ${NC} $1" +} + +log_error() { + echo -e "${RED}โœ—${NC} $1" +} + +api_call() { + local method="$1" + local endpoint="$2" + local data="$3" + local response_file="${TEMP_DIR}/api_response.json" + + local url="${API_BASE_URL}${endpoint}" + + if [ "$DRY_RUN" = "true" ]; then + log_warning "DRY RUN: Would call $method $url" + if [ -n "$data" ]; then + log_info "Request data: $data" + fi + echo '{"status":"dry-run","message":"Dry run mode - no actual API call made"}' + return 0 + fi + + local http_code + if [ -n "$data" ]; then + http_code=$(curl -s -w "%{http_code}" -o "$response_file" \ + -X "$method" \ + -H "Authorization: Bearer ${DEVIN_API_KEY}" \ + -H "Content-Type: application/json" \ + -d "$data" \ + "$url") + else + http_code=$(curl -s -w "%{http_code}" -o "$response_file" \ + -X "$method" \ + -H "Authorization: Bearer ${DEVIN_API_KEY}" \ + "$url") + fi + + if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then + cat "$response_file" + return 0 + else + log_error "API call failed with status $http_code" + cat "$response_file" >&2 + return 1 + fi +} + +create_playbook() { + local file_path="$1" + local title + local body + + title=$(basename "$file_path" .md) + body=$(cat "$file_path") + + log_info "Creating playbook: $title" + + local json_data + if [ -n "$PLAYBOOK_MACRO" ]; then + json_data=$(jq -n \ + --arg title "$title" \ + --arg body "$body" \ + --arg macro "$PLAYBOOK_MACRO" \ + '{title: $title, body: $body, macro: $macro}') + else + json_data=$(jq -n \ + --arg title "$title" \ + --arg body "$body" \ + '{title: $title, body: $body}') + fi + + local response + if response=$(api_call "POST" "/v1/playbooks" "$json_data"); then + local playbook_id + playbook_id=$(echo "$response" | jq -r '.playbook_id // .id // empty') + + if [ -n "$playbook_id" ]; then + log_success "Created playbook '$title' with ID: $playbook_id" + echo "$playbook_id" >> "${TEMP_DIR}/playbook_ids.txt" + else + log_warning "Playbook created but ID not found in response" + fi + return 0 + else + log_error "Failed to create playbook: $title" + return 1 + fi +} + +list_playbooks() { + log_info "Fetching all playbooks..." + + local response + if response=$(api_call "GET" "/v1/playbooks" ""); then + echo "$response" | jq '.' + + local count + count=$(echo "$response" | jq 'length // 0') + log_success "Found $count playbook(s)" + + echo "playbooks-count=$count" >> "$GITHUB_OUTPUT" + echo "operation-result<> "$GITHUB_OUTPUT" + echo "$response" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + return 0 + else + log_error "Failed to list playbooks" + return 1 + fi +} + +get_playbook() { + local playbook_id="$1" + log_info "Fetching playbook: $playbook_id" + + local response + if response=$(api_call "GET" "/v1/playbooks/${playbook_id}" ""); then + echo "$response" | jq '.' + log_success "Retrieved playbook: $playbook_id" + + echo "operation-result<> "$GITHUB_OUTPUT" + echo "$response" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + return 0 + else + log_error "Failed to get playbook: $playbook_id" + return 1 + fi +} + +update_playbook() { + local playbook_id="$1" + log_info "Updating playbook: $playbook_id" + + local title="$PLAYBOOK_TITLE" + local body="$PLAYBOOK_BODY" + + if [ -z "$title" ] && [ -z "$body" ]; then + log_error "Either title or body must be provided for update" + return 1 + fi + + if [ -z "$title" ] || [ -z "$body" ]; then + local current + if current=$(api_call "GET" "/v1/playbooks/${playbook_id}" ""); then + if [ -z "$title" ]; then + title=$(echo "$current" | jq -r '.title') + fi + if [ -z "$body" ]; then + body=$(echo "$current" | jq -r '.body') + fi + else + log_error "Failed to fetch current playbook for update" + return 1 + fi + fi + + local json_data + if [ -n "$PLAYBOOK_MACRO" ]; then + json_data=$(jq -n \ + --arg title "$title" \ + --arg body "$body" \ + --arg macro "$PLAYBOOK_MACRO" \ + '{title: $title, body: $body, macro: $macro}') + else + json_data=$(jq -n \ + --arg title "$title" \ + --arg body "$body" \ + '{title: $title, body: $body}') + fi + + local response + if response=$(api_call "PUT" "/v1/playbooks/${playbook_id}" "$json_data"); then + log_success "Updated playbook: $playbook_id" + + echo "operation-result<> "$GITHUB_OUTPUT" + echo "$response" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + return 0 + else + log_error "Failed to update playbook: $playbook_id" + return 1 + fi +} + +delete_playbook() { + local playbook_id="$1" + log_info "Deleting playbook: $playbook_id" + + local response + if response=$(api_call "DELETE" "/v1/playbooks/${playbook_id}" ""); then + log_success "Deleted playbook: $playbook_id" + + echo "operation-result<> "$GITHUB_OUTPUT" + echo "$response" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + return 0 + else + log_error "Failed to delete playbook: $playbook_id" + return 1 + fi +} + +sync_markdown_files() { + log_info "Scanning directory: $DIRECTORY" + + local find_cmd="find \"$DIRECTORY\" -type f -name '*.md'" + if [ "$RECURSIVE" != "true" ]; then + find_cmd="find \"$DIRECTORY\" -maxdepth 1 -type f -name '*.md'" + fi + + local md_files + md_files=$(eval "$find_cmd" | sort) + + if [ -z "$md_files" ]; then + log_warning "No .md files found in $DIRECTORY" + echo "playbooks-count=0" >> "$GITHUB_OUTPUT" + echo "playbook-ids=" >> "$GITHUB_OUTPUT" + return 0 + fi + + local total_files + total_files=$(echo "$md_files" | wc -l) + log_info "Found $total_files markdown file(s)" + + echo "::group::Creating playbooks" + + local success_count=0 + local failed_count=0 + + while IFS= read -r file; do + if [ -n "$file" ]; then + if create_playbook "$file"; then + ((success_count++)) + else + ((failed_count++)) + fi + fi + done <<< "$md_files" + + echo "::endgroup::" + + log_success "Successfully created $success_count playbook(s)" + if [ $failed_count -gt 0 ]; then + log_warning "Failed to create $failed_count playbook(s)" + fi + + if [ -f "${TEMP_DIR}/playbook_ids.txt" ]; then + local ids + ids=$(cat "${TEMP_DIR}/playbook_ids.txt" | tr '\n' ',' | sed 's/,$//') + echo "playbook-ids=$ids" >> "$GITHUB_OUTPUT" + else + echo "playbook-ids=" >> "$GITHUB_OUTPUT" + fi + + echo "playbooks-count=$success_count" >> "$GITHUB_OUTPUT" +} + +main() { + echo "::group::Devin Playbook Sync - ${OPERATION}" + log_info "Starting operation: $OPERATION" + log_info "API Base URL: $API_BASE_URL" + + case "$OPERATION" in + sync) + sync_markdown_files + ;; + list) + list_playbooks + ;; + get) + get_playbook "$PLAYBOOK_ID" + ;; + update) + update_playbook "$PLAYBOOK_ID" + ;; + delete) + delete_playbook "$PLAYBOOK_ID" + ;; + *) + log_error "Unknown operation: $OPERATION" + exit 1 + ;; + esac + + echo "::endgroup::" + log_success "Operation completed successfully" +} + +main diff --git a/test-playbooks/code-review-checklist.md b/test-playbooks/code-review-checklist.md new file mode 100644 index 0000000..5bb1dd4 --- /dev/null +++ b/test-playbooks/code-review-checklist.md @@ -0,0 +1,54 @@ +# Code Review Checklist + +Use this playbook when reviewing pull requests to ensure consistent and thorough reviews. + +## Pre-Review + +- [ ] PR has a clear title and description +- [ ] All CI checks are passing +- [ ] No merge conflicts exist +- [ ] PR is not a draft + +## Code Quality + +- [ ] Code follows project style guidelines +- [ ] No unnecessary commented-out code +- [ ] No debug statements or console.logs +- [ ] Functions and variables have clear names +- [ ] Complex logic has explanatory comments +- [ ] No hardcoded values that should be constants + +## Functionality + +- [ ] Code does what the PR description says +- [ ] Edge cases are handled +- [ ] Error handling is appropriate +- [ ] No obvious bugs or logic errors +- [ ] Performance considerations addressed + +## Testing + +- [ ] New features have tests +- [ ] Tests cover edge cases +- [ ] All tests pass locally and in CI +- [ ] Test names clearly describe what they test + +## Documentation + +- [ ] README updated if needed +- [ ] API documentation updated +- [ ] Inline comments for complex logic +- [ ] Breaking changes documented + +## Security + +- [ ] No sensitive data in code +- [ ] Input validation present +- [ ] Authentication/authorization correct +- [ ] Dependencies are up to date + +## Final Steps + +- [ ] Leave constructive feedback +- [ ] Approve or request changes +- [ ] Follow up on previous review comments diff --git a/test-playbooks/example-setup.md b/test-playbooks/example-setup.md new file mode 100644 index 0000000..654e324 --- /dev/null +++ b/test-playbooks/example-setup.md @@ -0,0 +1,58 @@ +# Development Environment Setup + +This playbook guides you through setting up the development environment for our project. + +## Prerequisites + +Before starting, ensure you have: +- Git installed and configured +- Node.js 18 or higher +- Docker Desktop installed +- Access to the repository + +## Installation Steps + +1. Clone the repository: + ```bash + git clone https://github.com/org/repo.git + cd repo + ``` + +2. Install dependencies: + ```bash + npm install + ``` + +3. Copy environment variables: + ```bash + cp .env.example .env + ``` + +4. Configure your local environment: + - Update DATABASE_URL in .env + - Set API_KEY from the team secrets manager + - Configure any required service credentials + +5. Start the development server: + ```bash + npm run dev + ``` + +6. Verify the setup: + - Open http://localhost:3000 + - Run tests: `npm test` + - Check linting: `npm run lint` + +## Troubleshooting + +If you encounter issues: +- Clear node_modules and reinstall: `rm -rf node_modules && npm install` +- Verify Docker is running: `docker ps` +- Check Node version: `node --version` (should be 18+) + +## Next Steps + +After setup: +- Read the CONTRIBUTING.md guide +- Join the team Slack channel +- Attend the onboarding session From c6f93b2a2ae21aa90d4a9d42da326ea97187b7c5 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 01:29:34 +0000 Subject: [PATCH 2/2] Fix CI failures: redirect logs to stderr and fix arithmetic increments - Redirect all log function output to stderr to prevent mixing with stdout data - Change arithmetic increments from ((var++)) to var=$((var + 1)) to avoid exit code 1 with set -e - Ensures script completes successfully when processing multiple files Fixes: - Test Dry Run Mode failure - script now processes all files and exits with code 0 - Test List Operation failure - log messages no longer interfere with JSON parsing - Both test playbooks are now successfully processed in dry-run mode Co-Authored-By: Sam Fertig --- scripts/sync-playbooks.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/sync-playbooks.sh b/scripts/sync-playbooks.sh index 8af2a8c..30a0a0f 100755 --- a/scripts/sync-playbooks.sh +++ b/scripts/sync-playbooks.sh @@ -9,19 +9,19 @@ BLUE='\033[0;34m' NC='\033[0m' log_info() { - echo -e "${BLUE}โ„น${NC} $1" + echo -e "${BLUE}โ„น${NC} $1" >&2 } log_success() { - echo -e "${GREEN}โœ“${NC} $1" + echo -e "${GREEN}โœ“${NC} $1" >&2 } log_warning() { - echo -e "${YELLOW}โš ${NC} $1" + echo -e "${YELLOW}โš ${NC} $1" >&2 } log_error() { - echo -e "${RED}โœ—${NC} $1" + echo -e "${RED}โœ—${NC} $1" >&2 } api_call() { @@ -252,9 +252,9 @@ sync_markdown_files() { while IFS= read -r file; do if [ -n "$file" ]; then if create_playbook "$file"; then - ((success_count++)) + success_count=$((success_count + 1)) else - ((failed_count++)) + failed_count=$((failed_count + 1)) fi fi done <<< "$md_files"