Track GitHub Reusable Workflow Usage with Custom Tags
This product is not supported for your selected
Datadog site. (
).
Overview
GitHub Reusable Workflows allow organizations to centralize CI/CD logic in shared workflow files that are called from other repositories. As usage grows, it becomes difficult to track which repositories are using specific versions of a reusable workflow, or when callers are pinned to outdated refs.
CI Visibility does not automatically extract reusable workflow metadata (such as version, ref, or source repository). However, you can use custom tags to attach this information to your pipeline and job spans, enabling you to build dashboards, monitors, and queries to track reusable workflow usage across your organization.
Prerequisites
The most reliable way to tag reusable workflow metadata is to add a tagging step inside the reusable workflow itself, so every caller automatically gets the tags.
The GitHub Actions job context exposes the identity of the workflow file that defines the current job. When the step runs inside a reusable workflow, these properties resolve to the called workflow. (The github.workflow_ref context, by contrast, resolves to the caller workflow’s ref.) You can read them directly from the context:
Reusable workflow:
# my-org/shared-workflows/.github/workflows/build.yml
name: Shared Build Workflow
on:
workflow_call:
inputs:
build-target:
required: true
type: string
secrets:
DD_API_KEY:
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Tag reusable workflow metadata in CI Visibility
env:
DATADOG_API_KEY: ${{ secrets.DD_API_KEY }}
DATADOG_SITE:
run: |
npx @datadog/datadog-ci tag --level job \
--tags "reusable_workflow.ref:${{ job.workflow_ref }}" \
--tags "reusable_workflow.sha:${{ job.workflow_sha }}" \
--tags "reusable_workflow.repo:${{ job.workflow_repository }}" \
--tags "reusable_workflow.file_path:${{ job.workflow_file_path }}" \
--tags "reusable_workflow.caller_repo:${{ github.repository }}"
- name: Build
run: echo "Building ${{ inputs.build-target }}"
Caller workflow:
# In a caller repository's workflow
name: CI
on: [push]
jobs:
call-shared-build:
uses: my-org/shared-workflows/.github/workflows/[email protected]
with:
build-target: production
secrets:
DD_API_KEY: ${{ secrets.DD_API_KEY }}
This produces the following tags on the job span:
| Tag | Example value | Description |
|---|
reusable_workflow.ref | my-org/shared-workflows/.github/workflows/build.yml@refs/tags/v2.1.0 | The full ref of the called workflow file, including the repository, path, and Git ref. |
reusable_workflow.sha | a1b2c3d4e5f67890abcdef1234567890abcdef12 | The commit SHA of the called workflow file. |
reusable_workflow.repo | my-org/shared-workflows | The owner/repo of the repository containing the called workflow. |
reusable_workflow.file_path | .github/workflows/build.yml | The path to the called workflow file, relative to its repository root. |
reusable_workflow.caller_repo | my-org/frontend-app | The repository that called the reusable workflow. |
Note: The job.workflow_* context properties require GitHub Actions runner v2.334.0 or later. For self-hosted runners on older versions, see Use the REST API as a fallback.
Use the REST API as a fallback
If your self-hosted runners are on a version earlier than v2.334.0, query the GitHub Actions REST API from within the workflow to look up the referenced_workflows for the current run:
- name: Tag reusable workflow metadata in CI Visibility
env:
DATADOG_API_KEY: ${{ secrets.DD_API_KEY }}
DATADOG_SITE:
GH_TOKEN: ${{ github.token }}
run: |
# Look up the reusable workflow ref from the GitHub API
WORKFLOW_REF=$(gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }} \
--jq '.referenced_workflows[0] | "\(.path)@\(.ref)"')
# Extract the version or branch ref (the part after '@')
WORKFLOW_VERSION="${WORKFLOW_REF##*@}"
# Extract the workflow path (the part before '@')
WORKFLOW_PATH="${WORKFLOW_REF%%@*}"
# Extract the source repository
WORKFLOW_REPO="${WORKFLOW_PATH%%/.github/*}"
npx @datadog/datadog-ci tag --level job \
--tags "reusable_workflow.ref:${WORKFLOW_VERSION}" \
--tags "reusable_workflow.path:${WORKFLOW_PATH}" \
--tags "reusable_workflow.repo:${WORKFLOW_REPO}" \
--tags "reusable_workflow.caller_repo:${{ github.repository }}"
If you cannot modify the shared workflow, you can tag the metadata from a separate job in the caller workflow instead. The job.workflow_* context properties resolve to the caller’s own workflow file in this case, so use the GitHub Actions REST API to look up the called workflow’s ref:
# In a caller repository's workflow
name: CI
on: [push]
jobs:
call-shared-build:
uses: my-org/shared-workflows/.github/workflows/[email protected]
with:
build-target: production
secrets: inherit
tag-workflow-metadata:
runs-on: ubuntu-latest
needs: call-shared-build
steps:
- name: Tag reusable workflow version
env:
DATADOG_API_KEY: ${{ secrets.DD_API_KEY }}
DATADOG_SITE:
GH_TOKEN: ${{ github.token }}
run: |
WORKFLOW_REF=$(gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }} \
--jq '.referenced_workflows[0] | "\(.path)@\(.ref)"')
WORKFLOW_VERSION="${WORKFLOW_REF##*@}"
WORKFLOW_PATH="${WORKFLOW_REF%%@*}"
WORKFLOW_REPO="${WORKFLOW_PATH%%/.github/*}"
npx @datadog/datadog-ci tag --level pipeline \
--tags "reusable_workflow.ref:${WORKFLOW_VERSION}" \
--tags "reusable_workflow.path:${WORKFLOW_PATH}" \
--tags "reusable_workflow.repo:${WORKFLOW_REPO}"
If your reusable workflow accepts inputs that affect build behavior (for example, target environment, feature flags, or runtime version), you can tag those as well to understand how the workflow is being invoked:
- name: Tag workflow inputs
env:
DATADOG_API_KEY: ${{ secrets.DD_API_KEY }}
DATADOG_SITE:
run: |
npx @datadog/datadog-ci tag --level job \
--tags "reusable_workflow.input.build_target:${{ inputs.build-target }}"
Further reading
Additional helpful documentation, links, and articles: