Skip to content

Add Multi Platform Sales Monitor #1083

Add Multi Platform Sales Monitor

Add Multi Platform Sales Monitor #1083

Workflow file for this run

name: Lint
on:
pull_request_target:
branches: [dev, main]
paths:
- '**.py'
jobs:
lint:
name: lint
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
statuses: write
steps:
- uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install linters
run: pip install flake8 autopep8 autoflake
# ── Get EXACT PR-changed files via GitHub API ──────────────
- name: Get changed Python files
id: changed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Fetch exact file list from the PR (not git diff)
ALL_FILES=$(curl -s \
-H "Authorization: token $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files?per_page=100" \
| jq -r '.[].filename' \
| grep '\.py$' \
| grep -E '^(community|official|templates)/' || true)
echo "πŸ“‹ PR changed Python files:"
echo "$ALL_FILES"
if [ -z "$ALL_FILES" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "No Python files changed β€” skipping"
exit 0
fi
INIT_FILES=""
LINT_FILES=""
while IFS= read -r file; do
# Skip files that no longer exist (deleted in PR)
if [ ! -f "$file" ]; then
continue
fi
if [[ "$(basename "$file")" == "__init__.py" ]]; then
INIT_FILES="$INIT_FILES $file"
else
LINT_FILES="$LINT_FILES $file"
fi
done <<< "$ALL_FILES"
INIT_FILES=$(echo "$INIT_FILES" | xargs)
LINT_FILES=$(echo "$LINT_FILES" | xargs)
echo "skip=false" >> $GITHUB_OUTPUT
echo "lint_files=$LINT_FILES" >> $GITHUB_OUTPUT
echo "init_files=$INIT_FILES" >> $GITHUB_OUTPUT
echo "πŸ” Lint files: ${LINT_FILES:-none}"
echo "πŸ“¦ __init__.py files: ${INIT_FILES:-none}"
# ── __init__.py must be empty check ──────────────────────────
- name: Check __init__.py files are empty
if: steps.changed.outputs.skip == 'false' && steps.changed.outputs.init_files != ''
id: init_check
run: |
INIT_FILES="${{ steps.changed.outputs.init_files }}"
> init_violations.txt
has_violations=false
for file in $INIT_FILES; do
if [ ! -f "$file" ]; then
continue
fi
CONTENT=$(sed '/^\s*$/d' "$file")
if [ -n "$CONTENT" ]; then
echo "$file" >> init_violations.txt
has_violations=true
fi
done
echo "has_violations=$has_violations" >> $GITHUB_OUTPUT
# ── Auto-fix with autoflake (remove unused imports & vars) ──
- name: Auto-fix with autoflake
if: steps.changed.outputs.skip == 'false' && steps.changed.outputs.lint_files != ''
run: |
autoflake --in-place \
--remove-all-unused-imports \
--remove-unused-variables \
${{ steps.changed.outputs.lint_files }}
# ── Auto-format with autopep8 ───────────────────────────────
- name: Auto-format with autopep8
if: steps.changed.outputs.skip == 'false' && steps.changed.outputs.lint_files != ''
id: autoformat
run: |
autopep8 --in-place --max-line-length=120 --ignore=E501,W503 \
${{ steps.changed.outputs.lint_files }}
if git diff --quiet; then
echo "has_fixes=false" >> $GITHUB_OUTPUT
else
echo "has_fixes=true" >> $GITHUB_OUTPUT
fi
# ── Commit ONLY the specific PR files ──────────────────────
- name: Commit auto-format fixes
if: steps.autoformat.outputs.has_fixes == 'true'
continue-on-error: true
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Stage ONLY the exact files from this PR β€” nothing else
for file in ${{ steps.changed.outputs.lint_files }}; do
git add "$file"
done
git commit -m "style: auto-format Python files with autoflake + autopep8"
git push
# ── Flake8 (check remaining issues after auto-format) ──────
- name: Run Flake8
if: always() && steps.changed.outputs.skip == 'false' && steps.changed.outputs.lint_files != ''
id: flake8
continue-on-error: true
run: |
OUTPUT=$(flake8 ${{ steps.changed.outputs.lint_files }} \
--max-line-length=120 --ignore=E501,W503 2>&1) || true
echo "$OUTPUT"
echo "$OUTPUT" > flake8_output.txt
if [ -n "$OUTPUT" ]; then
echo "has_errors=true" >> $GITHUB_OUTPUT
else
echo "has_errors=false" >> $GITHUB_OUTPUT
fi
# ── Create empty fallback files if steps were skipped ───────
- name: Ensure output files exist
if: always() && steps.changed.outputs.skip == 'false'
run: |
touch flake8_output.txt init_violations.txt
# ── PR Comment ──────────────────────────────────────────────
- name: Comment on PR
if: always() && steps.changed.outputs.skip == 'false'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const flake8 = fs.readFileSync('flake8_output.txt', 'utf8').trim();
const initViolations = fs.readFileSync('init_violations.txt', 'utf8').trim();
const flake8Err = '${{ steps.flake8.outputs.has_errors }}' === 'true';
const initErr = '${{ steps.init_check.outputs.has_violations }}' === 'true';
const autoFixed = '${{ steps.autoformat.outputs.has_fixes }}' === 'true';
const lintFiles = '${{ steps.changed.outputs.lint_files }}';
const initFiles = '${{ steps.changed.outputs.init_files }}';
const allPassed = !flake8Err && !initErr;
let body = '<!-- lint-check-result -->\n';
body += '## πŸ” Lint Results\n\n';
if (autoFixed) {
body += '### πŸ”§ Auto-formatted\n';
body += 'Some files were automatically cleaned and formatted with `autoflake` + `autopep8` and committed.\n';
body += '- βœ… **Unused imports removed** (autoflake)\n';
body += '- βœ… **Unused variables removed** (autoflake)\n';
body += '- βœ… **PEP8 formatting applied** (autopep8)\n\n';
}
if (initFiles) {
if (initErr) {
body += '### ❌ `__init__.py` Must Be Empty\n\n';
body += 'The following `__init__.py` files must be **completely empty** (no code, no comments, no imports):\n\n';
body += '```\n' + initViolations + '\n```\n\n';
body += '> `__init__.py` in ability folders is only used as a package marker. Remove all content from these files.\n\n';
} else {
body += '### βœ… `__init__.py` β€” Empty as expected\n\n';
}
}
if (lintFiles) {
body += `**Files linted:** \`${lintFiles}\`\n\n`;
if (flake8Err) {
body += '### ❌ Flake8 Errors (could not be auto-fixed)\n```\n' + flake8 + '\n```\n\n';
} else {
body += '### βœ… Flake8 β€” Passed\n\n';
}
} else {
body += '_No non-init Python files to lint._\n\n';
}
if (allPassed) {
body += '> βœ… All checks passed!';
} else {
body += '> Fix the remaining issues and push again. The lint will re-run automatically.';
}
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});
const existing = comments.find(c =>
c.user.type === 'Bot' && c.body.includes('<!-- lint-check-result -->')
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body: body
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}
# ── Fail the workflow if any check failed ──────────────────
- name: Fail if errors
if: |
steps.flake8.outputs.has_errors == 'true' ||
steps.init_check.outputs.has_violations == 'true'
run: |
echo "❌ Lint failed β€” check the PR comment for details"
exit 1
- name: Report status
if: always()
uses: actions/github-script@v7
with:
script: |
const conclusion = '${{ job.status }}';
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.payload.pull_request.head.sha,
state: conclusion === 'success' ? 'success' : 'failure',
context: 'lint',
description: conclusion === 'success' ? 'Passed' : 'Failed'
});