Skip to content

fix(dev): ensure Ads and Common Protos new component parameters are derived correctly - #9691

Open
cy-yun wants to merge 3 commits into
mainfrom
dev-derive-ads-common-protos
Open

cy-yun wants to merge 3 commits into
mainfrom
dev-derive-ads-common-protos

Conversation

@cy-yun

@cy-yun cy-yun commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Ensures that component parameters for Google Ads APIs and Common Protos libraries are derived correctly when running component:new.

Fixes #9387

Summary of Changes

  • Google Ads APIs (Google\Ads):
    • Sets Composer package vendor to googleads/ (e.g. googleads/ad-manager, googleads/data-manager, googleads/marketingplatform-admin).
    • Correctly hyphenates trailing -manager and strips ads- prefix.
    • Sets GitHub repository to googleapis/php-ads-[project-name].
    • Normalizes package name even if a versioned proto package is provided.
  • Common Protos (No Protobuf Service):
    • Adds hasGapicClient detection to check for protobuf service definitions in proto contents.
    • Strips trailing type and common proto and PHP namespace segments.
    • Appends CommonProtos to component name (e.g. GeoCommonProtos, ShoppingCommonProtos).
    • Appends -common-protos to Composer package and GitHub repository names.
    • Allows empty api_shortname without erroring when no default_host is defined in the proto.
    • Sets library_type to CORE in .repo-metadata-full.json.
  • Tests:
    • Added unit test cases in NewComponentTest and ComponentNewCommandTest covering Ads APIs and Common Protos libraries.

…erived correctly

- Support Google\Ads namespace by using vendor googleads/, hyphenating project name, and setting github repo to googleapis/php-ads-*
- Support CommonProtos by detecting missing protobuf service definitions, stripping type/common subpackages, appending CommonProtos to component name, and setting repo metadata library_type to CORE
- Allow empty api_shortname when no default_host is defined

Fixes #9387
@cy-yun
cy-yun requested a review from a team as a code owner September 14, 2026 22:39

@bshaffer bshaffer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks good but the changes are way too complex for what I had in mind. I think there are a lot of opportunities to simplify things

Comment thread dev/src/NewComponent.php Outdated
Comment on lines +156 to +175
if (str_starts_with($phpNamespace, 'Google\\Ads')) {
if (count($parts) > 1 && 'v' === strtolower($parts[count($parts) - 1][0] ?? '')) {
array_pop($parts);
}
$name = str_replace(
['google.', 'devtools.cloud', '.'],
['', 'cloud-', '-'],
implode('.', $parts)
);
if (str_starts_with($name, 'ads-')) {
$name = substr($name, 4);
}
if (str_ends_with($name, 'manager') && !str_ends_with($name, '-manager')) {
$name = substr($name, 0, -7) . '-manager';
}
if (!$hasGapicClient && !str_ends_with($name, '-common-protos')) {
$name .= '-common-protos';
}
return 'googleads/' . $name;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is overly complicated. We don't need special handling for all of these cases, but rather should just use googleads instead of google if the phpNamespace starts with Google\Ads

Comment thread dev/src/NewComponent.php Outdated
Comment on lines +220 to +228
while (count($parts) > 1) {
$last = end($parts);
if ('v' === $last[0]) {
array_pop($parts);
} elseif (!$hasGapicClient && count($parts) > 2 && in_array($last, ['type', 'common'])) {
array_pop($parts);
} else {
break;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is also over complicated. Could simplify to

Suggested change
while (count($parts) > 1) {
$last = end($parts);
if ('v' === $last[0]) {
array_pop($parts);
} elseif (!$hasGapicClient && count($parts) > 2 && in_array($last, ['type', 'common'])) {
array_pop($parts);
} else {
break;
}
$last = end($parts);
if ('v' === $last[0] || in_array($last, ['type', 'common'])) {
array_pop($parts);
}

Comment thread dev/src/NewComponent.php Outdated
Comment on lines +259 to +267
while (count($parts) > 1) {
$last = end($parts);
if ('v' === strtolower($last[0])) {
array_pop($parts);
} elseif (!$hasGapicClient && count($parts) > 2 && in_array(strtolower($last), ['type', 'common'])) {
array_pop($parts);
} else {
break;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We do not want to modify the proto namespace, we should take what the PHP namespace is from the file

Comment thread dev/src/NewComponent.php Outdated
Comment on lines +90 to +98
$hasGapicClient = !str_ends_with($new->componentName, 'CommonProtos');
if (!$hasGapicClient && !str_ends_with($new->displayName, 'Common Protos')) {
$new->displayName .= ' Common Protos';
}
$new->composerPackage = self::getComposerPackage(
$new->protoPackage,
$new->phpNamespace,
$hasGapicClient
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This logic is a bit odd, as it relies on the user to pass in CommonProtos as the component name. But if this is done, then we can also expect the user to pass in Common Protos as the display name, so there's no reason for us to write logic to do so.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, removed the display name mutation from fromOptions.

Comment thread dev/src/NewComponent.php Outdated
private static function getComposerPackage(
string $protoPackage,
string $phpNamespace,
bool $hasGapicClient = true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

instead of $hasGapicClient, let's just make it $isCommonProtos

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated to $isCommonProtos across the class.

Comment thread dev/src/NewComponent.php Outdated
return 'googleads/' . $name;
}

if (!$hasGapicClient && count($parts) > 2 && in_array(end($parts), ['type', 'common'])) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

simplify

Suggested change
if (!$hasGapicClient && count($parts) > 2 && in_array(end($parts), ['type', 'common'])) {
if (!$hasGapicClient && in_array(end($parts), ['type', 'common'])) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Simplified as suggested.

Comment thread dev/src/NewComponent.php Outdated
Comment on lines +55 to +61
if (!$hasGapicClient) {
if (!str_ends_with($new->componentName, 'CommonProtos')) {
$new->componentName .= 'CommonProtos';
}
if (!str_ends_with($new->displayName, 'Common Protos')) {
$new->displayName .= ' Common Protos';
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This logic should be in getDisplayName and getComponentName respectively

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Moved the CommonProtos naming logic into getDisplayName and getComponentName.

@cy-yun

cy-yun commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Updated to simplify per review feedback:

  • Renamed $hasGapicClient to $isCommonProtos across the class, eliminating inverted conditions.
  • Moved CommonProtos naming logic into getDisplayName and getComponentName.
  • Removed display name mutation from fromOptions.
  • Simplified getComposerPackage and extraction methods (extractPackageNameFromProtoContents, extractPhpNamespaceFromProtoContents) to remove verbose while loops.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dev: Ensure Ads and Common Protos new component parameters are derived correctly

2 participants