Skip to content

GitHub Actions

Unentropy provides two GitHub Actions for automated metrics tracking and quality enforcement.

ActionPurposeContext
track-metricsCollect and store metricsMain branch pushes
quality-gateEvaluate PR against thresholdsPull requests

Collects metrics, updates the database, and generates reports. Runs on main branch to build historical data.

name: Track Metrics
on:
  push:
    branches: [main]

jobs:
  metrics:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: unentropy/track-metrics-action@v1

Type: string
Default: sqlite-local
Values: sqlite-local, sqlite-artifact, sqlite-s3

Storage backend for the metrics database.

- uses: unentropy/track-metrics-action@v1
  with:
    storage-type: sqlite-artifact

Required when storage-type is sqlite-s3:

Type: string
Required: Yes (for S3)

S3-compatible endpoint URL.

s3-endpoint: https://s3.amazonaws.com
s3-endpoint: https://<account-id>.r2.cloudflarestorage.com

Type: string
Required: Yes (for S3)

S3 bucket name.

s3-bucket: my-metrics-bucket

Type: string
Required: Yes (for S3)

S3 region.

s3-region: us-east-1
s3-region: auto  # Cloudflare R2

Type: string
Required: Yes (for S3)

S3 access key ID from GitHub Secrets.

s3-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }}

Type: string
Required: Yes (for S3)

S3 secret access key from GitHub Secrets.

s3-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }}

Used when storage-type is sqlite-artifact:

Type: string
Default: unentropy-metrics

Name of the database artifact.

artifact-name: my-project-metrics

Type: string
Default: ${{ github.ref_name }}

Branch to search for previous artifacts.

artifact-branch-filter: main

Type: string
Default: unentropy.json

Path to configuration file.

config-file: custom-config.json

Type: string
Default: unentropy-metrics.db

Database file key in storage.

database-key: production/metrics.db

Type: string
Default: index.html

Generated report filename.

report-name: metrics-report.html

Type: boolean

Whether workflow completed successfully.

- name: Check success
  if: steps.metrics.outputs.success == 'true'
  run: echo "Metrics collected"

Type: string

Storage backend type used.

Type: string

Database storage location identifier.

Type: string

Database file size in bytes.

Type: number

Number of metrics collected.

Type: number

Total workflow duration in milliseconds.

Type: string
Available: Artifact storage only

Workflow run ID where previous artifact was found.

Type: string
Available: Artifact storage only

ID of uploaded database artifact.

name: Track Metrics
on:
  push:
    branches: [main]

jobs:
  metrics:
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
    steps:
      - uses: actions/checkout@v4

      - name: Run tests with coverage
        run: bun test --coverage

      - name: Track metrics
        uses: unentropy/track-metrics-action@v1
        with:
          storage-type: sqlite-artifact

      - name: Upload report
        uses: actions/upload-artifact@v4
        with:
          name: metrics-report
          path: index.html
name: Track Metrics
on:
  push:
    branches: [main]

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

      - name: Run tests with coverage
        run: bun test --coverage

      - name: Track metrics
        uses: unentropy/track-metrics-action@v1
        with:
          storage-type: sqlite-s3
          s3-endpoint: ${{ secrets.S3_ENDPOINT }}
          s3-bucket: ${{ secrets.S3_BUCKET }}
          s3-region: ${{ secrets.S3_REGION }}
          s3-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }}
          s3-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }}

      - name: Upload report
        uses: actions/upload-artifact@v4
        with:
          name: metrics-report
          path: index.html

Evaluates PR metrics against baseline thresholds and posts results. Runs on pull requests.

name: Quality Gate
on:
  pull_request:

jobs:
  gate:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: unentropy/quality-gate-action@v1

Type: string
Default: sqlite-s3
Values: sqlite-local, sqlite-artifact, sqlite-s3

Storage backend where baseline database is stored. Must match the storage used by track-metrics.

- uses: unentropy/quality-gate-action@v1
  with:
    storage-type: sqlite-s3

Same as track-metrics action. Required when storage-type is sqlite-s3.

See track-metrics S3 inputs.

Type: string
Default: unentropy.json

Path to configuration file.

config-file: custom-config.json

Type: string
Default: unentropy.db

Database file key in storage. Must match the key used by track-metrics.

database-key: production/metrics.db

Type: string
Values: off, soft, hard

Override quality gate mode from config file:

  • off: Skip evaluation
  • soft: Evaluate and comment, don’t fail build
  • hard: Fail build on threshold violations
quality-gate-mode: soft

Type: boolean
Default: true

Post/update PR comment with results.

enable-pr-comment: true

Type: string
Default: <!-- unentropy-quality-gate -->

HTML marker to identify quality gate comment.

pr-comment-marker: <!-- my-custom-marker -->

Type: number
Default: 30

Maximum metrics to show in PR comment.

max-pr-comment-metrics: 50

Type: string
Default: .unentropy/quality-gate-results.json

Path to write the structured JSON results file (relative to workspace). The file contains the complete quality gate evaluation data in machine-readable format.

output-file: reports/quality-gate.json

Type: string
Values: pass, fail, unknown

Overall gate status.

- name: Check gate
  if: steps.gate.outputs.quality-gate-status == 'fail'
  run: echo "Quality gate failed"

Type: string

Gate mode used.

Type: string

Comma-separated list of failing metric names.

- name: Log failures
  if: steps.gate.outputs.quality-gate-status == 'fail'
  run: echo "Failed: ${{ steps.gate.outputs.quality-gate-failing-metrics }}"

Type: string

URL of the PR comment (if created).

Type: number

Number of metrics collected from PR.

Type: number

Number of baseline builds used for comparison.

Type: string

Reference branch used for baseline.

Type: string

Absolute path to the written JSON results file.

- name: Upload results
  uses: actions/upload-artifact@v4
  with:
    name: quality-gate-results
    path: ${{ steps.gate.outputs.quality-gate-results-path }}

Type: string

Full quality gate result as a JSON string. Usable with fromJSON() in workflow expressions.

- name: Check failing metrics
  run: |
    echo "Failing: ${{ fromJSON(steps.gate.outputs.quality-gate-results-json).qualityGate.failingCount }}"
name: Quality Gate
on:
  pull_request:

jobs:
  gate:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      - name: Run tests with coverage
        run: bun test --coverage

      - name: Quality gate
        uses: unentropy/quality-gate-action@v1
        with:
          storage-type: sqlite-s3
          quality-gate-mode: soft
          s3-endpoint: ${{ secrets.S3_ENDPOINT }}
          s3-bucket: ${{ secrets.S3_BUCKET }}
          s3-region: ${{ secrets.S3_REGION }}
          s3-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }}
          s3-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }}
name: Quality Gate
on:
  pull_request:

jobs:
  gate:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      actions: read
    steps:
      - uses: actions/checkout@v4

      - name: Run tests with coverage
        run: bun test --coverage

      - name: Quality gate
        uses: unentropy/quality-gate-action@v1
        with:
          storage-type: sqlite-artifact
          quality-gate-mode: hard

Use structured output in downstream steps or external tools:

name: Quality Gate
on:
  pull_request:

jobs:
  gate:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      - name: Run tests with coverage
        run: bun test --coverage

      - name: Quality gate
        uses: unentropy/quality-gate-action@v1
        id: gate

      - name: Access full result via fromJSON
        run: |
          echo "Status: ${{ fromJSON(steps.gate.outputs.quality-gate-results-json).qualityGate.status }}"
          echo "Evaluated: ${{ fromJSON(steps.gate.outputs.quality-gate-results-json).qualityGate.summary.evaluatedMetrics }}"

      - name: Upload results as artifact
        uses: actions/upload-artifact@v4
        with:
          name: quality-gate-results
          path: ${{ steps.gate.outputs.quality-gate-results-path }}

Both actions need:

permissions:
  actions: read # Download artifacts
  contents: read # Checkout repository

Quality gate also needs:

permissions:
  pull-requests: write # Post PR comments
permissions:
  contents: read # Checkout repository

Quality gate also needs:

permissions:
  pull-requests: write # Post PR comments

S3 access is controlled via credentials, not GitHub permissions.

Main branch + PR workflows together:

# .github/workflows/metrics.yml
name: Metrics
on:
  push:
    branches: [main]

jobs:
  track-metrics:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: bun test --coverage
      - uses: unentropy/track-metrics-action@v1
        with:
          storage-type: sqlite-s3
          s3-endpoint: ${{ secrets.S3_ENDPOINT }}
          s3-bucket: ${{ secrets.S3_BUCKET }}
          s3-region: ${{ secrets.S3_REGION }}
          s3-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }}
          s3-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }}
# .github/workflows/quality-gate.yml
name: Quality Gate
on:
  pull_request:

jobs:
  quality-gate:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: bun test --coverage
      - uses: unentropy/quality-gate-action@v1
        with:
          storage-type: sqlite-s3
          quality-gate-mode: soft
          s3-endpoint: ${{ secrets.S3_ENDPOINT }}
          s3-bucket: ${{ secrets.S3_BUCKET }}
          s3-region: ${{ secrets.S3_REGION }}
          s3-access-key-id: ${{ secrets.S3_ACCESS_KEY_ID }}
          s3-secret-access-key: ${{ secrets.S3_SECRET_ACCESS_KEY }}
  • All S3 credentials must come from GitHub Secrets
  • Credentials are never logged or exposed in error messages
  • GITHUB_TOKEN is auto-detected for artifact operations
  • PR comments contain only metric values, no sensitive data