Skip to content
Closed
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
68 changes: 7 additions & 61 deletions .github/workflows/pull-request-helper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,14 @@ on:

permissions:
contents: write
pull-requests: write

jobs:
pull-request-helper:
if: github.event.pull_request.user.login == 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# this is the personal access token used for "git push" below
# which is needed in order to trigger workflows
token: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}

- name: Setup Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
with:
cache-read-only: true

- name: Set git user
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com

# - name: Spotless
# env:
# NUMBER: ${{ github.event.issue.number }}
# run: |
# ./gradlew spotlessApply
# if git diff --quiet; then
# exit 0 # success
# fi
# git commit -a -m "./gradlew spotlessApply"

- name: Update license report
env:
NUMBER: ${{ github.event.issue.number }}
run: |
./gradlew generateLicenseReport
git add licenses
# there's always going to one line difference due to the timestamp included in the report
if [[ $(git diff --cached --shortstat licenses) == " 1 file changed, 1 insertion(+), 1 deletion(-)" ]]
then
git reset HEAD licenses
git checkout -- licenses
exit 0 # success
fi
git commit -m "./gradlew generateLicenseReport"

- name: Update lock files
env:
NUMBER: ${{ github.event.issue.number }}
run: |
./gradlew resolveAndLockAll --write-locks
git add "*.lockfile"
if git diff --cached --quiet; then
exit 0 # success
fi
git commit -m "./gradlew resolveAndLockAll --write-locks"

- name: Push
env:
GH_TOKEN: ${{ github.token }}
run: |
git push
uses: ./.github/workflows/reusable-regenerate-generated-files.yml
with:
pr_number: ${{ github.event.pull_request.number }}
skip_if_contains_main: false
secrets:
PR_HELPER_GITHUB_TOKEN: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
22 changes: 22 additions & 0 deletions .github/workflows/regenerate-generated-files-runner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Regenerate generated files runner

on:
workflow_dispatch:
inputs:
pr_number:
description: Pull request number to process
required: true
type: number

permissions:
contents: write
pull-requests: write

jobs:
regenerate-generated-files:
uses: ./.github/workflows/reusable-regenerate-generated-files.yml
with:
pr_number: ${{ inputs.pr_number }}
skip_if_contains_main: true
secrets:
PR_HELPER_GITHUB_TOKEN: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
93 changes: 93 additions & 0 deletions .github/workflows/regenerate-generated-files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Regenerate generated files

on:
push:
branches:
- main
issue_comment:
types:
- created
workflow_dispatch:
inputs:
pr_number:
description: Pull request number to process
required: false
type: string

permissions:
contents: read
pull-requests: read

jobs:
dispatch-regeneration-request:
if: github.event_name == 'issue_comment' && github.event.issue.pull_request != null && startsWith(github.event.comment.body, '/regen') && github.event.issue.user.login == 'dependabot[bot]' && (github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR')
runs-on: ubuntu-latest
steps:
- name: Trigger workflow_dispatch for target pull request
env:
GH_TOKEN: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.issue.number }}
REPO: ${{ github.repository }}
run: |
gh workflow run regenerate-generated-files-runner.yml \
--repo "$REPO" \
--ref main \
-f pr_number="$PR_NUMBER"

prepare-targets:
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.targets.outputs.matrix }}
steps:
- name: Determine target pull requests
id: targets
env:
EVENT_NAME: ${{ github.event_name }}
GH_TOKEN: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
REPO: ${{ github.repository }}
WORKFLOW_DISPATCH_PR_NUMBER: ${{ inputs.pr_number }}
run: |
set -euo pipefail

if [[ "$EVENT_NAME" == "push" ]]; then
prs=$(gh pr list --repo "$REPO" --state open --label dependencies --json number,headRepository)
matrix=$(echo "$prs" | jq -c '[.[] | {pr: .number}]')
elif [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
if [[ -z "$WORKFLOW_DISPATCH_PR_NUMBER" ]]; then
echo "No workflow_dispatch pr_number provided, skipping"
matrix='[]'
else
matrix=$(jq -cn --argjson pr "$WORKFLOW_DISPATCH_PR_NUMBER" '[{pr:$pr}]')
fi
else
echo "Unsupported event: $EVENT_NAME"
exit 1
fi

echo "matrix=$matrix" >> "$GITHUB_OUTPUT"

regenerate-generated-files:
needs:
- prepare-targets
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && needs.prepare-targets.outputs.matrix != '[]'
strategy:
fail-fast: false
max-parallel: 3
matrix:
include: ${{ fromJson(needs.prepare-targets.outputs.matrix) }}
concurrency:
group: regen-${{ matrix.pr }}
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- name: Trigger workflow_dispatch for target pull request
env:
GH_TOKEN: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
PR_NUMBER: ${{ matrix.pr }}
REPO: ${{ github.repository }}
run: |
gh workflow run regenerate-generated-files-runner.yml \
--repo "$REPO" \
--ref main \
-f pr_number="$PR_NUMBER"
134 changes: 134 additions & 0 deletions .github/workflows/reusable-regenerate-generated-files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: Reusable - Regenerate generated files

on:
workflow_call:
inputs:
pr_number:
type: number
required: true
skip_if_contains_main:
type: boolean
required: false
default: true
secrets:
PR_HELPER_GITHUB_TOKEN:
required: true

permissions:
contents: write
pull-requests: write

jobs:
regenerate-generated-files:
runs-on: ubuntu-latest
steps:
- name: Resolve PR head branch
id: pr
env:
GH_TOKEN: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
PR_NUMBER: ${{ inputs.pr_number }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail

pr_json=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json headRefName,headRefOid,headRepository)
head_repo=$(echo "$pr_json" | jq -r '.headRepository.nameWithOwner // ""')
head_ref=$(echo "$pr_json" | jq -r '.headRefName')
head_sha=$(echo "$pr_json" | jq -r '.headRefOid')

echo "head_repo=$head_repo" >> "$GITHUB_OUTPUT"
echo "head_ref=$head_ref" >> "$GITHUB_OUTPUT"
echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT"

if [[ "$head_repo" != "$REPO" ]]; then
echo "eligible=false" >> "$GITHUB_OUTPUT"
echo "Skipping PR #$PR_NUMBER from fork repository: $head_repo"
else
echo "eligible=true" >> "$GITHUB_OUTPUT"
fi

- name: Checkout PR head
if: steps.pr.outputs.eligible == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# this personal access token is required so pushes retrigger workflows
token: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
repository: ${{ steps.pr.outputs.head_repo }}
ref: ${{ steps.pr.outputs.head_sha }}
fetch-depth: 0

- name: Setup Gradle
if: steps.pr.outputs.eligible == 'true'
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
with:
cache-read-only: true

- name: Set git user
if: steps.pr.outputs.eligible == 'true'
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com

- name: Merge main and regenerate generated files
if: steps.pr.outputs.eligible == 'true'
env:
GH_TOKEN: ${{ secrets.PR_HELPER_GITHUB_TOKEN }}
PR_NUMBER: ${{ inputs.pr_number }}
REPO: ${{ github.repository }}
SKIP_IF_CONTAINS_MAIN: ${{ inputs.skip_if_contains_main }}
HEAD_REF: ${{ steps.pr.outputs.head_ref }}
run: |
set -euo pipefail

git fetch origin main

if [[ "$SKIP_IF_CONTAINS_MAIN" == "true" ]] && git merge-base --is-ancestor origin/main HEAD; then
echo "PR #$PR_NUMBER already contains origin/main, skipping"
exit 0
fi

git merge --no-edit origin/main || true

mapfile -t conflicted < <(git diff --name-only --diff-filter=U)

if [ ${#conflicted[@]} -gt 0 ]; then
generated=()
real=()

for f in "${conflicted[@]}"; do
case "$f" in
*gradle.lockfile|licenses/more-licenses.md) generated+=("$f") ;;
*) real+=("$f") ;;
esac
done

if [ ${#real[@]} -gt 0 ]; then
printf 'genuine conflict, aborting: %s\n' "${real[@]}"

comment=$'Auto-regeneration stopped because this PR has genuine merge conflicts in non-generated files:\n\n'
for f in "${real[@]}"; do
comment+="- \`$f\`"$'\n'
done
comment+=$'\nPlease resolve these conflicts manually, then rerun `/regen` if needed.'

gh pr comment "$PR_NUMBER" --repo "$REPO" --body "$comment"
git merge --abort
exit 0
fi

for f in "${generated[@]}"; do
git checkout --ours -- "$f"
git add -- "$f"
done
fi

if [ -f .git/MERGE_HEAD ]; then
git commit --no-edit
fi

./gradlew resolveAndLockAll --write-locks
./gradlew generateLicenseReport --no-build-cache

git add -A -- '*.lockfile' licenses
git diff --cached --quiet || git commit -m "regenerate lock files and license report"
git push origin "HEAD:$HEAD_REF"
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ After updating dependencies, regenerate the license report to include licenses f

This ensures all third-party licenses are properly documented.

### Automatic regeneration for dependency pull requests

Generated files (`**/gradle.lockfile` and `licenses/more-licenses.md`) are automatically refreshed by GitHub Actions:

- On each push to `main`, open dependency PRs are merged with `main` and regenerated automatically.
- On an individual Dependabot PR, a repository member can comment `/regen` to run the regeneration workflow on demand.
- `pull-request-helper.yml` continues to refresh generated files for newly opened Dependabot PRs.

If regeneration detects merge conflicts in non-generated source files (`.kts`, `.java`, `.toml`, workflows, etc.), the bot leaves a PR comment and stops. In that case, resolve those source conflicts manually and rerun `/regen` if needed.

## IntelliJ setup and troubleshooting

See [IntelliJ setup and troubleshooting](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/contributing/intellij-setup-and-troubleshooting.md)
Expand Down