Skip to content

Add incentives examples - #554

Open
dorasun wants to merge 9 commits into
mainfrom
add_incentives_example
Open

dorasun wants to merge 9 commits into
mainfrom
add_incentives_example

Conversation

@dorasun

@dorasun dorasun commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Change-Id: I57fa8a776fb8a1cbd43f6c1d3a1a71c3c63bdd19

Change-Id: I57fa8a776fb8a1cbd43f6c1d3a1a71c3c63bdd19
@dorasun
dorasun requested a review from a team as a code owner July 15, 2026 18:19
@dorasun
dorasun requested review from Raibaz and sundquist July 15, 2026 18:19
Raibaz
Raibaz previously approved these changes Jul 16, 2026
Change-Id: I2f4db5b40ddc0494f631b62d60b6992f786cbf57
Raibaz
Raibaz previously approved these changes Jul 17, 2026
@dorasun
dorasun requested a review from bobhancockg July 17, 2026 19:32
@bobhancockg

Copy link
Copy Markdown
Contributor

Code Vetting & Review Recommendations

Overall, the implementation for adding incentive examples (apply_incentive.rb and fetch_incentive.rb) is well-structured. Below are recommended improvements to align with google-ads-ruby repository standards, fix documentation indexing tags, ensure type safety, and standardize monetary formatting.


1. examples/incentives/apply_incentive.rb

  • Default Parameter Value: Add country_code = nil to the method signature so calling apply_incentive(customer_id, incentive_id) programmatically works without explicitly passing nil:
    def apply_incentive(customer_id, incentive_id, country_code = nil)
  • Type Safety for selected_incentive_id: Explicitly call .to_i on incentive_id when constructing request_args for protobuf field type safety (int64):
    request_args = {
      customer_id: customer_id,
      selected_incentive_id: incentive_id.to_i
    }
  • CLI Default Initializers & Validation: Initialize options[:incentive_id] = 'INSERT_INCENTIVE_ID_HERE' at the top of if __FILE__ == $0 to match the doc comments, and update argument validation accordingly:
    options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'
    options[:incentive_id] = 'INSERT_INCENTIVE_ID_HERE'
    if options[:customer_id].nil? ||
        options[:customer_id] == 'INSERT_CUSTOMER_ID_HERE' ||
        options[:incentive_id].nil? ||
        options[:incentive_id] == 'INSERT_INCENTIVE_ID_HERE'
      puts 'Missing required arguments. See usage:'
      puts 'Customer ID and Incentive ID are required.'
      exit 1
    end

2. examples/incentives/fetch_incentive.rb

  • Documentation Region Tags: Add # [START fetch_incentive] and # [END fetch_incentive] region tags around the main method so Google Developers documentation (devsite) can automatically index the code snippet.
  • Standardize Currency Formatting in format_money: Simplify calculation to cleanly format zero, fractional, and negative currency values with standard 2 decimal places:
    def format_money(money)
      return 'N/A' if money.nil?
    
      amount = money.units.to_f + (money.nanos.to_f / 1_000_000_000.0)
      sprintf('%.2f %s', amount, money.currency_code)
    end
  • CLI Option Placeholder & Check: Initialize options[:email] = 'INSERT_EMAIL_HERE' and validate against INSERT_EMAIL_HERE in if __FILE__ == $0.
Comment thread examples/incentives/apply_incentive.rb Resolved
Change-Id: I19de34550a54efaa8095b503bd5e8c449930e9d4
Comment thread examples/incentives/apply_incentive.rb Resolved
Comment thread examples/incentives/apply_incentive.rb Resolved
Comment thread examples/incentives/fetch_incentives.rb Resolved
Comment thread examples/incentives/fetch_incentives.rb Resolved
Comment thread examples/incentives/fetch_incentives.rb Resolved
Change-Id: I4f3b19fe5ace2a6d88f7f0c3b90906f97b0d454b
@dorasun
dorasun removed the request for review from sundquist August 14, 2026 20:33
@dorasun
dorasun requested a review from bobhancockg August 25, 2026 21:37

@bobhancockg bobhancockg 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.

Overall, the implementation for adding incentive examples is well-structured and incorporates previous feedback nicely. Here are a few remaining recommendations and optimizations before merging:

  1. examples/incentives/apply_incentive.rb:

    • Clean up redundant request_args[:country_code] = country_code if country_code duplicate assignment on line 36.
  2. examples/incentives/fetch_incentive.rb:

    • Update request field name from type: :ACQUISITION to incentive_type: :ACQUISITION to match current Google Ads API protobuf definitions (v24+) and avoid runtime ArgumentError.
    • Provide default nil arguments in def fetch_incentive(email, language_code = nil, country_code = nil) and construct request args using .compact.
    • Fix missing whitespace in string continuation on lines 51-52 ("type." \ "Non-CYO" -> "type.Non-CYO").
    • Defensively format monetary currency strings against empty protobuf defaults ("").
Comment thread examples/incentives/apply_incentive.rb Resolved
Comment thread examples/incentives/fetch_incentive.rb Resolved
Comment thread examples/incentives/fetch_incentive.rb Resolved
Comment thread examples/incentives/fetch_incentive.rb Resolved
Change-Id: I6dfd7bc56bafdf1910e5e35209600f3bc52a6e84
@dorasun
dorasun requested a review from bobhancockg September 15, 2026 16:11
@bobhancockg

Copy link
Copy Markdown
Contributor

