Skip to content

chore: add Kokoro release config and script for OSS Exit Gate - #570

Open
zarturod wants to merge 1 commit into
googleads:mainfrom
zarturod:chore/oss-exit-gate-kokoro-release
Open

zarturod wants to merge 1 commit into
googleads:mainfrom
zarturod:chore/oss-exit-gate-kokoro-release

Conversation

@zarturod

Copy link
Copy Markdown

Summary

Adds .kokoro/release.cfg and .kokoro/release.sh to migrate google-ads-ruby releases (RubyGems (google-ads-googleads)) to OSS Exit Gate (google-ads-ruby/rubygems) via the BAM DevRel Kokoro RBE release pool:

  • Builds release artifacts in the Kokoro release container (ubuntu2204/full:current).
  • Stages built artifacts to the internal OSS Exit Gate Artifact Registry staging repository (oss-exit-gate-prod).
  • Supports DRY_RUN=true (default) to stage and validate artifacts without publishing, and DRY_RUN=false to upload manifest.json to gs://oss-exit-gate-prod-projects-bucket/google-ads-ruby/rubygems/manifests to trigger automated BCID verification and production release.

Related Internal CLs

  • Exit Gate Project Config (google-ads-ruby/rubygems): http://cl/1009122561 (submitted) & http://cl/1009709985
  • Kokoro Release Job Config (ads-api-devrel/bam-devrel/aim/google-ads-ruby-release.cfg): http://cl/1009766855

@zarturod
zarturod requested a review from a team as a code owner October 29, 2026 17:00
Comment thread .kokoro/release.sh
if [[ -f "third_party/rspec/caller_filter.rb" ]]; then
cp third_party/rspec/caller_filter.rb lib/google/ads/google_ads/deprecation.rb
fi
gem build google-ads-googleads.gemspec

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.

gem build here bypasses the repo's own release build, rake build (task :build => [:copy_code, :codegen, :validate_protos, :file_permissions]). The script re-implements copy_third_party_code by hand (lines 21-23) but drops the other two steps that matter for a published gem:

  • file_permissions (chmod -R ugo+r .): the gemspec globs lib/** and gem build preserves file modes, so a restrictive umask on the Kokoro worker would ship a gem whose files aren't world-readable (the historical reason this task exists).
  • validate_protos: the only check that every generated v* module actually loads before we publish.

Suggest either calling the Rake tasks (bundle exec rake copy_code validate_protos file_permissions && gem build ..., or rake build and pick the gem up from pkg/), or at minimum adding chmod -R ugo+r lib and a ruby -Ilib -e 'require "google/ads/google_ads"' smoke test before building. Either way, please log ruby --version / gem --version at the top so a container image bump that changes the Ruby version is visible in the release log.

Comment thread .kokoro/release.sh
fi
gem build google-ads-googleads.gemspec

GEM_FILE="$(ls google-ads-googleads-*.gem | head -n 1)"

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.

The -z check on line 27 is unreachable: with set -e -o pipefail, a no-match ls fails the pipeline, the failed command substitution fails the assignment, and the script exits before the if. The version is also already known from the source of truth, so the glob can go entirely:

Suggested change
GEM_FILE="$(ls google-ads-googleads-*.gem | head -n 1)"
PACKAGE_VERSION="$(ruby -Ilib -e 'require "google/ads/google_ads/version"; puts Google::Ads::GoogleAds::CLIENT_LIB_VERSION')"
PACKAGE_NAME="google-ads-googleads"
GEM_FILE="${PACKAGE_NAME}-${PACKAGE_VERSION}.gem"
if [[ ! -f "${GEM_FILE}" ]]; then
echo "ERROR: expected ${GEM_FILE} after gem build." >&2
exit 1
fi

(and drop lines 31-33). This also guarantees the manifest version matches what the gemspec stamped into the artifact rather than whatever .gem happened to sort first.

Comment thread .kokoro/release.sh
--location="${EXIT_GATE_LOCATION}" \
--repository="${EXIT_GATE_REPOSITORY}" &>/dev/null; then
echo "=== Deleting existing package '${PACKAGE_NAME}' from Exit Gate staging repository ==="
gcloud artifacts packages delete "${PACKAGE_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 deletes every staged version of google-ads-googleads from the prod Exit Gate staging repo, and it runs on every invocation including the default DRY_RUN=true. go/oss-exit-gate-release-rubygems does suggest cleaning AR before a build, but combined with a dry-run default it means: someone kicks a dry run to test the pipeline while a real release is staged-but-not-yet-manifested, and the real artifact is gone. The Exit Gate only needs the version being published to be absent, so I'd scope this to the version being re-staged:

if gcloud artifacts versions describe "${PACKAGE_VERSION}" --package="${PACKAGE_NAME}" ... &>/dev/null; then
  gcloud artifacts versions delete "${PACKAGE_VERSION}" --package="${PACKAGE_NAME}" ... --quiet
fi

and keep the manifest at publish_all: false (as it is) so stray versions can never be published by accident. If you want the full-package wipe as a maintenance step, gate it behind an explicit CLEAN_STAGING=true rather than running it unconditionally.

Comment thread .kokoro/release.sh
echo "=== Uploading ${GEM_FILE} to Exit Gate Ruby Artifact Registry ==="
set +x
ACCESS_TOKEN="$(gcloud auth print-access-token)"
curl -fsSL -X POST \

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.

Two things here:

  1. The bearer token is passed as a curl argument, so it is visible in /proc/<pid>/cmdline / ps on the worker for the duration of the upload; set +x only hides it from the shell trace (and the set +x on line 56 is a no-op since -x was never enabled). The documented path for this registry is gem push, which reads the token from the environment:
GEM_HOST_API_KEY="Bearer $(gcloud auth print-access-token)" \
  gem push "${GEM_FILE}" --host "https://us-ruby.pkg.dev/${EXIT_GATE_PROJECT}/${EXIT_GATE_REPOSITORY}"

(see go/oss-exit-gate-release-rubygems "Update Your Build Script to Publish to AR"). That also removes the hand-built /api/v1/gems URL and gives you RubyGems' own error reporting.

  1. If you keep curl, replace -f with --fail-with-body (curl 7.76+, present on 22.04): -f discards the response body on 4xx/5xx, which is exactly the AR error message you'll need when a release fails at 2am.

Comment thread .kokoro/release.sh
EOF

EXIT_GATE_BUCKET="gs://oss-exit-gate-prod-projects-bucket/google-ads-ruby/rubygems/manifests"
MANIFEST_NAME="manifest-$(date +%Y%m%d%H%M%S).json"

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.

Nit: include the version in the manifest object name (manifest-${PACKAGE_VERSION}-$(date -u +%Y%m%dT%H%M%SZ).json) so the GCS listing is self-describing when auditing which manifest triggered which release, and use UTC so timestamps don't depend on the worker's TZ.

Comment thread .kokoro/release.cfg

container_properties {
docker_image: "us-central1-docker.pkg.dev/kokoro-container-bakery/kokoro/ubuntu/ubuntu2204/full:current"
}

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.

Consider retaining the release inputs as Kokoro artifacts so a published gem can be matched back to the exact build that produced it:

action {
  define_artifacts {
    regex: "github/google-ads-ruby/*.gem"
    regex: "github/google-ads-ruby/manifest*.json"
  }
}

Also worth an explicit timeout_mins so a hung upload fails fast rather than holding a pool slot.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please revert this PR, we are not ready to do this migration.
Pls reach out to anash@ to discuss the specifics.

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.

3 participants