Skip to content

Commit a8e5bda

Browse files
authored
fix(devtools/cmd/migrate-sidekick): generate config for google-cloud-wkt (#3269)
To generate google-cloud-wkt using the librarian config created by migrate-sidekick tool, we need to - Add source roots at the module level - Add disabled rustdoc warnings at the module level Add a type alias for `[]string` because we need a way to marshal empty slice to `[]` but omit `nil`. To generate google-cloud-wkt: ``` migrate-sidekick . // wkt/src/generated librarian generate google-cloud-wkt // wkt/tests/common/src/generated librarian generate common ``` Result: ``` deleted: src/wkt/src/generated/.sidekick.toml deleted: src/wkt/tests/common/src/generated/.sidekick.toml ``` Note that the common package needs a 2nd command to generate as its package name is not `google-cloud-wkt`. Fixes #3200
1 parent aa2a59f commit a8e5bda

File tree

13 files changed

+332
-33
lines changed

13 files changed

+332
-33
lines changed

devtools/cmd/migrate-sidekick/main.go

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func readRootSidekick(repoPath string) (*config.Config, error) {
213213
ReleaseLevel: releaseLevel,
214214
Rust: &config.RustDefault{
215215
PackageDependencies: packageDependencies,
216-
DisabledRustdocWarnings: strToSlice(warnings),
216+
DisabledRustdocWarnings: strToSlice(warnings, false),
217217
GenerateSetterSamples: generateSetterSamples,
218218
},
219219
},
@@ -358,7 +358,7 @@ func buildGAPIC(files []string, repoPath string) (map[string]*config.Library, er
358358
}
359359

360360
if extraModules, ok := sidekick.Codec["extra-modules"].(string); ok {
361-
for _, module := range strToSlice(extraModules) {
361+
for _, module := range strToSlice(extraModules, false) {
362362
if module == "" {
363363
continue
364364
}
@@ -421,7 +421,7 @@ func buildGAPIC(files []string, repoPath string) (map[string]*config.Library, er
421421
rustCrate := &config.RustCrate{
422422
RustDefault: config.RustDefault{
423423
PackageDependencies: packageDeps,
424-
DisabledRustdocWarnings: strToSlice(disabledRustdocWarnings),
424+
DisabledRustdocWarnings: strToSlice(disabledRustdocWarnings, false),
425425
GenerateSetterSamples: generateSetterSamples,
426426
},
427427
PerServiceFeatures: strToBool(perServiceFeatures),
@@ -430,12 +430,12 @@ func buildGAPIC(files []string, repoPath string) (map[string]*config.Library, er
430430
TitleOverride: titleOverride,
431431
PackageNameOverride: packageNameOverride,
432432
RootName: rootName,
433-
Roots: strToSlice(roots),
434-
DefaultFeatures: strToSlice(defaultFeatures),
435-
IncludeList: strToSlice(includeList),
436-
IncludedIds: strToSlice(includeIds),
437-
SkippedIds: strToSlice(skippedIds),
438-
DisabledClippyWarnings: strToSlice(disabledClippyWarnings),
433+
Roots: strToSlice(roots, false),
434+
DefaultFeatures: strToSlice(defaultFeatures, false),
435+
IncludeList: strToSlice(includeList, false),
436+
IncludedIds: strToSlice(includeIds, false),
437+
SkippedIds: strToSlice(skippedIds, false),
438+
DisabledClippyWarnings: strToSlice(disabledClippyWarnings, false),
439439
HasVeneer: strToBool(hasVeneer),
440440
RoutingRequired: strToBool(routingRequired),
441441
IncludeGrpcOnlyMethods: strToBool(includeGrpcOnlyMethods),
@@ -522,9 +522,9 @@ func buildVeneer(files []string) (map[string]*config.Library, error) {
522522
return veneers, nil
523523
}
524524

525-
func buildModules(path string) ([]*config.RustModule, error) {
525+
func buildModules(rootDir string) ([]*config.RustModule, error) {
526526
var modules []*config.RustModule
527-
err := filepath.WalkDir(path, func(path string, d os.DirEntry, err error) error {
527+
err := filepath.WalkDir(rootDir, func(path string, d os.DirEntry, err error) error {
528528
if err != nil {
529529
return err
530530
}
@@ -533,6 +533,22 @@ func buildModules(path string) ([]*config.RustModule, error) {
533533
return nil
534534
}
535535

536+
if strings.Contains(path, "tests") {
537+
// Only use a .sidekick.toml in tests directory to represent a rust module if the following directory
538+
// exists:
539+
//
540+
// |-src
541+
// | |-generated
542+
// | |-.sidekick.toml
543+
// |-Cargo.toml
544+
// Only one pair of Cargo.toml and .sidekick.toml (within tests directory) is not comply this structure in
545+
// google-cloud-rust, which is wkt/Cargo.toml and src/wkt/tests/common/src/generated/.sidekick.toml.
546+
srcDir := strings.TrimSuffix(path, fmt.Sprintf("/src/generated/%s", sidekickFile))
547+
if rootDir != srcDir {
548+
return nil
549+
}
550+
}
551+
536552
sidekick, err := readTOML[SidekickConfig](path)
537553
if err != nil {
538554
return err
@@ -542,6 +558,17 @@ func buildModules(path string) ([]*config.RustModule, error) {
542558
includeList, _ := sidekick.Source["include-list"].(string)
543559
skippedIds, _ := sidekick.Source["skipped-ids"].(string)
544560
titleOverride, _ := sidekick.Source["title-override"].(string)
561+
moduleRoots := make(map[string]string)
562+
roots, ok := sidekick.Source["roots"].(string)
563+
if ok {
564+
for _, root := range strings.Split(roots, ",") {
565+
root = fmt.Sprintf("%s-root", root)
566+
modPath, ok := sidekick.Source[root].(string)
567+
if ok {
568+
moduleRoots[root] = modPath
569+
}
570+
}
571+
}
545572

546573
hasVeneer, _ := sidekick.Codec["has-veneer"].(string)
547574
includeGrpcOnlyMethods, _ := sidekick.Codec["include-grpc-only-methods"].(string)
@@ -551,15 +578,16 @@ func buildModules(path string) ([]*config.RustModule, error) {
551578
nameOverrides, _ := sidekick.Codec["name-overrides"].(string)
552579
postProcessProtos, _ := sidekick.Codec["post-process-protos"].(string)
553580
templateOverride, _ := sidekick.Codec["template-override"].(string)
581+
554582
generateSetterSamples, ok := sidekick.Codec["generate-setter-samples"].(string)
555583
if !ok {
556584
generateSetterSamples = "true"
557585
}
558586

559-
modules = append(modules, &config.RustModule{
587+
module := &config.RustModule{
560588
GenerateSetterSamples: strToBool(generateSetterSamples),
561589
HasVeneer: strToBool(hasVeneer),
562-
IncludedIds: strToSlice(includedIds),
590+
IncludedIds: strToSlice(includedIds, false),
563591
IncludeGrpcOnlyMethods: strToBool(includeGrpcOnlyMethods),
564592
IncludeList: includeList,
565593
ModulePath: modulePath,
@@ -569,11 +597,22 @@ func buildModules(path string) ([]*config.RustModule, error) {
569597
RoutingRequired: strToBool(routingRequired),
570598
ExtendGrpcTransport: strToBool(extendGrpcTransport),
571599
ServiceConfig: sidekick.General.ServiceConfig,
572-
SkippedIds: strToSlice(skippedIds),
600+
SkippedIds: strToSlice(skippedIds, false),
573601
Source: sidekick.General.SpecificationSource,
574602
Template: strings.TrimPrefix(templateOverride, "templates/"),
575603
TitleOverride: titleOverride,
576-
})
604+
}
605+
606+
if len(moduleRoots) > 0 {
607+
module.ModuleRoots = moduleRoots
608+
}
609+
610+
disabledRustdocWarnings, ok := sidekick.Codec["disabled-rustdoc-warnings"].(string)
611+
if ok {
612+
module.DisabledRustdocWarnings = strToSlice(disabledRustdocWarnings, true)
613+
}
614+
615+
modules = append(modules, module)
577616

578617
return nil
579618
})
@@ -657,8 +696,17 @@ func strToBool(s string) bool {
657696
return s == "true"
658697
}
659698

660-
func strToSlice(s string) []string {
699+
// strToSlice converts a comma-separated string into a slice of strings.
700+
//
701+
// The wantEmpty parameter controls the behavior when the input string is empty:
702+
// - If true: Returns an empty initialized slice (make([]string, 0)).
703+
// - If false: Returns nil.
704+
func strToSlice(s string, wantEmpty bool) []string {
661705
if s == "" {
706+
if wantEmpty {
707+
return make([]string, 0)
708+
}
709+
662710
return nil
663711
}
664712

devtools/cmd/migrate-sidekick/main_test.go

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,10 @@ func TestBuildVeneer(t *testing.T) {
414414
Rust: &config.RustCrate{
415415
Modules: []*config.RustModule{
416416
{
417-
GenerateSetterSamples: true,
418-
HasVeneer: true,
417+
DisabledRustdocWarnings: []string{},
418+
GenerateSetterSamples: true,
419+
ModuleRoots: nil,
420+
HasVeneer: true,
419421
IncludedIds: []string{
420422
".google.storage.v2.Storage.DeleteBucket",
421423
".google.storage.v2.Storage.GetBucket",
@@ -435,10 +437,13 @@ func TestBuildVeneer(t *testing.T) {
435437
{
436438
GenerateSetterSamples: false,
437439
ModulePath: "crate::generated::gapic_control::model",
438-
NameOverrides: ".google.storage.control.v2.IntelligenceConfig.Filter.cloud_storage_buckets=CloudStorageBucketsOneOf",
439-
Output: "testdata/build-veneer/success/lib-1/dir-2/dirdir-2",
440-
Source: "google/storage/control/v2",
441-
Template: "convert-prost",
440+
ModuleRoots: map[string]string{
441+
"project-root": ".",
442+
},
443+
NameOverrides: ".google.storage.control.v2.IntelligenceConfig.Filter.cloud_storage_buckets=CloudStorageBucketsOneOf",
444+
Output: "testdata/build-veneer/success/lib-1/dir-2/dirdir-2",
445+
Source: "google/storage/control/v2",
446+
Template: "convert-prost",
442447
},
443448
},
444449
},
@@ -452,6 +457,55 @@ func TestBuildVeneer(t *testing.T) {
452457
},
453458
},
454459
},
460+
{
461+
name: "google_cloud-wkt",
462+
files: []string{
463+
"testdata/build-veneer/wkt/Cargo.toml",
464+
"testdata/build-veneer/wkt/tests/common/Cargo.toml",
465+
},
466+
want: map[string]*config.Library{
467+
"common": {
468+
Name: "common",
469+
Veneer: true,
470+
Output: "testdata/build-veneer/wkt/tests/common",
471+
Version: "0.0.0",
472+
CopyrightYear: "2025",
473+
Rust: &config.RustCrate{
474+
Modules: []*config.RustModule{
475+
{
476+
DisabledRustdocWarnings: []string{},
477+
ModulePath: "crate::generated",
478+
ModuleRoots: map[string]string{
479+
"project-root": ".",
480+
},
481+
Output: "testdata/build-veneer/wkt/tests/common/src/generated",
482+
Source: "src/wkt/tests/protos",
483+
Template: "mod",
484+
},
485+
},
486+
},
487+
},
488+
"google-cloud-wkt": {
489+
Name: "google-cloud-wkt",
490+
Veneer: true,
491+
Output: "testdata/build-veneer/wkt",
492+
Version: "1.2.0",
493+
CopyrightYear: "2025",
494+
Rust: &config.RustCrate{
495+
Modules: []*config.RustModule{
496+
{
497+
GenerateSetterSamples: true,
498+
IncludeList: "api.proto,source_context.proto,type.proto,descriptor.proto",
499+
ModulePath: "crate",
500+
Output: "testdata/build-veneer/wkt/src/generated",
501+
Source: "google/protobuf",
502+
Template: "mod",
503+
},
504+
},
505+
},
506+
},
507+
},
508+
},
455509
} {
456510
t.Run(test.name, func(t *testing.T) {
457511
got, err := buildVeneer(test.files)

devtools/cmd/migrate-sidekick/testdata/build-veneer/success/lib-1/dir-1/.sidekick.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ name-overrides = '.google.storage.v2.Storage=StorageControl'
2121
include-grpc-only-methods = 'true'
2222
has-veneer = 'true'
2323
routing-required = 'true'
24+
disabled-rustdoc-warnings = ''

devtools/cmd/migrate-sidekick/testdata/build-veneer/success/lib-1/dir-2/dirdir-2/.sidekick.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
language = 'rust'
33
specification-source = 'google/storage/control/v2'
44

5+
[source]
6+
roots = 'project'
7+
project-root = '.'
8+
59
[codec]
610
copyright-year = '2025'
711
template-override = 'templates/convert-prost'
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Copyright 2024 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+
# https://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+
[package]
16+
description = "Google Cloud Client Libraries for Rust - Well Known Types"
17+
name = "google-cloud-wkt"
18+
# ATTENTION: if you change the major version, remember to change the major
19+
# version of all downstream dependencies. For details see:
20+
# https://github.com/googleapis/google-cloud-rust/issues/3237
21+
# https://github.com/googleapis/google-cloud-rust/issues/3265
22+
version = "1.2.0"
23+
# Inherit other attributes from the workspace.
24+
authors.workspace = true
25+
categories.workspace = true
26+
edition.workspace = true
27+
keywords.workspace = true
28+
license.workspace = true
29+
repository.workspace = true
30+
rust-version.workspace = true
31+
32+
[package.metadata.docs.rs]
33+
# Generate documentation for some of the optional conversions. It is too early
34+
# for `prost`.
35+
features = ["chrono", "time"]
36+
37+
[features]
38+
chrono = ["dep:chrono"]
39+
time = []
40+
# DO NOT USE: this allows us to detect semver changes in types used in the
41+
# implementation of client libraries. None of the types or functions gated
42+
# by this feature are intended for general use. We do not plan to document these
43+
# features and offer no guarantees on their stability.
44+
_internal-semver = []
45+
46+
[dependencies]
47+
base64.workspace = true
48+
bytes.workspace = true
49+
chrono = { workspace = true, optional = true }
50+
serde.workspace = true
51+
serde_json.workspace = true
52+
serde_with.workspace = true
53+
thiserror.workspace = true
54+
time = { workspace = true, features = ["formatting", "parsing"] }
55+
url.workspace = true
56+
57+
[dev-dependencies]
58+
anyhow.workspace = true
59+
test-case.workspace = true
60+
time = { workspace = true, features = ["formatting", "macros", "parsing"] }
61+
wkt = { path = ".", package = "google-cloud-wkt", features = ["chrono", "time"] }
62+
common = { path = "tests/common" }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2025 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+
# https://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+
[general]
16+
specification-source = 'google/protobuf'
17+
18+
[source]
19+
roots = 'protobuf-src'
20+
include-list = "api.proto,source_context.proto,type.proto,descriptor.proto"
21+
22+
[codec]
23+
copyright-year = '2025'
24+
template-override = 'templates/mod'
25+
module-path = 'crate'
26+
package-name-override = 'google-cloud-wkt'
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2025 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+
# https://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+
[package]
16+
name = "common"
17+
description = "Generated types for tests."
18+
version = "0.0.0"
19+
edition.workspace = true
20+
publish = false
21+
22+
[dependencies]
23+
bytes.workspace = true
24+
serde.workspace = true
25+
serde_json.workspace = true
26+
serde_with.workspace = true
27+
# Local dependencies
28+
wkt.workspace = true

0 commit comments

Comments
 (0)