Updated the PR with the following optimizations:

  • Parameter Defaults & API Alignment:
    • : Defaulted country_code to 'US' (required by API proto schema) rather than nil to avoid INVALID_ARGUMENT when omitted.
    • : Provided default values (language_code = 'en', country_code = 'US') matching API proto defaults.
  • Defensive Protobuf Traversal:
    • Used incentive_id&.to_i to prevent coercing nil to 0.
    • Added safe navigation (response.incentive_offer&.cyo_incentives).
    • Added !field.to_s.empty? checks for protobuf strings before output.
    • Improved requirement fallback message when spend requirement is absent.
    • Cleaned up format_money currency formatting.
  • Documentation / Code Snippet Tags:
    • Extended [START fetch_incentive] / [END fetch_incentive] scope to encompass helper functions (print_incentive_details, format_requirement, format_money) so extracted DevSite snippets are complete and runnable.
  • Diagnostics & Error Reporting:
    • Surfaced e.request_id in stderr when catching GoogleAdsError across both scripts.
    • Standardized CLI parameter validation to report the exact missing flag with OptionParser usage banner.
@Raibaz
Raibaz self-requested a review October 7, 2026 15:44
Raibaz
Raibaz previously approved these changes Oct 7, 2026
Comment thread examples/incentives/fetch_incentive.rb Resolved
Comment thread examples/incentives/fetch_incentive.rb Resolved
Comment thread examples/incentives/fetch_incentive.rb Resolved
Comment thread examples/incentives/apply_incentive.rb Resolved
- Add shebang and Encoding header
- Remove trailing whitespace after .compact
- Surface consolidated terms and conditions URL when present in fetch_incentive
- Validate against empty email string in CLI options
- Add fallback confirmation message when incentive applied without coupon code or creation time

Change-Id: I5a0ed0cd2a2ef3744b28c6f83a47a12dfd2cb24d
@@ -0,0 +1,168 @@
#!/usr/bin/env ruby

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.

  1. DevSite filename alignment (fetch_incentives.rb): The DevSite Incentives guide (docs/billing/incentives.md) and sample page (samples/fetch-incentives.md) reference code_example_id='incentives/fetch_incentives' (plural, matching fetch_incentives.py in Python, FetchIncentives.java in Java, and FetchIncentives.cs in .NET), which resolves to examples/incentives/fetch_incentives.rb. Consider renaming this file to examples/incentives/fetch_incentives.rb so DevSite snippet inclusion works out of the box without custom path overrides.
  2. Executable file mode (100755) & header: Since #!/usr/bin/env ruby and Usage: %s [options] were added for standalone script execution, please chmod +x (100755) this file (currently 100644). Also, # Encoding: utf-8 on line 2 can be removed since UTF-8 is the default source encoding in Ruby 2.0+.
Comment thread examples/incentives/fetch_incentive.rb Outdated
response = client.service.incentive.fetch_incentive(request_args)

# Processes the response.
if response.incentive_offer.nil?

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.

When no incentive is available for a user, the API returns a populated IncentiveOffer with offer_type == :NO_INCENTIVE and cyo_incentives unset (nil). Currently, that case skips this nil? check and falls into the else branch on line 58 (printing 'Incentive offer is not a CHOOSE_YOUR_OWN_INCENTIVE type...').

Checking for :NO_INCENTIVE here handles empty offers accurately (and allows removing the redundant &. on line 49):

Suggested change
if response.incentive_offer.nil?
if response.incentive_offer.nil? || response.incentive_offer.offer_type == :NO_INCENTIVE
Comment thread examples/incentives/fetch_incentive.rb Outdated
parser.parse!

# Check if required parameters are present.
if options[:email].to_s.empty? || options[:email] == 'INSERT_EMAIL_HERE'

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.

Since fetch_incentive strips whitespace on line 32 (email.to_s.strip), using .strip.empty? here ensures whitespace-only input (e.g., -E " ") is caught during CLI validation rather than sending an empty email: "" to the API:

Suggested change
if options[:email].to_s.empty? || options[:email] == 'INSERT_EMAIL_HERE'
if options[:email].to_s.strip.empty? || options[:email] == 'INSERT_EMAIL_HERE'
@@ -0,0 +1,138 @@
#!/usr/bin/env ruby

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.

Since #!/usr/bin/env ruby and Usage: %s [options] are used for standalone execution, please chmod +x (100755) this file (currently committed with mode 100644). Also, # Encoding: utf-8 on line 2 is redundant in Ruby 2.0+ and can be removed.

Comment thread examples/incentives/apply_incentive.rb Outdated
# Issues the request.
request_args = {
customer_id: customer_id.to_s.tr('-', ''),
selected_incentive_id: incentive_id&.to_i,

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.

If apply_incentive is called programmatically with a non-numeric string (such as an unreplaced placeholder 'INSERT_INCENTIVE_ID_HERE'), incentive_id&.to_i silently coerces it to 0 (selected_incentive_id: 0). Using Integer(incentive_id) when incentive_id is present fails fast with an ArgumentError on invalid input:

Suggested change
selected_incentive_id: incentive_id&.to_i,
selected_incentive_id: incentive_id ? Integer(incentive_id) : nil,
Comment thread examples/incentives/apply_incentive.rb Outdated
exit 1
end

if options[:country_code].to_s.empty?

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.

Use .strip.empty? (and strip country_code in request_args on line 38) to guard against whitespace-only --country-code values:

Suggested change
if options[:country_code].to_s.empty?
if options[:country_code].to_s.strip.empty?
…ssions, NO_INCENTIVE handling, and validation

Change-Id: I3fc292a3b6a8f3180c12ede0f1e7982e32179b38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants