GitHub Actions Tutorial — Project: Custom Action

1 minute read

Project: Custom Action — PR Comment Bot

Build a composite action that posts a formatted comment on pull requests with build status, test results, and a link to the deployment preview.


Requirements

Feature Implementation
Composite action action.yml with using: composite
Inputs build-status, test-count, preview-url
Uses GitHub API gh CLI to post comments
Publishable Has branding and README
Tested CI workflow tests the action

Project Structure

pr-comment-action/
├── action.yml
├── comment.sh
├── .github/
│   └── workflows/
│       └── test.yml
├── README.md
└── LICENSE

action.yml


name: 'PR Comment Bot'
description: 'Posts a formatted build status comment on pull requests'
author: 'my-org'

branding:
  icon: 'message-square'
  color: 'blue'

inputs:
  build-status:
    description: 'Build status (success/failure)'
    required: true
  test-count:
    description: 'Number of tests passed'
    required: false
    default: '0'
  preview-url:
    description: 'Preview deployment URL'
    required: false
    default: ''
  github-token:
    description: 'GitHub token for posting comments'
    required: true

runs:
  using: 'composite'
  steps:
    - name: Post comment
      env:
        BUILD_STATUS: ${{ inputs.build-status }}
        TEST_COUNT: ${{ inputs.test-count }}
        PREVIEW_URL: ${{ inputs.preview-url }}
        GH_TOKEN: ${{ inputs.github-token }}
        PR_NUMBER: ${{ github.event.pull_request.number }}
        REPO: ${{ github.repository }}
      run: bash ${{ github.action_path }}/comment.sh
      shell: bash


comment.sh

#!/bin/bash
set -e

if [ "$BUILD_STATUS" = "success" ]; then
  ICON="✅"
else
  ICON="❌"
fi

BODY="## ${ICON} Build Report

| Metric | Value |
|--------|-------|
| **Status** | ${BUILD_STATUS} |
| **Tests** | ${TEST_COUNT} passed |"

if [ -n "$PREVIEW_URL" ]; then
  BODY="${BODY}
| **Preview** | [Open Preview](${PREVIEW_URL}) |"
fi

BODY="${BODY}

---
*Posted by PR Comment Bot*"

gh pr comment "$PR_NUMBER" --repo "$REPO" --body "$BODY"

Test Workflow

.github/workflows/test.yml:


name: Test Action

on:
  pull_request:

permissions:
  pull-requests: write

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Test the action
        uses: ./
        with:
          build-status: 'success'
          test-count: '42'
          preview-url: 'https://preview.example.com'
          github-token: ${{ secrets.GITHUB_TOKEN }}


Publishing

  1. Push to a public repository
  2. Create a release: git tag v1.0.0 && git push origin v1.0.0
  3. Create the v1 tag: git tag -fa v1 v1.0.0 && git push origin v1 --force
  4. In GitHub Releases, check “Publish to Marketplace”

Usage by others:


- uses: my-org/pr-comment-action@v1
  with:
    build-status: 'success'
    test-count: '42'
    github-token: ${{ secrets.GITHUB_TOKEN }}


Design Decisions

Decision Reasoning
Composite (not JavaScript) Simpler — no build step, no node_modules
gh CLI for comments Pre-installed on GitHub runners; simpler than REST API
External script Bash in action.yml is hard to maintain; separate file is testable
Token as input Explicit — caller decides which token to use

← Previous: Project — Reusable Library

Next: Practice Exercises →

Updated: