Skip to content
Open
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
55 changes: 55 additions & 0 deletions .github/workflows/analyze-dependabot-reusable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Dependabot Analyze PR

on:
workflow_call:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
workflow_call:
workflow_call: { }


jobs:

analyze-pull-request:
# Skip this workflow on commits not pushed by Dependabot
if: ${{ github.actor == 'dependabot[bot]' }}
runs-on: ubuntu-latest

steps:

- name: Fetch Dependabot metadata
id: dependabot
uses: ppkarwasz/fetch-metadata@feat/multi-versions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume this will be replaced once dependabot/fetch-metadata#632 is merged.

with:
github-token: ${{ github.token }}

#
# Stores the data required by the process-dependabot-reusable workflow as JSON files.
#
Comment on lines +38 to +40
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#
# Stores the data required by the process-dependabot-reusable workflow as JSON files.
#
# Creates the data required by the `process-dependabot-reusable` workflow as JSON files.

- name: Create artifacts
shell: bash
env:
PULL_REQUEST: ${{ toJSON(github.event.pull_request) }}
UPDATED_DEPENDENCIES: ${{ steps.dependabot.outputs.updated-dependencies-json }}
run: |
mkdir -p dependabot-metadata
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is -p necessary here, since we only provide a single folder name?

echo "$PULL_REQUEST" > dependabot-metadata/pull_request.json
echo "$UPDATED_DEPENDENCIES" > dependabot-metadata/updated_dependencies.json
Comment on lines +48 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the meat of this entire reusable workflow, 2 LoC, the rest is just ceremony. I think this should consider integrating this into process-d-r, and removing analyze-d-r.

IIRC, you introduce this split for analyze-d-r needs less privileges compared to process-d-r. But the former is useless without the latter, hence, the split just inflates 2 LoC to 55 LoC, not to mention the inflation at call sites invoking these reusables.

- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # 4.6.2
with:
name: dependabot-metadata
path: dependabot-metadata
169 changes: 169 additions & 0 deletions .github/workflows/process-dependabot-reusable.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: Dependabot Process PR

on:
workflow_call:
inputs:
user-name:
description: The name of the user to use for the commit
default: 'ASF Logging Services RM'
type: string
user-email:
description: The email of the user to use for the commit
default: '[email protected]'
Comment on lines +25 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we expect an occasion where these defaults will be overriden? If not, please consider inlining them. I prefer code that is 8 lines shorter compared to a functionality that we don't use.

type: string
analyze-workflow-run-id:
description: The ID of the workflow run that analyzed the PR
required: true
type: number
secrets:
RECURSIVE_TOKEN:
description: "A PAT with `contents: write` permission to push changes and trigger the next workflow run"
required: true
GPG_PASSPHRASE:
description: GPG passphrase for signing commits
required: false
GPG_PRIVATE_KEY:
description: GPG secret key for signing commits
required: true

permissions: { }

jobs:

generate-changelog:
# Skip this workflow on commits not pushed by Dependabot
if: ${{ github.actor == 'dependabot[bot]' }}
runs-on: ubuntu-latest

steps:

- name: Fetch Dependabot metadata
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # 4.3.0
with:
github-token: ${{ github.token }}
name: dependabot-metadata
path: ${{ runner.temp }}/dependabot-metadata
run-id: ${{ inputs.analyze-workflow-run-id }}

- name: Process Dependabot metadata
shell: bash
run: |
# Extract the pull request metadata from the downloaded artifact
path="$RUNNER_TEMP/dependabot-metadata"
if [[ ! -f "$path/pull_request.json" ]]; then
echo "Pull request metadata not found at $path/pull_request.json"
exit 1
fi
if [[ ! -f "$path/updated_dependencies.json" ]]; then
echo "Updated dependencies metadata not found at $path/updated_dependencies.json"
exit 1
fi
# Extract the required metadata and set it as environment variables
pull_request="$path/pull_request.json"
Comment on lines +68 to +79
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this can be avoided if 2 LoC moved from analyze-d-r to here.

echo "PR_ID=$(jq -r '.number' < "$pull_request")" >> $GITHUB_ENV
echo "PR_URL=$(jq -r '.html_url' < "$pull_request")" >> $GITHUB_ENV
echo "PR_HEAD_REF=$(jq -r '.head.ref' < "$pull_request")" >> $GITHUB_ENV
Comment on lines +80 to +82
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a spec. somewhere on the JSON schema of the dependabot PR payload? If yes, sharing it here in a comment would be very useful for the next maintainer troubleshooting an issue here.

- name: Check out repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
with:
ref: ${{ env.PR_HEAD_REF }}
token: ${{ secrets.RECURSIVE_TOKEN }}

- name: Install `xmlstarlet`
shell: bash
run: sudo apt-get update && sudo apt-get install -y xmlstarlet

- name: Find the release version major
shell: bash
run: |
revision=$(
xmlstarlet sel \
-N m=http://maven.apache.org/POM/4.0.0 \
--template --value-of /m:project/m:properties/m:revision \
pom.xml
)
if [[ ! $revision =~ ^[0-9]+\.[0-9]+\.[0-9]+(-SNAPSHOT)?$ ]]; then
echo "Invalid version format: $revision"
exit 1
fi
parts=(${revision//./ })
echo "RELEASE_VERSION_MAJOR=${parts[0]}" >> $GITHUB_ENV
Comment on lines +107 to +108
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can alternatively use the parameter expansion:

Suggested change
parts=(${revision//./ })
echo "RELEASE_VERSION_MAJOR=${parts[0]}" >> $GITHUB_ENV
revisionMajor=${revision%%.*}
echo "RELEASE_VERSION_MAJOR=$revisionMajor" >> $GITHUB_ENV

- name: Create changelog entries
shell: bash
run: |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really appreciate it if you can ventilate this big chunk of code with some empty lines delimiting the blocks by their semantics.

PULL_REQUEST="$RUNNER_TEMP/dependabot-metadata/pull_request.json"
UPDATED_DEPENDENCIES="$RUNNER_TEMP/dependabot-metadata/updated_dependencies.json"
# Generates the content of a changelog entry
function generate_changelog_entry() {
local dependency="$1"
local issue_id=$(xmlstarlet esc "$PR_ID")
local issue_link=$(xmlstarlet esc "$PR_URL")
local dependency_name=$(echo "$dependency" | jq -r '.dependencyName' | xmlstarlet esc)
local new_version=$(echo "$dependency" | jq -r '.newVersion' | xmlstarlet esc)
cat << CHANGELOG_ENTRY
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-License-Identifier: Apache-2.0 -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, Logging Services speak CDX, not SPDX. I think we should discuss this with the rest of the crew and introduce it in a mass roll out instead of piggybacking.

Suggested change
<!-- SPDX-License-Identifier: Apache-2.0 -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://logging.apache.org/xml/ns"
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
type="updated">
<issue id="$issue_id" link="$issue_link"/>
<description format="asciidoc">Update \`$dependency_name\` to version \`$new_version\`.</description>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd stick to the existing description:

Suggested change
<description format="asciidoc">Update \`$dependency_name\` to version \`$new_version\`.</description>
<description format="asciidoc">Update \`$dependency_name\` to version \`$new_version\`</description>

</entry>
CHANGELOG_ENTRY
}
# Ensure the changelog directory exists
release_changelog_path="src/changelog/.${RELEASE_VERSION_MAJOR}.x.x"
mkdir -p "$release_changelog_path"
cd "$release_changelog_path"
# Generate the changelog entries for each updated dependency
cat "$UPDATED_DEPENDENCIES" | jq --compact-output '.[]' | while read -r dependency; do
# Extract the dependency name and version
dependency_name=$(echo "$dependency" | jq -r '.dependencyName')
changelog_file_name=$(echo "update_${dependency_name,,}.xml" | sed -r -e 's/[^a-z0-9.-]/_/g' -e 's/_+/_/g')
generate_changelog_entry "$dependency" > "$changelog_file_name"
done
- name: Set up GPG
uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # 6.3.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"In crazy-max we trust." ℒ️ We won't be shot by the ASF police for using this, right?

with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}

- name: Add & commit changes
shell: bash
env:
USER_NAME: ${{ inputs.user-name }}
USER_EMAIL: ${{ inputs.user-email }}
run: |
git add src/changelog
git config user.name "$USER_NAME"
git config user.email "$USER_EMAIL"
git commit -S -m "Generate changelog entries for PR #$PR_ID"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
git commit -S -m "Generate changelog entries for PR #$PR_ID"
git commit -S -m "Generate changelog entries for #$PR_ID"

git push origin
- name: Enable auto-merge on PR
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr merge --squash --auto "$PR_URL"
10 changes: 10 additions & 0 deletions src/changelog/.12.x.x/add-deploy-profile.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://logging.apache.org/xml/ns"
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
type="added">
<issue id="417" link="https://github.com/apache/logging-parent/issues/417"/>
<description format="asciidoc">
Added `process-dependabot-reusable` to handle Dependabot PRs under RTC restrictions.
</description>
</entry>
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,18 @@
# limitations under the License.
#

name: merge-dependabot
name: "Dependabot Analyze PR"

on:
pull_request_target:
paths-ignore:
- "**.adoc"
- "**.md"
- "**.txt"
pull_request:

permissions: read-all
permissions: { }

jobs:

build:
if: github.repository == 'apache/logging-parent' && github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]'
uses: ./.github/workflows/build-reusable.yaml

merge-dependabot:
needs: build
uses: ./.github/workflows/merge-dependabot-reusable.yaml
permissions:
contents: write # to push changelog commits
pull-requests: write # to close the PR
secrets:
GPG_SECRET_KEY: ${{ secrets.LOGGING_GPG_SECRET_KEY }} # to sign commits
# tag::analyze-dependabot[]
analyze-dependabot:
# Skip this workflow on commits not pushed by Dependabot
if: ${{ github.actor == 'dependabot[bot]' }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep the extra check against the repository for DiD reasons:

Suggested change
if: ${{ github.actor == 'dependabot[bot]' }}
if: ${{ github.repository == 'apache/logging-parent' && github.actor == 'dependabot[bot]' }}

(I don't know if above change necessitates an workflows.adoc update.)

uses: apache/logging-parent/.github/workflows/analyze-dependabot-reusable.yaml@rel/{project-version}
# end::analyze-dependabot[]
52 changes: 52 additions & 0 deletions src/site/antora/modules/ROOT/examples/process-dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

name: "Dependabot Process PR"

on:
workflow_run:
workflows:
- "Dependabot Analyze PR"
types:
- completed

permissions: { }

jobs:

# tag::process-dependabot[]
process-dependabot:
# Skip this workflow on commits not pushed by Dependabot
if: ${{ github.event.workflow_run.conclusion == 'success' && github.actor == 'dependabot[bot]' }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I'd keep the repository name validation.

uses: apache/logging-parent/.github/workflows/process-dependabot-reusable.yaml@rel/{project-version}
permissions:
# The default GITHUB_TOKEN will be used to enable the "auto-merge" on the PR
# This requires the following two permissions:
contents: write
pull-requests: write
secrets:
RECURSIVE_TOKEN: ${{ secrets.DEPENDABOT_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
with:
# These are the default values.
# The e-mail address must match the one used in the GPG key.
user_name: "ASF Logging Services RM"
user_email: "[email protected]"
# The run ID of the workflow that analyzed the PR.
analyze-workflow-run-id: ${{ github.event.workflow_run.id }}
# end::process-dependabot[]
60 changes: 57 additions & 3 deletions src/site/antora/modules/ROOT/pages/workflows.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,64 @@ To verify the reproducibility of a release, you can use:
include::example$build.yaml[tag=verify-reproducibility-release,indent=0]
----

[#merge-dependabot]
== {project-github-url}/blob/main/.github/workflows/merge-dependabot-reusable.yaml[`merge-dependabot-reusable.yaml`]
[#analyze-dependabot]
== {project-github-url}/blob/main/.github/workflows/analyze-dependabot-reusable.yaml[`analyze-dependabot-reusable.yaml`]

Merges Dependabot PRs along with changelog entries.
Analyzes Dependabot pull requests to collect detailed information about updated dependencies.
Stores the results in the `dependabot-metadata` artifact,
which is later consumed by the <<process-dependabot>> workflow to automate changelog generation and PR processing.

[NOTE]
====
This workflow must be triggered by an event that includes the `pull_request` payload and does not require any privileges.
It can then be used in a `pull_request` workflow.
====

.Snippet from an {examples-base-link}/analyze-dependabot.yaml[example `analyze-dependabot.yaml`] using this workflow
[source,yaml,subs=+attributes]
----
include::example$analyze-dependabot.yaml[tag=analyze-dependabot,indent=0]
----

[#process-dependabot]
== {project-github-url}/blob/main/.github/workflows/process-dependabot-reusable.yaml[`process-dependabot-reusable.yaml`]

Helps to process Dependabot pull requests by:

* Generating changelog entries for the updated dependencies.
* Enabling the "auto-merge" option for the pull request.

The workflow needs the following privileged tokens:

`GITHUB_TOKEN`::
The default GitHub token with `contents:write` and `pull_requests:write` permissions,
used to enable auto-merge on pull requests.
+
This token is automatically provided by GitHub Actions, but needs to be configured in the `permissions` property.

`RECURSIVE_TOKEN`::
A GitHub token required to push generated changelog files as a new commit to the repository.
The default `GITHUB_TOKEN` can **not** be used,
as it will not trigger required check runs and will prevent the pull request from being merged.
A Personal Access Token (PAT) with `contents:write` permission must be provided instead.
+
The token must be passed as a secret named `RECURSIVE_TOKEN`.

This workflow is designed to be triggered by the `workflow_run` event,
as soon as the <<analyze-dependabot>> workflow completes.

[NOTE]
====
When this workflow is triggered by `workflow_run`,
GitHub Actions uses the "Actions" secret context instead of "Dependabot" secrets,
even if the `github.actor` is `dependabot[bot]`.
====

.Snippet from an {examples-base-link}/process-dependabot.yaml[example `process-dependabot.yaml`] using this workflow
[source,yaml,subs=+attributes]
----
include::example$process-dependabot.yaml[tag=process-dependabot,indent=0]
----

[#deploy-site]
== {project-github-url}/blob/main/.github/workflows/deploy-site-reusable.yaml[`deploy-site-reusable.yaml`]
Expand Down
Loading