-
-
Notifications
You must be signed in to change notification settings - Fork 561
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Combine all headers checks into workflow with steps that end with a P…
…R comment
- Loading branch information
1 parent
71c04d9
commit 9f4683b
Showing
3 changed files
with
214 additions
and
109 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
name: Validate script headers | ||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
paths: | ||
- "ct/*.sh" | ||
- "install/*.sh" | ||
- ".github/workflows/validate-headers.yml" | ||
|
||
jobs: | ||
check-scripts: | ||
name: Check changed files | ||
runs-on: ubuntu-latest | ||
permissions: | ||
pull-requests: write | ||
|
||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 0 }} | ||
|
||
- name: Get changed files | ||
id: changed-files | ||
run: | | ||
if ${{ github.event_name == 'pull_request' }}; then | ||
echo "files=$(git diff --name-only -r HEAD^1 HEAD | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT | ||
else | ||
echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | grep -E '\.(sh|func)$' | xargs)" >> $GITHUB_OUTPUT | ||
fi | ||
- name: Check build.func line | ||
if: always() && steps.changed-files.outputs.files != '' | ||
id: build-func | ||
run: | | ||
NON_COMPLIANT_FILES="" | ||
for FILE in ${{ steps.changed-files.outputs.files }}; do | ||
if [[ $(sed -n '2p' "$FILE") != "source <(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" ]]; then | ||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" | ||
fi | ||
done | ||
if [ -n "$NON_COMPLIANT_FILES" ]; then | ||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT | ||
echo "Build.func line missing or incorrect in files:" | ||
for FILE in $NON_COMPLIANT_FILES; do | ||
echo "$FILE" | ||
done | ||
exit 1 | ||
fi | ||
- name: Check executable permissions | ||
if: always() && steps.changed-files.outputs.files != '' | ||
id: check-executable | ||
run: | | ||
NON_COMPLIANT_FILES="" | ||
for FILE in ${{ steps.changed-files.outputs.files }}; do | ||
if [[ ! -x "$FILE" ]]; then | ||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" | ||
fi | ||
done | ||
if [ -n "$NON_COMPLIANT_FILES" ]; then | ||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT | ||
echo "Files not executable:" | ||
for FILE in $NON_COMPLIANT_FILES; do | ||
echo "$FILE" | ||
done | ||
exit 1 | ||
fi | ||
- name: Check copyright | ||
if: always() && steps.changed-files.outputs.files != '' | ||
id: check-copyright | ||
run: | | ||
NON_COMPLIANT_FILES="" | ||
for FILE in ${{ steps.changed-files.outputs.files }}; do | ||
if [[ "$(sed -n '3p' "$FILE")" != "# Copyright (c) 2021-2025 community-scripts ORG" ]]; then | ||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" | ||
fi | ||
done | ||
if [ -n "$NON_COMPLIANT_FILES" ]; then | ||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT | ||
echo "Copyright header missing or not on line 3 in files:" | ||
for FILE in $NON_COMPLIANT_FILES; do | ||
echo "$FILE" | ||
done | ||
exit 1 | ||
fi | ||
- name: Check author | ||
if: always() && steps.changed-files.outputs.files != '' | ||
id: check-author | ||
run: | | ||
NON_COMPLIANT_FILES="" | ||
for FILE in ${{ steps.changed-files.outputs.files }}; do | ||
if ! sed -n '4p' "$FILE" | grep -qE "^# Author: .+"; then | ||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" | ||
fi | ||
done | ||
if [ -n "$NON_COMPLIANT_FILES" ]; then | ||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT | ||
echo "Author header missing or invalid on line 4 in files:" | ||
for FILE in $NON_COMPLIANT_FILES; do | ||
echo "$FILE" | ||
done | ||
exit 1 | ||
fi | ||
- name: Check license | ||
if: always() && steps.changed-files.outputs.files != '' | ||
id: check-license | ||
run: | | ||
NON_COMPLIANT_FILES="" | ||
for FILE in ${{ steps.changed-files.outputs.files }}; do | ||
if [[ "$(sed -n '5p' "$FILE")" != "# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE" ]]; then | ||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" | ||
fi | ||
done | ||
if [ -n "$NON_COMPLIANT_FILES" ]; then | ||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT | ||
echo "License header missing or not on line 5 in files:" | ||
for FILE in $NON_COMPLIANT_FILES; do | ||
echo "$FILE" | ||
done | ||
exit 1 | ||
fi | ||
- name: Check source | ||
if: always() && steps.changed-files.outputs.files != '' | ||
id: check-source | ||
run: | | ||
NON_COMPLIANT_FILES="" | ||
for FILE in ${{ steps.changed-files.outputs.files }}; do | ||
if ! sed -n '6p' "$FILE" | grep -qE "^# Source: .+"; then | ||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE" | ||
fi | ||
done | ||
if [ -n "$NON_COMPLIANT_FILES" ]; then | ||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT | ||
echo "Source header missing or not on line 6 in files:" | ||
for FILE in $NON_COMPLIANT_FILES; do | ||
echo "$FILE" | ||
done | ||
exit 1 | ||
fi | ||
- name: Post results and comment | ||
if: always() && steps.changed-files.outputs.files != '' && github.event_name == 'pull_request' | ||
uses: actions/github-script@v7 | ||
with: | ||
script: | | ||
const result = '${{ job.status }}' === 'success' ? 'success' : 'failure'; | ||
const nonCompliantFiles = { | ||
'Invalid build.func source': "${{ steps.build-func.outputs.files }}", | ||
'Not executable': "${{ steps.check-executable.outputs.files }}", | ||
'Copyright header line missing or invalid': "${{ steps.check-copyright.outputs.files }}", | ||
'Author header line missing or invalid': "${{ steps.check-author.outputs.files }}", | ||
'License header line missing or invalid': "${{ steps.check-license.outputs.files }}", | ||
'Source header line missing or invalid': "${{ steps.check-source.outputs.files }}" | ||
}; | ||
const issueNumber = context.payload.pull_request ? context.payload.pull_request.number : null; | ||
const commentIdentifier = 'validate-headers'; | ||
let newCommentBody = `<!-- ${commentIdentifier}-start -->\n### Script header validation\n\n`; | ||
if (result === 'failure') { | ||
newCommentBody += ':x: We found issues in the following changed files:\n\n'; | ||
for (const [check, files] of Object.entries(nonCompliantFiles)) { | ||
if (files) { | ||
newCommentBody += `**${check}:**\n${files.trim().split(' ').map(file => `- ${file}`).join('\n')}\n\n`; | ||
} | ||
} | ||
} else { | ||
newCommentBody += `:rocket: All changed shell scripts passed header validation!\n`; | ||
} | ||
newCommentBody += `\n\n<!-- ${commentIdentifier}-end -->`; | ||
if (issueNumber) { | ||
const { data: comments } = await github.rest.issues.listComments({ | ||
...context.repo, | ||
issue_number: issueNumber | ||
}); | ||
const existingComment = comments.find(comment => comment.user.login === 'github-actions[bot]'); | ||
if (existingComment) { | ||
if (existingComment.body.includes(commentIdentifier)) { | ||
const re = new RegExp(String.raw`<!-- ${commentIdentifier}-start -->[\s\S]*?<!-- ${commentIdentifier}-end -->`, ""); | ||
newCommentBody = existingComment.body.replace(re, newCommentBody); | ||
} else { | ||
newCommentBody = existingComment.body + '\n\n---\n\n' + newCommentBody; | ||
} | ||
await github.rest.issues.updateComment({ | ||
...context.repo, | ||
comment_id: existingComment.id, | ||
body: newCommentBody | ||
}); | ||
} else { | ||
await github.rest.issues.createComment({ | ||
...context.repo, | ||
issue_number: issueNumber, | ||
body: newCommentBody | ||
}); | ||
} | ||
} |