name: 'Rust PR Diff Analyzer'
description: 'Analyze and limit PR size by distinguishing production code from test code using Rust AST analysis'
author: 'RAprogramm'
branding:
icon: 'code'
color: 'orange'
inputs:
max_prod_units:
description: 'Maximum number of production units allowed'
required: false
default: '30'
max_weighted_score:
description: 'Maximum weighted score allowed'
required: false
default: '100'
max_prod_lines:
description: 'Maximum production lines added'
required: false
default: ''
fail_on_exceed:
description: 'Fail the action if limits are exceeded'
required: false
default: 'true'
output_format:
description: 'Output format (github, json, human)'
required: false
default: 'github'
config_file:
description: 'Path to configuration file'
required: false
default: ''
post_comment:
description: 'Post analysis as PR comment'
required: false
default: 'false'
update_comment:
description: 'Update existing comment instead of creating new'
required: false
default: 'true'
outputs:
prod_functions_changed:
description: 'Number of production functions changed'
value: ${{ steps.analyze.outputs.prod_functions_changed }}
prod_structs_changed:
description: 'Number of production structs changed'
value: ${{ steps.analyze.outputs.prod_structs_changed }}
prod_other_changed:
description: 'Number of other production units changed'
value: ${{ steps.analyze.outputs.prod_other_changed }}
test_units_changed:
description: 'Number of test units changed'
value: ${{ steps.analyze.outputs.test_units_changed }}
prod_lines_added:
description: 'Lines added in production code'
value: ${{ steps.analyze.outputs.prod_lines_added }}
prod_lines_removed:
description: 'Lines removed from production code'
value: ${{ steps.analyze.outputs.prod_lines_removed }}
test_lines_added:
description: 'Lines added in test code'
value: ${{ steps.analyze.outputs.test_lines_added }}
test_lines_removed:
description: 'Lines removed from test code'
value: ${{ steps.analyze.outputs.test_lines_removed }}
weighted_score:
description: 'Weighted score of changes'
value: ${{ steps.analyze.outputs.weighted_score }}
exceeds_limit:
description: 'Whether limits were exceeded'
value: ${{ steps.analyze.outputs.exceeds_limit }}
runs:
using: 'composite'
steps:
- name: Get PR diff
id: get_diff
shell: bash
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
git fetch origin ${{ github.base_ref }} --depth=1
git diff origin/${{ github.base_ref }}...HEAD > /tmp/pr_diff.txt
else
git diff HEAD~1 > /tmp/pr_diff.txt
fi
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Build analyzer
shell: bash
run: |
cd ${{ github.action_path }}
cargo build --release
- name: Run analysis
id: analyze
shell: bash
run: |
ARGS="--diff-file /tmp/pr_diff.txt"
ARGS="$ARGS --max-units ${{ inputs.max_prod_units }}"
ARGS="$ARGS --max-score ${{ inputs.max_weighted_score }}"
ARGS="$ARGS --format ${{ inputs.output_format }}"
ARGS="$ARGS --no-fail"
if [ -n "${{ inputs.max_prod_lines }}" ]; then
ARGS="$ARGS --max-lines ${{ inputs.max_prod_lines }}"
fi
if [ -n "${{ inputs.config_file }}" ]; then
ARGS="$ARGS --config ${{ inputs.config_file }}"
fi
OUTPUT=$(${{ github.action_path }}/target/release/rust-diff-analyzer $ARGS)
echo "$OUTPUT"
if [ "${{ inputs.output_format }}" = "github" ]; then
echo "$OUTPUT" >> $GITHUB_OUTPUT
fi
if echo "$OUTPUT" | grep -q "exceeds_limit=true"; then
echo "EXCEEDS_LIMIT=true" >> $GITHUB_ENV
else
echo "EXCEEDS_LIMIT=false" >> $GITHUB_ENV
fi
- name: Post PR comment
if: inputs.post_comment == 'true' && github.event_name == 'pull_request'
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
ARGS="--diff-file /tmp/pr_diff.txt"
ARGS="$ARGS --max-units ${{ inputs.max_prod_units }}"
ARGS="$ARGS --max-score ${{ inputs.max_weighted_score }}"
ARGS="$ARGS --format comment"
ARGS="$ARGS --no-fail"
if [ -n "${{ inputs.max_prod_lines }}" ]; then
ARGS="$ARGS --max-lines ${{ inputs.max_prod_lines }}"
fi
if [ -n "${{ inputs.config_file }}" ]; then
ARGS="$ARGS --config ${{ inputs.config_file }}"
fi
COMMENT=$(${{ github.action_path }}/target/release/rust-diff-analyzer $ARGS)
MARKER="<!-- rust-diff-analyzer-comment -->"
PR_NUMBER=${{ github.event.pull_request.number }}
if [ "${{ inputs.update_comment }}" = "true" ]; then
EXISTING=$(gh api repos/${{ github.repository }}/issues/${PR_NUMBER}/comments \
--jq ".[] | select(.body | contains(\"${MARKER}\")) | .id" | head -1)
if [ -n "$EXISTING" ]; then
gh api repos/${{ github.repository }}/issues/comments/${EXISTING} \
-X PATCH -f body="$COMMENT"
echo "Updated existing comment"
else
gh pr comment $PR_NUMBER --body "$COMMENT"
echo "Created new comment"
fi
else
gh pr comment $PR_NUMBER --body "$COMMENT"
echo "Created new comment"
fi
- name: Fail if limits exceeded
if: env.EXCEEDS_LIMIT == 'true' && inputs.fail_on_exceed == 'true'
shell: bash
run: |
echo "::error::Production code changes exceed configured limits"
exit 1