diff --git a/.github/workflows/check-formatting.sh b/.github/workflows/check-formatting.sh new file mode 100755 index 0000000000..0c2effbbb9 --- /dev/null +++ b/.github/workflows/check-formatting.sh @@ -0,0 +1,45 @@ +if [ ! -d "src" ] && [ ! -d "SubProcesses" ]; then + echo "Error: Neither 'src' nor 'SubProcesses' directory exists, script needs to be run from the root directory of a generated process" >&2 + exit 255 +fi + +count=0 +total=0 +files_needing_format=() +patch_file="format-changes.patch" +num_file="files2format" + +# clean patch file if it exists +> "$patch_file" +> "$num_file" + +echo "" +echo "Checking formatting with clang-format..." +echo "" + +while IFS= read -r file; do + ((total++)) + if ! clang-format --dry-run --Werror "$file" 2>/dev/null; then + echo "=== $file needs formatting ===" + clang-format "$file" | diff -u "$file" - >> "$patch_file" + echo "" >> "$patch_file" + ((count++)) + files_needing_format+=("$file") + fi +done < <(find src SubProcesses -type f \( -name "*.cc" -o -name "*.h" \) 2>/dev/null) + + +echo "" +echo "Files needing formatting: $count" +echo "Total files checked: $total" + +if [ $count -gt 0 ]; then + echo "Detailed patch saved to '$patch_file'" + echo "If this scrpt is run in the CI workflow, detailed patches are provided as comment on the PR." +else + echo "All files are properly formatted." + rm "$patch_file" +fi +echo "" + +echo $count | tr -d \\n >> $num_file diff --git a/.github/workflows/mg5_codegen.yml b/.github/workflows/mg5_codegen.yml new file mode 100644 index 0000000000..466444cb5d --- /dev/null +++ b/.github/workflows/mg5_codegen.yml @@ -0,0 +1,156 @@ +name: Generate code, check format and push to generated processes repo + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + generate-and-check: + runs-on: ubuntu-latest + + strategy: + matrix: + process: [pp_ttx, pp_ttxj] + + env: + PROC_DIR: PROC_${{ matrix.process }} + + steps: + - name: Checkout codegen repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + + - name: Run code generator + run: | + cd ${GITHUB_WORKSPACE} + if [ ! -e MG5aMC/mg5amcnlo/PLUGIN/CUDACPP_SA_OUTPUT ] ; then pushd MG5aMC/mg5amcnlo/PLUGIN/ && ln -s ../../../epochX/cudacpp/CODEGEN/PLUGIN/CUDACPP_SA_OUTPUT && popd ; fi + ./MG5aMC/mg5amcnlo/bin/mg5_aMC test/processes/${{ matrix.process }}/output.mg5 + + - name: Check code format with clang-format + id: clang-format-check + run: | + chmod +x ${GITHUB_WORKSPACE}/.github/workflows/check-formatting.sh + cd ${GITHUB_WORKSPACE}/${{ env.PROC_DIR }} + ${GITHUB_WORKSPACE}/.github/workflows/check-formatting.sh + files2format=$(cat files2format) + echo "files2format=$files2format" >> $GITHUB_OUTPUT + + if [ "$files2format" -eq 0 ]; then + echo "✅ clang-format check passed." + else + echo "❌ clang-format check failed." + fi + + - name: Generate GitHub App token + if: ${{ steps.clang-format-check.outputs.files2format == '0' }} + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + repositories: madgraph4gpu-generated-processes + + - name: Commit to target repository + if: ${{ steps.clang-format-check.outputs.files2format == '0' }} + env: + TARGET_REPO: roiser/madgraph4gpu-generated-processes + run: | + # Configure git + + git config --global user.name "github-actions" + git config --global user.email "github-actions@users.noreply.github.com" + + # Clone target repo + cd ${GITHUB_WORKSPACE} + git clone https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/${TARGET_REPO}.git + cd ${GITHUB_WORKSPACE}/madgraph4gpu-generated-processes + + # Create branch based on PR number + BRANCH_NAME="codegen-pr-${{ github.event.pull_request.number }}" + git checkout -b ${BRANCH_NAME} + + # Copy generated files (adjust paths as needed) + cp -r ${GITHUB_WORKSPACE}/${{ env.PROC_DIR }} . + + # Commit and push + git add . + git commit -m "Code generated from PR #${{ github.event.pull_request.number }}" \ + -m "Source PR: ${{ github.event.pull_request.html_url }}" + + git push -f origin ${BRANCH_NAME} + + echo "✅ Pushed to ${TARGET_REPO} on branch ${BRANCH_NAME}" + + - name: Set up Python + if: ${{ steps.commit_to_target_repository.outcome == 'success' }} + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Update README.md + if: ${{ steps.commit_to_target_repository.outcome == 'success' }} + run: | + cd ${GITHUB_WORKSPACE}/madgraph4gpu-generated-processes + git checkout main + + python ${GITHUB_WORKSPACE}/.github/workflows/update_readme.py \ + --title "${{ github.event.pull_request.title }}" \ + --url "${{ github.event.pull_request.html_url }}" \ + --pr_num "${{ github.event.pull_request.number }}" \ + --created "${{ github.event.pull_request.created_at }}" \ + --last_updated "${{ github.event.pull_request.updated_at }}" \ + --wip "${{ github.event.pull_request.draft }}" \ + --num_commits "${{ github.event.pull_request.commits }}" \ + --author "${{ github.event.pull_request.user.login }}" + + git add . + git commit -m "Update README for PR #${{ github.event.pull_request.number }}" + git push -f origin main + + echo "✅ Pushed to ${TARGET_REPO} on branch main" + + - name: Read patch file + if: ${{ steps.clang-format-check.outputs.files2format != '0' }} + run: | + { + echo "patch_file_content<> $GITHUB_OUTPUT + + - name: Comment on PR with format issues + if: ${{ steps.clang-format-check.outputs.files2format != '0' }} + uses: actions/github-script@v7 + env: + FILES2FORMAT: ${{ steps.clang-format-check.outputs.files2format }} + with: + script: | + + const fs = require('fs'); + const filesToFormat = parseInt(process.env.FILES2FORMAT); + const patchContent = fs.readFileSync(`${process.env.PROC_DIR}/format-changes.patch`, 'utf8'); + + const comment = `## ❌ Code Format Check Failed + + The generated code does not conform to clang-format rules. + + Please update your code generator to produce properly formatted code. + ${filesToFormat} files need formatting. + + Note: The CI is setup so it fails early, if formatting issues are detected for any of the processes. + The report below is for process **${process.env.PROC_DIR}** with backend **${process.env.BACKEND}**. + + See attached patch for details:`; + + github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `${comment} \n \`\`\` \n ${patchContent} \n \`\`\`` + }); + + - name: Fail if format check failed + if: ${{ steps.clang-format-check.outputs.files2format != '0' }} + run: exit 1 diff --git a/.github/workflows/testsuite_allprocesses.yml b/.github/workflows/testsuite_allprocesses.yml.disabled similarity index 100% rename from .github/workflows/testsuite_allprocesses.yml rename to .github/workflows/testsuite_allprocesses.yml.disabled diff --git a/.github/workflows/update_readme.py b/.github/workflows/update_readme.py new file mode 100644 index 0000000000..21c72607e0 --- /dev/null +++ b/.github/workflows/update_readme.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import json +import optparse + +class UpdateReadme: + def __init__(self, title, url, pr_num, created, last_updated, wip, num_commits, author): + self.title = title + self.url = url + self.pr_num = pr_num + self.created = created + self.last_updated = last_updated + self.wip = wip + self.num_commits = num_commits + self.author = author + self.remote_repo_url = "https://github.com/roiser/madgraph4gpu-generated-processes/" + + def update_json(self): + fh = open('readme_data.json', 'r') + data = json.load(fh) + fh.close() + + if self.pr_num not in data: + new_entry = { + "title": self.title, + "branch": self.remote_repo_url + "tree/codegen-pr-" + str(self.pr_num), + "url": self.url, + "created": self.created, + "last_updated": self.last_updated, + "wip": self.wip, + "num_commits": self.num_commits, + "author": self.author + } + data[self.pr_num] = new_entry + else: + data[self.pr_num]['last_updated'] = self.last_updated + data[self.pr_num]['wip'] = self.wip + data[self.pr_num]['num_commits'] = self.num_commits + data[self.pr_num]['title'] = self.title + + fh = open('readme_data.json', 'w') + json.dump(data, fh, indent=4) + fh.close() + + def write_readme(self): + fh = open('readme_data.json', 'r') + data = json.load(fh) + fh.close() + + sorted_prs = sorted(data.items(), key=lambda x: x[1]['last_updated'], reverse=True) + + with open('README.md', 'w') as fh: + fh.write("# Pull Request Summary\n\n") + fh.write("| PR Number | Local Branch | Title | WIP | # Commits | Author | Created | Last Update |\n") + fh.write("|-----------|--------------|-------|-----|-----------|--------|---------|-------------|\n") + for pr_num, details in sorted_prs: + fh.write(f"| [{pr_num}]({details['url']}) | [{details['branch'].split('/')[-1]}]({details['branch']}) | {details['title']} | {details['wip']} | {details['num_commits']} | {details['author']} | {details['created']} | {details['last_updated']} |\n") + + def run(self): + self.update_json() + self.write_readme() + +if __name__ == "__main__": + parser = optparse.OptionParser() + parser.add_option('--title', dest='title', help='PR title') + parser.add_option('--url', dest='url', help='PR URL') + parser.add_option('--pr_num', dest='pr_num', help='PR number') + parser.add_option('--created', dest='created', help='PR creation date') + parser.add_option('--last_updated', dest='last_updated', help='PR last updated date') + parser.add_option('--wip', dest='wip', help='Is PR WIP') + parser.add_option('--num_commits', dest='num_commits', help='Number of commits in PR') + parser.add_option('--author', dest='author', help='PR author') + + options, _ = parser.parse_args() + + updater = UpdateReadme(options.title, options.url, options.pr_num, options.created, options.last_updated, options.wip, options.num_commits, options.author) + updater.run() \ No newline at end of file diff --git a/.gitignore b/.gitignore index d59d93cf5c..a617fdaf7b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,13 @@ *.mod *.pyc *.so +py.py build.* .build.* +#=== testing === +test/processes/PROC_* + #=== Profiling === nsight_logs profile_* diff --git a/test/processes/pp_ttx/launch.mg5 b/test/processes/pp_ttx/launch.mg5 new file mode 100644 index 0000000000..2acf6a78e1 --- /dev/null +++ b/test/processes/pp_ttx/launch.mg5 @@ -0,0 +1,6 @@ +launch PROC_pp_ttx +set vector_size 32 +set nevents 25k +set sde_strategy 1 +set gridpack True + diff --git a/test/processes/pp_ttx/output.mg5 b/test/processes/pp_ttx/output.mg5 new file mode 100644 index 0000000000..0299c86959 --- /dev/null +++ b/test/processes/pp_ttx/output.mg5 @@ -0,0 +1,2 @@ +generate p p > t t~ +output madevent_simd PROC_pp_ttx diff --git a/test/processes/pp_ttxj/launch.mg5 b/test/processes/pp_ttxj/launch.mg5 new file mode 100644 index 0000000000..6be9aa7461 --- /dev/null +++ b/test/processes/pp_ttxj/launch.mg5 @@ -0,0 +1,6 @@ +launch PROC_pp_ttxj +set vector_size 32 +set nevents 25k +set sde_strategy 1 +set gridpack True + diff --git a/test/processes/pp_ttxj/output.mg5 b/test/processes/pp_ttxj/output.mg5 new file mode 100644 index 0000000000..1a934c01e6 --- /dev/null +++ b/test/processes/pp_ttxj/output.mg5 @@ -0,0 +1,2 @@ +generate p p > t t~ j +output madevent_simd PROC_pp_ttxj