-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Initial version of sample code to call payments reseller APIs #10146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Initial version of sample code to call payments reseller APIs #10146
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @miriyalavignesh, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces the initial set of Java sample code for interacting with the Google Payments Reseller Subscription APIs. The samples demonstrate how to provision subscriptions and generate user sessions, leveraging service account impersonation for authentication.
Highlights
- New Sample Directory: A new directory payments/reseller/subscription/snippets has been added to house the Java samples.
- API Interaction: Sample code for GenerateUserSession and ProvisionSubscription demonstrates core functionalities of the Payments Reseller Subscription API.
- Service Account Impersonation: A dedicated utility class ImpersonateServiceAccount is included to manage authentication via service account impersonation, which is crucial for these APIs.
- Maven Configuration: A pom.xml file is provided to manage project dependencies and define Maven profiles for easy execution of the sample applications.
- Constants Definition: A Constants.java file centralizes various IDs and configurations required for the API calls, improving maintainability.
- Setup Instructions: A README file guides users through the prerequisites and steps to set up their environment and run the samples.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces an initial set of Java sample code for the Payments Reseller Subscription API. The code demonstrates how to provision a subscription and generate a user session using service account impersonation. My review focuses on improving project configuration, error handling, code clarity, and documentation. Key suggestions include correcting the pom.xml
to use the required parent POM, fixing a critical error handling issue in the impersonation logic that could lead to NullPointerExceptions, removing dead code and unused imports, and improving the README instructions.
public ImpersonateServiceAccount(List<String> oauthScopes, String targetServiceAccount) { | ||
try { | ||
// File name output from: $gcloud auth application-default login | ||
GoogleCredentials sourceCredentials = GoogleCredentials.fromStream(new FileInputStream( | ||
USER_HOME.concat("/.config/gcloud/application_default_credentials.json"))); | ||
|
||
impersonatedCredentials = ImpersonatedCredentials.newBuilder() | ||
.setSourceCredentials(sourceCredentials) | ||
.setTargetPrincipal(targetServiceAccount) | ||
.setScopes(oauthScopes) | ||
.setDelegates(null) //Optional delegation | ||
.setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) | ||
.build(); | ||
|
||
} catch (IOException e) { | ||
System.err.println("Failed to get impersonated credentials: " + e.getMessage()); | ||
System.err.println( | ||
"Ensure your source credentials have the 'Service Account Token Creator' role on the target SA and that ADC is set up correctly."); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructor swallows the IOException
and only prints to System.err
. If an exception occurs (e.g., credentials file not found), impersonatedCredentials
will be null, leading to a NullPointerException
when its methods are called later. The constructor should propagate the IOException
to the caller to ensure proper error handling. The callers in main
methods already declare throws IOException
, so this change will not require further modifications there.
public ImpersonateServiceAccount(List<String> oauthScopes, String targetServiceAccount) throws IOException {
// File name output from: $gcloud auth application-default login
GoogleCredentials sourceCredentials = GoogleCredentials.fromStream(new FileInputStream(
USER_HOME.concat("/.config/gcloud/application_default_credentials.json")));
impersonatedCredentials = ImpersonatedCredentials.newBuilder()
.setSourceCredentials(sourceCredentials)
.setTargetPrincipal(targetServiceAccount)
.setScopes(oauthScopes)
.setDelegates(null) //Optional delegation
.setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY)
.build();
}
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR checklist indicates that the pom.xml
parent should be set to the latest shared-configuration
, but this is missing. Using the shared parent POM is important for maintaining consistency, managing dependencies, and inheriting standard plugin configurations across samples in the repository. Please add the parent configuration.
GoogleCredentials sourceCredentials = GoogleCredentials.fromStream(new FileInputStream( | ||
USER_HOME.concat("/.config/gcloud/application_default_credentials.json"))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The path to the application default credentials file is hardcoded. This is not robust as the location can vary, and it's not platform-independent. It's better to use GoogleCredentials.getApplicationDefault()
which automatically finds the credentials from the standard locations.
GoogleCredentials sourceCredentials = GoogleCredentials.getApplicationDefault();
List.of(ELIGIBILITY_ID)) | ||
.setPartnerPlanType(PLAN_TYPE) | ||
)) | ||
// .setLineItemPromotionSpecs(ImmutableList.of(new GoogleCloudPaymentsResellerSubscriptionV1SubscriptionPromotionSpec().setPromotion("partners/" + PARTNER_ID + "/promotions/" + PROMOTION))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You will need to be added to a specific allow list which will allow you to impersonate | ||
the service account `payment-reseller-test-serv-734@eng-diagram-369411.iam.gserviceaccount.com` | ||
|
||
<How to verify this as a developer?> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
ImpersonateServiceAccount impersonateServiceAccount = new ImpersonateServiceAccount(scopes, TARGET_SERVICE_ACCOUNT_EMAIL); | ||
impersonateServiceAccount.refreshCredentials(); | ||
System.out.println("Testing code " + impersonateServiceAccount.getImpersonatedCredentials()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new GoogleCloudPaymentsResellerSubscriptionV1YoutubePayload() | ||
.setPartnerEligibilityIds(List.of(ELIGIBILITY_ID)) | ||
.setPartnerPlanType(PLAN_TYPE))) | ||
// .setLineItemPromotionSpecs(ImmutableList.of(new GoogleCloudPaymentsResellerSubscriptionV1SubscriptionPromotionSpec().setPromotion("partners/" + PARTNER_ID + "/promotions/" + PROMOTION))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// .setPromotionSpecs(ImmutableList.of(new GoogleCloudPaymentsResellerSubscriptionV1SubscriptionPromotionSpec().setPromotion( | ||
// "partners/" + PARTNER_ID + "/promotions/" + PROMOTION_SUB_LEVEL))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} catch (Exception e) { | ||
System.err.println("Failed to provision subscription: " + e.getMessage()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catching a generic Exception
is generally discouraged. It's better to catch more specific exceptions that you expect, such as IOException
. Also, printing just the message (e.getMessage()
) can hide important context for debugging. For sample code, consider printing the full stack trace with e.printStackTrace()
.
} catch (Exception e) { | |
System.err.println("Failed to provision subscription: " + e.getMessage()); | |
} | |
} catch (IOException e) { | |
System.err.println("Failed to provision subscription:"); | |
e.printStackTrace(); | |
} |
// mvn clean compile | ||
// mvn exec:java -Dexec.mainClass="com.google.cloud.reseller.subscription.samples.ProvisionSubscription" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Description
Initial version of sample code to call payments reseller APIs
https://developers.google.com/payments/reseller/subscription
Checklist
pom.xml
parent set to latestshared-configuration
mvn clean verify
requiredmvn -P lint checkstyle:check
requiredmvn -P lint clean compile pmd:cpd-check spotbugs:check
advisory only