Skip to content
This repository was archived by the owner on Jun 30, 2026. It is now read-only.

Commit d83d25a

Browse files
authored
chore: Toys tool to generate updates (#9142)
1 parent 029b558 commit d83d25a

7 files changed

Lines changed: 198 additions & 95 deletions

File tree

.github/workflows/autoapprove.yml

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Daily-Generate-Updates
2+
on:
3+
schedule:
4+
- cron: '02 13 * * *'
5+
6+
jobs:
7+
generate-updates:
8+
if: ${{ github.repository == 'googleapis/elixir-google-api' }}
9+
runs-on: ubuntu-latest
10+
env:
11+
GITHUB_TOKEN: ${{ secrets.YOSHI_CODE_BOT_TOKEN }}
12+
APPROVAL_GITHUB_TOKEN: ${{secrets.YOSHI_APPROVER_TOKEN}}
13+
steps:
14+
- name: Checkout repo
15+
uses: actions/checkout@v2
16+
- name: Install Ruby
17+
uses: ruby/setup-ruby@v1
18+
with:
19+
ruby-version: "3.0"
20+
- name: Install Elixir
21+
uses: erlef/setup-elixir@v1
22+
with:
23+
otp-version: "23.3.4.10"
24+
elixir-version: "1.12.3"
25+
- name: Install tools
26+
run: "gem install --no-document toys"
27+
- name: execute
28+
run: |
29+
toys generate-updates -v --fork --all
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Generate-Updates
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
args:
6+
description: "Extra command line arguments."
7+
required: false
8+
9+
jobs:
10+
generate-updates:
11+
if: ${{ github.repository == 'googleapis/elixir-google-api' }}
12+
runs-on: ubuntu-latest
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.YOSHI_CODE_BOT_TOKEN }}
15+
APPROVAL_GITHUB_TOKEN: ${{secrets.YOSHI_APPROVER_TOKEN}}
16+
steps:
17+
- name: Checkout repo
18+
uses: actions/checkout@v2
19+
- name: Install Ruby
20+
uses: ruby/setup-ruby@v1
21+
with:
22+
ruby-version: "3.0"
23+
- name: Install Elixir
24+
uses: erlef/setup-elixir@v1
25+
with:
26+
otp-version: "23.3.4.10"
27+
elixir-version: "1.12.3"
28+
- name: Install tools
29+
run: "gem install --no-document toys"
30+
- name: execute
31+
run: |
32+
toys generate-updates -v --fork ${{ github.event.inputs.args }}

.toys/.toys.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
expand :clean, paths: :gitignore
16+
17+
if ENV["RUBY_COMMON_TOOLS"]
18+
common_tools_dir = File.expand_path ENV["RUBY_COMMON_TOOLS"]
19+
load File.join(common_tools_dir, "toys", "yoshi")
20+
else
21+
load_git remote: "https://github.com/googleapis/ruby-common-tools.git",
22+
path: "toys/yoshi",
23+
update: true
24+
end

