Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/actions/collect-format-results/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: "Collect Format Results"
description: "Aggregates results from multiple formatting jobs and creates a summary comment."
inputs:
results-json:
description: "JSON object containing job results"
required: true

outputs:
message:
description: "The formatted summary message"
value: ${{ steps.collect.outputs.message }}
has_failures:
description: "Whether any job failed"
value: ${{ steps.collect.outputs.has_failures }}

runs:
using: "composite"
steps:
- name: Aggregate results
id: collect
shell: bash
run: |
echo "results<<EOF" >> $GITHUB_ENV
echo '${{ inputs.results-json }}' >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV

# In a real script we would parse the JSON, but for a composite action
# we can pass pre-formatted data. To keep it simple and robust,
# let's assume the caller provides a bash-friendly format or we use python.

python3 -c "
import json, os
data = json.loads(os.environ['results'])
messages = []
has_failures = False
for name, res in data.items():
if res['result'] in ['failure', 'cancelled', 'skipped']:
messages.append(f'❌ {name} workflow {res[\"result\"]}')
has_failures = True
elif res.get('changes') == 'true':
if res.get('pushed') == 'true':
messages.append(f'✅ {name} fixes pushed (commit {res.get(\"sha\", \"\")})')
elif res.get('patch_name'):
messages.append(f'⚠️ {name} fixes available as patch {res.get(\"patch_name\")}')

output_msg = 'No automatic format fixes were necessary.'
if messages:
output_msg = '### Format Fixes Applied\n' + '\n'.join(messages) + '\n\n⚠️ **Note:** Some issues may require manual review.'

with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write(f'message<<EOF\n{output_msg}\nEOF\n')
f.write(f'has_failures={str(has_failures).lower()}\n')
"
57 changes: 57 additions & 0 deletions .github/actions/complete-pr-comment/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: "Complete PR Comment"
description: >-
Removes the 'eyes' reaction and adds a completion reaction ('rocket' for success, 'confused' for 'failure',
'cancelled', or 'skipped') to the triggering comment. Requires `issues: write` permission in the calling workflow to
update comment reactions via the GitHub Reactions API.
inputs:
status:
description:
"The status of the workflow. If 'success', a 'rocket' reaction is added. For any non-success status (including
'failure', 'cancelled', or 'skipped'), a 'confused' reaction is added. Defaults to 'success'."
required: false
default: "success"

runs:
using: "composite"
steps:
- name: Update PR Comment Reactions
if: github.event_name == 'issue_comment'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const status = '${{ inputs.status }}';
const completionReaction = (status === 'success') ? 'rocket' : 'confused';

// 1. Remove "eyes" reaction
try {
const { data: reactions } = await github.rest.reactions.listForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id
});
const eyesReaction = reactions.find(
(r) => r.content === 'eyes' && r.user && r.user.login === 'github-actions[bot]'
);
if (eyesReaction) {
await github.rest.reactions.deleteForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
reaction_id: eyesReaction.id
});
}
} catch (e) {
core.warning(`Failed to remove "eyes" reaction: ${e.message}`);
}

// 2. Add completion reaction
try {
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: completionReaction
});
} catch (e) {
core.warning(`Failed to add "${completionReaction}" reaction: ${e.message}`);
}
78 changes: 78 additions & 0 deletions .github/actions/post-clang-tidy-results/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: "Post Clang-Tidy Results"
description: "Consolidates Clang-Tidy artifacts and posts PR comments."
inputs:
build-path:
description: "Path where build artifacts are located"
required: true
pr-number:
description: "PR number for posting comments"
required: false
post-summary:
description: "Whether to post a summary comment (true/false)"
required: false
default: "false"

runs:
using: "composite"
steps:
- name: Download artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
pattern: clang-tidy-*
merge-multiple: true
continue-on-error: true

- name: Check if artifacts exist
id: check
shell: bash
run: |
if [ -f "${{ inputs.build-path }}/clang-tidy-fixes.yaml" ]; then
echo "has_fixes=true" >> "$GITHUB_OUTPUT"
else
echo "has_fixes=false" >> "$GITHUB_OUTPUT"
fi

- name: Post inline comments
if: steps.check.outputs.has_fixes == 'true' && inputs.pr-number != ''
uses: platisd/clang-tidy-pr-comments@28cfb84edafa771c044bde7e4a2a3fae57463818 # v1.8.0
with:
clang_tidy_fixes: ${{ inputs.build-path }}/clang-tidy-fixes.yaml
github_token: ${{ github.token }}
pull_request_id: ${{ inputs.pr-number }}

- name: Post summary comment
if: steps.check.outputs.has_fixes == 'true' && inputs.post-summary == 'true' && inputs.pr-number != ''
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const fs = require('fs');
const fixesFile = '${{ inputs.build-path }}/clang-tidy-fixes.yaml';

let totalIssues = 0;
const checkCounts = {};

if (fs.existsSync(fixesFile)) {
try {
const content = fs.readFileSync(fixesFile, 'utf8');
const matches = content.matchAll(/^\s*DiagnosticName:\s+(\S.+?)$/gm);
for (const match of matches) {
const name = match[1].trim();
checkCounts[name] = (checkCounts[name] || 0) + 1;
totalIssues++;
}
} catch (e) { console.log(e); }
}

if (totalIssues > 0) {
const sorted = Object.entries(checkCounts).sort((a, b) => b[1] - a[1]);
let body = `## Clang-Tidy Check Results\n\nFound ${totalIssues} issue(s).\n\n### Issues by check:\n\n`;
sorted.forEach(([check, count]) => { body += `- **${check}**: ${count}\n`; });
body += '\nSee inline comments for details. Comment `@phlexbot tidy-fix` to auto-fix.';

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ inputs.pr-number }},
body: body
});
}
97 changes: 97 additions & 0 deletions .github/actions/prepare-check-outputs/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: "Prepare Check Outputs"
description: "Determines environment and target refs for check workflows."
inputs:
ref:
description: "Manual ref override"
required: false
repo:
description: "Manual repo override"
required: false
pr-base-sha:
description: "Manual base SHA override"
required: false
checkout-path:
description: "Manual checkout path override"
required: false
build-path:
description: "Manual build path override"
required: false
outputs:
is_act:
description: "Whether running in act"
value: ${{ steps.detect_act.outputs.is_act }}
ref:
description: "The resolved ref"
value: ${{ steps.resolve.outputs.ref }}
repo:
description: "The resolved repository"
value: ${{ steps.resolve.outputs.repo }}
base_sha:
description: "The resolved base SHA for diffing"
value: ${{ steps.resolve.outputs.base_sha }}
pr_number:
description: "The PR number if available"
value: ${{ steps.resolve.outputs.pr_number }}
checkout_path:
description: "The resolved checkout path"
value: ${{ steps.resolve.outputs.checkout_path }}
build_path:
description: "The resolved build path"
value: ${{ steps.resolve.outputs.build_path }}
runs:
using: "composite"
steps:
- name: Get PR Info
if: github.event_name == 'issue_comment'
id: get_pr
uses: Framework-R-D/phlex/.github/actions/get-pr-info@main

- name: Detect act environment
id: detect_act
uses: Framework-R-D/phlex/.github/actions/detect-act-env@main

- name: Resolve outputs
id: resolve
shell: bash
run: |
REF="${{ inputs.ref }}"
REPO="${{ inputs.repo }}"
BASE_SHA="${{ inputs.pr-base-sha }}"
PR_NUMBER=""

