Skip to main content

Custom Action Templates

When you want to share consistent behavior across multiple repositories, storing templates in a custom GitHub Action is a great practice. This approach allows you to centralize management, reuse templates, and ensure consistency across projects.

You:

Is there a way, or is it a good practice, to perhaps store templates in a custom action so that they can be consumed by multiple repositories?


ChatGPT:

"Storing templates in a custom GitHub Action is not only possible, but it’s a great practice for scenarios where you want to share consistent behavior across multiple repositories while maintaining centralized control. It keeps everything modular, reusable, and easy to maintain."

Here’s how you can set it up:


Advantages of Storing Templates in a Custom Action

  1. Centralized Management:

    • All templates live in one place, reducing redundancy and ensuring consistency across repositories.
  2. Reusable Across Repositories:

    • Multiple repositories can consume the same templates without duplicating configuration files.
  3. Dynamic Updates:

    • Updating templates in the action automatically propagates changes to all consuming repositories.
  4. Improved Modularity:

    • The action acts as a single source of truth for templates, making it easier to maintain.

How to Store Templates in a Custom Action

1. Create a Custom GitHub Action Repository

Set up a dedicated repository for your custom action that includes templates.

Repository Structure

.
├── action.yml # Metadata for the GitHub Action
├── templates/ # Directory to store templates
│ ├── commentTemplates.json
│ ├── suggestionTemplates.json
│ └── workflowTemplates.yaml
├── src/ # Logic for the GitHub Action
│ └── index.js
├── package.json # Dependencies for the action
└── README.md # Documentation for the action

2. Add Templates to the Action

Example: templates/commentTemplates.json

{
"complexity": "The function at lines {startLine}-{endLine} exceeds the maximum cyclomatic complexity. Refactor to improve maintainability.",
"coverage": "Test coverage is below the required threshold of {minCoverage}%. Add tests to improve coverage.",
"positiveFeedback": "Great job implementing the feature `{featureName}`! The structure is clean and follows best practices."
}

Example: templates/suggestionTemplates.json

{
"lintFix": "Here’s a suggested linting fix for `{fileName}` at line {lineNumber}:",
"securityRisk": "The use of `{dependencyName}` could pose security risks. Consider replacing it with `{recommendedDependency}`."
}

3. Define the Custom Action (action.yml)

The action should provide a way to access these templates programmatically.

action.yml

name: "AIPR ReviewBot Template Action"
description: "Centralized repository for shared AIPR ReviewBot templates."
inputs:
templateName:
description: "The name of the template file to retrieve (e.g., 'commentTemplates')."
required: true
outputs:
templateContent:
description: "The content of the requested template in JSON format."
runs:
using: "node16"
main: "src/index.js"

4. Implement the Action Logic

Write the logic to serve templates dynamically from the templates/ directory.

src/index.js

const fs = require('fs');
const path = require('path');

async function run() {
try {
const templateName = process.env.INPUT_TEMPLATE_NAME;

// Locate the requested template file
const templatePath = path.join(__dirname, '..', 'templates', `${templateName}.json`);
if (!fs.existsSync(templatePath)) {
throw new Error(`Template file ${templateName}.json not found.`);
}

// Read and output the template content
const templateContent = fs.readFileSync(templatePath, 'utf8');
console.log(`::set-output name=templateContent::${templateContent}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
}

run();

5. Use the Custom Action in Repositories

Example Workflow

Repositories consuming the action can retrieve and use templates dynamically.

name: AI-Powered PR Review

on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest

steps:
# Step 1: Use the custom action to fetch templates
- name: Fetch Comment Templates
id: fetch-templates
uses: your-org/aipr-template-action@v1
with:
templateName: "commentTemplates"

# Step 2: Checkout code
- name: Checkout code
uses: actions/checkout@v3

# Step 3: Run AIPR ReviewBot
- name: Run AIPR ReviewBot
env:
COMMENT_TEMPLATES: ${{ steps.fetch-templates.outputs.templateContent }}
run: |
echo "Using templates: $COMMENT_TEMPLATES"
node review.js

6. Dynamically Use Templates in Your Bot

Access Templates During Runtime

Use the fetched templates dynamically in your bot logic.

const templates = JSON.parse(process.env.COMMENT_TEMPLATES);

// Example usage
function generateComplexityComment(startLine, endLine, maxComplexity) {
const template = templates.complexity;
return template
.replace('{startLine}', startLine)
.replace('{endLine}', endLine)
.replace('{maxComplexity}', maxComplexity);
}

// Generate a comment
const comment = generateComplexityComment(10, 20, 10);
console.log(comment);

Benefits of This Approach

  1. Centralized Updates:

    • Update templates in the action repository, and all consuming repositories automatically get the latest version.
  2. Reusable Across Projects:

    • No need to duplicate configuration files across multiple repositories.
  3. Dynamic Access:

    • Fetch only the templates needed for a specific workflow or use case.
  4. Versioning:

    • Tag releases in the action repository, allowing consuming repositories to lock specific versions if needed.

Advanced: Automate Setup for New Repositories

You can go one step further by automating the setup of workflows that use the custom action.

Bootstrapping Workflow Example

Create a GitHub workflow that initializes the AIPR ReviewBot for new repositories with the custom action preconfigured.

name: Bootstrap AIPR ReviewBot

on:
repository_dispatch:
types: [initialize-aipr]

jobs:
setup-bot:
runs-on: ubuntu-latest

steps:
- name: Checkout config
uses: actions/checkout@v3

- name: Create Workflow
run: |
echo "Creating AIPR Review workflow..."
mkdir -p .github/workflows
cat > .github/workflows/aipr-review.yml <<EOL
name: AI-Powered PR Review

on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest

steps:
- name: Fetch Comment Templates
id: fetch-templates
uses: your-org/aipr-template-action@v1
with:
templateName: "commentTemplates"

- name: Checkout code
uses: actions/checkout@v3

- name: Run AIPR ReviewBot
env:
COMMENT_TEMPLATES: \${{ steps.fetch-templates.outputs.templateContent }}
run: node review.js
EOL

Best Practices