Skip to content

Commit cb43182

Browse files
[changelog] Auto-create Dependabot entries before validation (#186) (#189)
* [changelog] Auto-create Dependabot entries before validation (#186) * Update wiki submodule pointer for PR #189 --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 2fdc7b2 commit cb43182

9 files changed

Lines changed: 200 additions & 6 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Create Dependabot Changelog Entry
2+
description: Create and push a minimal changelog entry for a same-repository Dependabot pull request when the branch still lacks one.
3+
4+
inputs:
5+
changelog-file:
6+
description: Managed changelog path.
7+
required: true
8+
base-ref:
9+
description: Base branch reference used for changelog comparison.
10+
required: true
11+
head-ref:
12+
description: Pull request head branch ref.
13+
required: true
14+
pull-request-number:
15+
description: Pull request number.
16+
required: true
17+
pull-request-title:
18+
description: Pull request title used as the fallback changelog message source.
19+
required: true
20+
21+
outputs:
22+
created:
23+
description: Whether a changelog entry was created and pushed.
24+
value: ${{ steps.create.outputs.created }}
25+
message:
26+
description: Generated changelog entry message, or empty when no entry was needed.
27+
value: ${{ steps.create.outputs.message }}
28+
29+
runs:
30+
using: composite
31+
steps:
32+
- id: create
33+
name: Create entry when missing
34+
shell: bash
35+
env:
36+
INPUT_CHANGELOG_FILE: ${{ inputs.changelog-file }}
37+
INPUT_BASE_REF: ${{ inputs.base-ref }}
38+
INPUT_HEAD_REF: ${{ inputs.head-ref }}
39+
INPUT_PULL_REQUEST_NUMBER: ${{ inputs.pull-request-number }}
40+
INPUT_PULL_REQUEST_TITLE: ${{ inputs.pull-request-title }}
41+
run: ${{ github.action_path }}/run.sh
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
if composer dev-tools changelog:check -- --file="${INPUT_CHANGELOG_FILE}" --against="origin/${INPUT_BASE_REF}" >/dev/null 2>&1; then
5+
echo "created=false" >> "$GITHUB_OUTPUT"
6+
exit 0
7+
fi
8+
9+
git fetch --no-tags --depth=1 origin "+refs/heads/${INPUT_HEAD_REF}:refs/remotes/origin/${INPUT_HEAD_REF}"
10+
git switch -C "${INPUT_HEAD_REF}" "refs/remotes/origin/${INPUT_HEAD_REF}"
11+
git config user.name "github-actions[bot]"
12+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
13+
14+
entry_message="$(php -r 'require "vendor/autoload.php"; $resolver = new \FastForward\DevTools\Changelog\DependabotChangelogEntryMessageResolver(); echo $resolver->resolve(getenv("INPUT_PULL_REQUEST_TITLE") ?: "", (int) (getenv("INPUT_PULL_REQUEST_NUMBER") ?: 0));')"
15+
16+
composer dev-tools changelog:entry -- --type=changed --file="${INPUT_CHANGELOG_FILE}" "${entry_message}"
17+
git add "${INPUT_CHANGELOG_FILE}"
18+
git commit -m "Add changelog entry for Dependabot PR #${INPUT_PULL_REQUEST_NUMBER}"
19+
git push origin "HEAD:${INPUT_HEAD_REF}"
20+
21+
{
22+
echo "created=true"
23+
printf 'message=%s\n' "${entry_message}"
24+
} >> "$GITHUB_OUTPUT"

.github/wiki

Submodule wiki updated from 47537fc to 22ce9fe

.github/workflows/changelog.yml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ jobs:
9292
env:
9393
CHANGELOG_FILE: ${{ inputs.changelog-file || 'CHANGELOG.md' }}
9494
CHANGELOG_ROOT_VERSION: ${{ github.event.pull_request.head.ref && format('dev-{0}', github.event.pull_request.head.ref) || 'dev-main' }}
95+
BASE_REF: ${{ github.event.pull_request.base.ref }}
96+
HEAD_REF: ${{ github.event.pull_request.head.ref }}
97+
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
98+
PULL_REQUEST_TITLE: ${{ github.event.pull_request.title }}
9599

96100
steps:
97101
- uses: actions/checkout@v6
@@ -114,13 +118,20 @@ jobs:
114118
install-options: --prefer-dist --no-progress --no-interaction --no-plugins --no-scripts
115119

116120
- name: Fetch base branch reference
117-
env:
118-
BASE_REF: ${{ github.event.pull_request.base.ref }}
119121
run: git fetch --no-tags --depth=1 origin "+refs/heads/${BASE_REF}:refs/remotes/origin/${BASE_REF}"
120122

123+
- name: Create Dependabot changelog entry when missing
124+
id: dependabot_entry
125+
if: ${{ (github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'app/dependabot' || startsWith(github.event.pull_request.head.ref, 'dependabot/')) && github.event.pull_request.head.repo.full_name == github.repository }}
126+
uses: ./.dev-tools-actions/.github/actions/changelog/create-dependabot-entry
127+
with:
128+
changelog-file: ${{ env.CHANGELOG_FILE }}
129+
base-ref: ${{ env.BASE_REF }}
130+
head-ref: ${{ env.HEAD_REF }}
131+
pull-request-number: ${{ env.PULL_REQUEST_NUMBER }}
132+
pull-request-title: ${{ env.PULL_REQUEST_TITLE }}
133+
121134
- name: Verify changelog update
122-
env:
123-
BASE_REF: ${{ github.event.pull_request.base.ref }}
124135
run: composer dev-tools changelog:check -- --file="${CHANGELOG_FILE}" --against="origin/${BASE_REF}"
125136

126137
- uses: ./.dev-tools-actions/.github/actions/summary/write
@@ -129,7 +140,9 @@ jobs:
129140
## Changelog Validation Summary
130141
131142
- Changelog file: `${{ env.CHANGELOG_FILE }}`
132-
- Compared base ref: `origin/${{ github.event.pull_request.base.ref }}`
143+
- Compared base ref: `origin/${{ env.BASE_REF }}`
144+
- Dependabot fallback entry created: `${{ steps.dependabot_entry.outputs.created || 'false' }}`
145+
- Dependabot fallback entry message: `${{ steps.dependabot_entry.outputs.message || 'not needed' }}`
133146
- Validation result: success
134147
135148
prepare_release_pull_request:

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Auto-create and push minimal changelog entries for same-repository Dependabot pull requests before changelog validation reruns (#186)
13+
1014
## [1.20.0] - 2026-04-23
1115

1216
### Changed

docs/commands/changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ The packaged changelog workflow consumes these commands in two places:
147147

148148
- pull-request validation runs ``changelog:check`` against the base branch to
149149
require a meaningful changelog update;
150+
- Dependabot pull-request validation MAY create one minimal ``changed`` entry
151+
from the pull-request title before re-running ``changelog:check`` so the
152+
branch keeps a persisted release note without manual intervention;
150153
- manual release preparation uses ``changelog:next-version`` and
151154
``changelog:promote`` to create a release pull request, then
152155
``changelog:show`` to publish the merged section as GitHub release notes.

docs/usage/github-actions.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ wrapper in ``resources/github-actions/changelog.yml``.
161161
* Uses ``fetch-depth: 0`` so the base branch reference can be compared
162162
safely.
163163
* Fetches the base branch changelog reference.
164+
* For same-repository Dependabot pull requests, creates and pushes a
165+
minimal ``Unreleased`` changelog entry derived from the pull request
166+
title when the branch has not added one yet.
164167
* Runs ``composer dev-tools changelog:check -- --against=<base-ref>`` against the base ref.
165168
* Fails when a normal non-release branch does not add a meaningful ``Unreleased`` change.
166169
* Skips the validation job for pull requests whose head branch matches the configured ``release-branch-prefix``, because release-preparation branches intentionally leave ``Unreleased`` empty after promotion.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Fast Forward Development Tools for PHP projects.
7+
*
8+
* This file is part of fast-forward/dev-tools project.
9+
*
10+
* @author Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
11+
* @license https://opensource.org/licenses/MIT MIT License
12+
*
13+
* @see https://github.com/php-fast-forward/
14+
* @see https://github.com/php-fast-forward/dev-tools
15+
* @see https://github.com/php-fast-forward/dev-tools/issues
16+
* @see https://php-fast-forward.github.io/dev-tools/
17+
* @see https://datatracker.ietf.org/doc/html/rfc2119
18+
*/
19+
20+
namespace FastForward\DevTools\Changelog;
21+
22+
/**
23+
* Normalizes minimal changelog entry messages for Dependabot pull requests.
24+
*/
25+
final readonly class DependabotChangelogEntryMessageResolver
26+
{
27+
/**
28+
* @param string $title
29+
* @param int $pullRequestNumber
30+
*
31+
* @return string
32+
*/
33+
public function resolve(string $title, int $pullRequestNumber): string
34+
{
35+
$message = \preg_replace('/\s+/', ' ', \trim($title)) ?? \trim($title);
36+
$message = \rtrim($message, " \t\n\r\0\x0B.");
37+
38+
if (\preg_match('/\(#\d+\)$/', $message) === 1) {
39+
return $message;
40+
}
41+
42+
return \sprintf('%s (#%d)', $message, $pullRequestNumber);
43+
}
44+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Fast Forward Development Tools for PHP projects.
7+
*
8+
* This file is part of fast-forward/dev-tools project.
9+
*
10+
* @author Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
11+
* @license https://opensource.org/licenses/MIT MIT License
12+
*
13+
* @see https://github.com/php-fast-forward/
14+
* @see https://github.com/php-fast-forward/dev-tools
15+
* @see https://github.com/php-fast-forward/dev-tools/issues
16+
* @see https://php-fast-forward.github.io/dev-tools/
17+
* @see https://datatracker.ietf.org/doc/html/rfc2119
18+
*/
19+
20+
namespace FastForward\DevTools\Tests\Changelog;
21+
22+
use FastForward\DevTools\Changelog\DependabotChangelogEntryMessageResolver;
23+
use PHPUnit\Framework\Attributes\CoversClass;
24+
use PHPUnit\Framework\Attributes\Test;
25+
use PHPUnit\Framework\TestCase;
26+
27+
#[CoversClass(DependabotChangelogEntryMessageResolver::class)]
28+
final class DependabotChangelogEntryMessageResolverTest extends TestCase
29+
{
30+
#[Test]
31+
public function resolveWillAppendThePullRequestNumberWhenTheTitleHasNoSuffix(): void
32+
{
33+
$resolver = new DependabotChangelogEntryMessageResolver();
34+
35+
self::assertSame(
36+
'GitHub Actions(deps): Bump actions/github-script from 8 to 9 (#183)',
37+
$resolver->resolve(" GitHub Actions(deps): Bump actions/github-script from 8 to 9 \n", 183),
38+
);
39+
}
40+
41+
#[Test]
42+
public function resolveWillPreserveAnExistingPullRequestSuffix(): void
43+
{
44+
$resolver = new DependabotChangelogEntryMessageResolver();
45+
46+
self::assertSame(
47+
'Bump symfony/console from 7.3.0 to 7.3.1 (#123)',
48+
$resolver->resolve('Bump symfony/console from 7.3.0 to 7.3.1 (#123)', 123),
49+
);
50+
}
51+
52+
#[Test]
53+
public function resolveWillTrimTrailingPunctuationBeforeAppendingTheSuffix(): void
54+
{
55+
$resolver = new DependabotChangelogEntryMessageResolver();
56+
57+
self::assertSame(
58+
'Bump peter-evans/create-pull-request from 7 to 8 (#181)',
59+
$resolver->resolve('Bump peter-evans/create-pull-request from 7 to 8.', 181),
60+
);
61+
}
62+
}

0 commit comments

Comments
 (0)