.toys/generate-updates.rb

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
desc "Run standard Google client generation."
16+
17+
flag :git_remote, "--remote=NAME" do
18+
desc "The name of the git remote to use as the pull request head. If omitted, does not open a pull request."
19+
end
20+
flag :enable_fork, "--fork" do
21+
desc "The github user for whom to create/use a fork"
22+
end
23+
flag :approval_token, "--approval-token" do
24+
default ENV["APPROVAL_GITHUB_TOKEN"]
25+
desc "GitHub token for adding labels and approving pull requests"
26+
end
27+
flag :all do
28+
desc "Generate all APIs"
29+
end
30+
flag :clean do
31+
desc "Open a PR to clean out old APIs if needed"
32+
end
33+
34+
remaining_args :requested do
35+
desc "Requested api names"
36+
end
37+
38+
include :exec, e: true
39+
include :git_cache
40+
include :terminal
41+
42+
include "yoshi-pr-generator"
43+
44+
def run
45+
require "json"
46+
Dir.chdir context_directory
47+
48+
yoshi_utils.git_ensure_identity
49+
if enable_fork
50+
set :git_remote, "pull-request-fork" unless git_remote
51+
yoshi_utils.gh_ensure_fork remote: git_remote
52+
end
53+
54+
@timestamp = Time.now.utc.strftime("%Y%m%d-%H%M%S")
55+
setup_builds
56+
api_names = list_apis
57+
api_names.each_with_index do |entry, index|
58+
handle_package entry, index + 1, api_names.size
59+
end
60+
end
61+
62+
def setup_builds
63+
exec ["mix", "deps.get"]
64+
end
65+
66+
def list_apis
67+
return requested unless all
68+
api_list = JSON.parse File.read "#{context_directory}/config/apis.json"
69+
api_list.map { |entry| entry["name"] }.uniq.compact.shuffle
70+
end
71+
72+
def handle_package api_name, index, total
73+
branch_name = "gen/#{api_name}-#{@timestamp}"
74+
commit_message = "feat: Automated regeneration of #{api_name} client"
75+
if open_pr_exists? commit_message
76+
puts "(#{index}/#{total}) Pull request already exists for #{api_name}", :yellow
77+
return
78+
end
79+
approval_message = "Rubber-stamped client auto-generation!"
80+
result = yoshi_pr_generator.capture enabled: !git_remote.nil?,
81+
remote: git_remote,
82+
branch_name: branch_name,
83+
commit_message: commit_message,
84+
labels: ["do not merge"],
85+
auto_approve: approval_message,
86+
approval_token: approval_token do
87+
generate_package api_name
88+
end
89+
case result
90+
when Integer
91+
puts "(#{index}/#{total}) Opened pull request #{result} for #{api_name}", :green, :bold
92+
when :unchanged
93+
puts "(#{index}/#{total}) No changes for #{api_name}", :magenta
94+
else
95+
puts "(#{index}/#{total}) Generated #{api_name}", :cyan
96+
end
97+
end
98+
99+
def open_pr_exists? title
100+
content = capture ["gh", "pr", "list", "--search", "\"#{title}\" in:title", "--state=open", "--json=number"]
101+
!JSON.parse(content).empty?
102+
end
103+
104+
def generate_package api_name
105+
lower_api_name = api_name.gsub(/([A-Z]+)([A-Z][a-z])/, "\\1_\\2").gsub(/([a-z0-9])([A-Z])/, "\\1_\\2").downcase
106+
exec ["mix", "google_apis.generate", api_name]
107+
unless capture(["git", "status", "--porcelain", "clients/#{lower_api_name}"]).empty?
108+
exec ["mix", "google_apis.bump_version", api_name]
109+
end
110+
end

lib/google_apis/generator.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ defmodule GoogleApis.Generator do
3434
def rollback_if_not_significant(api_configs) do
3535
if !Enum.any?(api_configs, &(ChangeAnalyzer.has_changes_of_significance?(&1, :documentation))) do
3636
Logger.info("Found only discovery_revision and/or formatting changes. Not significant enough for a PR.")
37-
System.cmd("git", ["reset", "--hard"])
37+
directories = Enum.map(api_configs, &(GoogleApis.ApiConfig.library_directory(&1)))
38+
System.cmd("git", ["restore" | directories])
3839
end
3940
end
4041

synth.py

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,50 +14,6 @@
1414

1515
"""This script is used to synthesize generated parts of this library."""
1616

17-
from synthtool.__main__ import extra_args
18-
from synthtool import _tracked_paths
19-
import synthtool as s
2017
import synthtool.log as log
21-
import synthtool.shell as shell
22-
import logging
23-
import os
24-
import pathlib
25-
import shutil
26-
import tempfile
2718

28-
logging.basicConfig(level=logging.DEBUG)
29-
s.metadata.set_track_obsolete_files(False) # TODO: enable again.
30-
31-
# Copy the repo into a temporary directory, removing the build and deps, and
32-
# perform generation there. This is because the docker command may be a
33-
# cross-compile whose build environment should be isolated from the current
34-
# git clone.
35-
with tempfile.TemporaryDirectory() as tmpdir:
36-
repository = pathlib.Path(tmpdir) / "repo"
37-
shutil.copytree(os.getcwd(), repository)
38-
shutil.rmtree(repository / "_build", ignore_errors=True)
39-
shutil.rmtree(repository / "deps", ignore_errors=True)
40-
41-
image = "gcr.io/cloud-devrel-public-resources/elixir19"
42-
generate_command = "scripts/generate_client.sh"
43-
command = [
44-
"docker",
45-
"run",
46-
"--rm",
47-
f"-v{repository}:/workspace",
48-
"-v/var/run/docker.sock:/var/run/docker.sock",
49-
"-e", f"USER_GROUP={os.getuid()}:{os.getgid()}",
50-
"-w", "/workspace",
51-
image,
52-
generate_command]
53-
54-
if extra_args():
55-
command.extend(extra_args())
56-
57-
log.debug(f"Running: {' '.join(command)}")
58-
59-
shell.run(command, cwd=repository, hide_output=False)
60-
61-
# Copy the resulting clients directory back into the git clone.
62-
shutil.rmtree("clients", ignore_errors=True)
63-
shutil.move(repository / "clients", "clients")
19+
log.debug("Synthtool disabled for elixir")

0 commit comments

Comments
 (0)