Skip to content

Commit af56b86

Browse files
committed
[github] Refine CODEOWNERS inference rules (#67)
1 parent 8d320fe commit af56b86

4 files changed

Lines changed: 71 additions & 56 deletions

File tree

resources/CODEOWNERS

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Generated by fast-forward/dev-tools.
2+
# Review the generated owners before committing this file.
3+
#
4+
# When no GitHub owners can be inferred automatically, replace the placeholder
5+
# example below with the usernames, teams, or emails that should review
6+
# changes in the consumer repository.
7+
#
8+
# Example:
9+
# * @your-github-user @your-org/platform-team
10+
{{ suggestions }}
11+
{{ rule }}

resources/CODEOWNERS.dist

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/CodeOwners/CodeOwnersGenerator.php

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,19 @@ public function __construct(
6161
*/
6262
public function inferOwners(): array
6363
{
64+
$owners = [];
65+
$groupOwner = $this->inferGroupOwner();
66+
67+
if (null !== $groupOwner) {
68+
$owners[] = $groupOwner;
69+
}
70+
6471
$authors = $this->composer->getAuthors();
6572

6673
if (! is_iterable($authors)) {
67-
return [];
74+
return $owners;
6875
}
6976

70-
$owners = [];
71-
7277
foreach ($authors as $author) {
7378
if (! $author instanceof AuthorInterface) {
7479
continue;
@@ -86,29 +91,6 @@ public function inferOwners(): array
8691
return array_values(array_unique($owners));
8792
}
8893

89-
/**
90-
* Returns best-effort commented suggestions when direct ownership cannot be inferred.
91-
*
92-
* @return list<string>
93-
*/
94-
public function inferSuggestedOwners(): array
95-
{
96-
$source = $this->composer->getSupport()
97-
->getSource();
98-
99-
if ('' === $source) {
100-
return [];
101-
}
102-
103-
$owner = $this->extractGitHubRepositoryOwner($source);
104-
105-
if (null === $owner) {
106-
return [];
107-
}
108-
109-
return ['@' . $owner];
110-
}
111-
11294
/**
11395
* Normalizes user-provided owner tokens.
11496
*
@@ -147,23 +129,40 @@ static function (string $owner): string {
147129
public function generate(?array $owners = null): string
148130
{
149131
$owners ??= $this->inferOwners();
150-
$suggestions = [];
151-
152-
if ([] === $owners) {
153-
$suggestions = $this->inferSuggestedOwners();
154-
}
155-
156-
$template = $this->filesystem->readFile($this->fileLocator->locate('resources/CODEOWNERS.dist'));
157-
$suggestionBlock = [] === $suggestions
132+
$template = $this->filesystem->readFile($this->fileLocator->locate('resources/CODEOWNERS'));
133+
$suggestionBlock = [] === $owners
158134
? '# No GitHub owners could be inferred from composer.json metadata.'
159-
: \sprintf('# Suggested owner from composer support metadata: %s', implode(' ', $suggestions));
135+
: '';
160136
$rule = [] === $owners
161137
? '# * @your-github-user'
162138
: \sprintf('* %s', implode(' ', $owners));
163139

164140
return str_replace(['{{ suggestions }}', '{{ rule }}'], [$suggestionBlock, $rule], $template);
165141
}
166142

143+
/**
144+
* Returns the repository or organization owner inferred from support metadata.
145+
*
146+
* @return string|null the inferred group owner with `@`, or null when unavailable
147+
*/
148+
public function inferGroupOwner(): ?string
149+
{
150+
$source = $this->composer->getSupport()
151+
->getSource();
152+
153+
if ('' === $source) {
154+
return null;
155+
}
156+
157+
$owner = $this->extractGitHubRepositoryOwner($source);
158+
159+
if (null === $owner) {
160+
return null;
161+
}
162+
163+
return '@' . $owner;
164+
}
165+
167166
/**
168167
* Extracts a GitHub user handle from a homepage URL.
169168
*

tests/CodeOwners/CodeOwnersGeneratorTest.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ protected function setUp(): void
6767
$this->filesystem = $this->prophesize(FilesystemInterface::class);
6868
$this->fileLocator = $this->prophesize(FileLocatorInterface::class);
6969

70-
$this->fileLocator->locate('resources/CODEOWNERS.dist')
71-
->willReturn('/package/resources/CODEOWNERS.dist');
72-
$this->filesystem->readFile('/package/resources/CODEOWNERS.dist')
70+
$this->fileLocator->locate('resources/CODEOWNERS')
71+
->willReturn('/package/resources/CODEOWNERS');
72+
$this->filesystem->readFile('/package/resources/CODEOWNERS')
7373
->willReturn(<<<'TEXT'
7474
# Header
7575
{{ suggestions }}
@@ -87,8 +87,10 @@ protected function setUp(): void
8787
* @return void
8888
*/
8989
#[Test]
90-
public function inferOwnersWillCollectGitHubHandlesFromAuthorHomepages(): void
90+
public function inferOwnersWillCollectGroupAndAuthorOwners(): void
9191
{
92+
$this->composerJson->getSupport()
93+
->willReturn(new Support(source: 'https://github.com/php-fast-forward/dev-tools'));
9294
$this->composerJson->getAuthors()
9395
->willReturn([
9496
new Author(homepage: 'https://github.com/php-fast-forward'),
@@ -103,12 +105,12 @@ public function inferOwnersWillCollectGitHubHandlesFromAuthorHomepages(): void
103105
* @return void
104106
*/
105107
#[Test]
106-
public function inferSuggestedOwnersWillReturnRepositoryOwnerFromSupportSource(): void
108+
public function inferGroupOwnerWillReturnRepositoryOwnerFromSupportSource(): void
107109
{
108110
$this->composerJson->getSupport()
109111
->willReturn(new Support(source: 'https://github.com/php-fast-forward/dev-tools'));
110112

111-
self::assertSame(['@php-fast-forward'], $this->generator->inferSuggestedOwners());
113+
self::assertSame('@php-fast-forward', $this->generator->inferGroupOwner());
112114
}
113115

114116
/**
@@ -117,28 +119,42 @@ public function inferSuggestedOwnersWillReturnRepositoryOwnerFromSupportSource()
117119
#[Test]
118120
public function generateWillRenderExplicitOwners(): void
119121
{
122+
self::assertSame(
123+
"# Header\n\n* @php-fast-forward @mentordosnerds",
124+
$this->generator->generate(['@php-fast-forward', '@mentordosnerds']),
125+
);
126+
}
127+
128+
/**
129+
* @return void
130+
*/
131+
#[Test]
132+
public function generateWillRenderCommentedFallbackWhenOwnersCannotBeInferred(): void
133+
{
134+
$this->composerJson->getAuthors()
135+
->willReturn([]);
120136
$this->composerJson->getSupport()
121137
->willReturn(new Support());
122138

123139
self::assertSame(
124-
"# Header\n# No GitHub owners could be inferred from composer.json metadata.\n* @php-fast-forward @mentordosnerds",
125-
$this->generator->generate(['@php-fast-forward', '@mentordosnerds']),
140+
"# Header\n# No GitHub owners could be inferred from composer.json metadata.\n# * @your-github-user",
141+
$this->generator->generate(),
126142
);
127143
}
128144

129145
/**
130146
* @return void
131147
*/
132148
#[Test]
133-
public function generateWillRenderCommentedFallbackWhenOwnersCannotBeInferred(): void
149+
public function generateWillRenderGroupOwnerWhenAuthorCannotBeInferred(): void
134150
{
135151
$this->composerJson->getAuthors()
136152
->willReturn([]);
137153
$this->composerJson->getSupport()
138154
->willReturn(new Support(source: 'https://github.com/php-fast-forward/dev-tools'));
139155

140156
self::assertSame(
141-
"# Header\n# Suggested owner from composer support metadata: @php-fast-forward\n# * @your-github-user",
157+
"# Header\n\n* @php-fast-forward",
142158
$this->generator->generate(),
143159
);
144160
}

0 commit comments

Comments
 (0)