if [ "${{ github.event_name }}" == "pull_request" ]; then
REF="${REF:-${{ github.sha }}}"
BASE_SHA="${BASE_SHA:-${{ github.event.pull_request.base.sha }}}"
PR_NUMBER="${{ github.event.pull_request.number }}"
elif [ "${{ github.event_name }}" == "issue_comment" ]; then
REF="${REF:-${{ steps.get_pr.outputs.ref }}}"
REPO="${REPO:-${{ steps.get_pr.outputs.repo }}}"
BASE_SHA="${BASE_SHA:-${{ steps.get_pr.outputs.base_sha }}}"
PR_NUMBER="${{ github.event.issue.number }}"
elif [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
REF="${REF:-${{ github.event.inputs.ref || github.ref }}}"
BASE_SHA="${BASE_SHA:-${{ github.event.before }}}"
else
REF="${REF:-${{ github.sha }}}"
BASE_SHA="${BASE_SHA:-${{ github.event.before }}}"
fi

REPO="${REPO:-${{ github.repository }}}"
REPO_NAME="${REPO##*/}"

CHECKOUT_PATH="${{ inputs.checkout-path }}"
if [ -z "$CHECKOUT_PATH" ]; then
CHECKOUT_PATH="${REPO_NAME}-src"
fi

BUILD_PATH="${{ inputs.build-path }}"
if [ -z "$BUILD_PATH" ]; then
BUILD_PATH="${REPO_NAME}-build"
fi

echo "ref=$REF" >> "$GITHUB_OUTPUT"
echo "repo=$REPO" >> "$GITHUB_OUTPUT"
echo "base_sha=$BASE_SHA" >> "$GITHUB_OUTPUT"
echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
echo "checkout_path=$CHECKOUT_PATH" >> "$GITHUB_OUTPUT"
echo "build_path=$BUILD_PATH" >> "$GITHUB_OUTPUT"
66 changes: 66 additions & 0 deletions .github/actions/prepare-fix-outputs/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: "Prepare Fix Outputs"
description: "Determines the target ref and repository for fix workflows triggered by various events."
inputs:
ref:
description: "Manual ref override"
required: false
repo:
description: "Manual repo override"
required: false
checkout-path:
description: "Manual checkout path override"
required: false
outputs:
ref:
description: "The resolved ref"
value: ${{ steps.resolve.outputs.ref }}
repo:
description: "The resolved repository"
value: ${{ steps.resolve.outputs.repo }}
checkout_path:
description: "The resolved checkout path"
value: ${{ steps.resolve.outputs.checkout_path }}
runs:
using: "composite"
steps:
- name: Get PR Info
if: github.event_name == 'issue_comment' && (inputs.ref == '' || inputs.repo == '')
id: get_pr
uses: Framework-R-D/phlex/.github/actions/get-pr-info@main

- name: Resolve outputs
id: resolve
shell: bash
run: |
REF="${{ inputs.ref }}"
REPO="${{ inputs.repo }}"

if [ -z "$REF" ]; then
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
REF="${{ github.event.inputs.ref || github.ref_name }}"
elif [ "${{ github.event_name }}" == "issue_comment" ]; then
REF="${{ steps.get_pr.outputs.ref }}"
else
REF="${{ github.ref_name }}"
fi
fi

if [ -z "$REPO" ]; then
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
REPO="${{ github.repository }}"
elif [ "${{ github.event_name }}" == "issue_comment" ]; then
REPO="${{ steps.get_pr.outputs.repo }}"
else
REPO="${{ github.repository }}"
fi
fi

REPO_NAME="${REPO##*/}"
CHECKOUT_PATH="${{ inputs.checkout-path }}"
if [ -z "$CHECKOUT_PATH" ]; then
CHECKOUT_PATH="${REPO_NAME}-src"
fi

echo "ref=$REF" >> "$GITHUB_OUTPUT"
echo "repo=$REPO" >> "$GITHUB_OUTPUT"
echo "checkout_path=$CHECKOUT_PATH" >> "$GITHUB_OUTPUT"
Loading
Loading