Skip to content

Commit 736803f

Browse files
authored
feat(migrate): block legacylibrarian release and generate (#4612)
Modifies or adds entries to .librarian/config.yaml to to block legacylibrarian generation and releasing of migrated libraries. This loses comments from the config.yaml file, but after migration it will be irrelevant anyway. Fixes #4610
1 parent c9b390f commit 736803f

3 files changed

Lines changed: 144 additions & 15 deletions

File tree

internal/legacylibrarian/legacyconfig/librarian_config.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,20 @@ const (
2626

2727
// LibrarianConfig defines the contract for the config.yaml file.
2828
type LibrarianConfig struct {
29-
GlobalFilesAllowlist []*GlobalFile `yaml:"global_files_allowlist"`
30-
Libraries []*LibraryConfig `yaml:"libraries"`
31-
TagFormat string `yaml:"tag_format"`
29+
GlobalFilesAllowlist []*GlobalFile `yaml:"global_files_allowlist,omitempty"`
30+
Libraries []*LibraryConfig `yaml:"libraries,omitempty"`
31+
TagFormat string `yaml:"tag_format,omitempty"`
3232
}
3333

3434
// LibraryConfig defines configuration for a single library, identified by its ID.
3535
type LibraryConfig struct {
36-
GenerateBlocked bool `yaml:"generate_blocked"`
37-
LibraryID string `yaml:"id"`
38-
NextVersion string `yaml:"next_version"`
39-
ReleaseBlocked bool `yaml:"release_blocked"`
40-
TagFormat string `yaml:"tag_format"`
36+
GenerateBlocked bool `yaml:"generate_blocked,omitempty"`
37+
LibraryID string `yaml:"id,omitempty"`
38+
NextVersion string `yaml:"next_version,omitempty"`
39+
ReleaseBlocked bool `yaml:"release_blocked,omitempty"`
40+
TagFormat string `yaml:"tag_format,omitempty"`
4141
// Whether to create a GitHub release for this library.
42-
SkipGitHubReleaseCreation bool `yaml:"skip_github_release_creation"`
42+
SkipGitHubReleaseCreation bool `yaml:"skip_github_release_creation,omitempty"`
4343
}
4444

4545
// GlobalFile defines the global files in language repositories.

tool/cmd/migrate/legacylibrarian.go

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ func runLibrarianMigration(ctx context.Context, language string, repoPath string
109109
if err := librarian.RunTidyOnConfig(ctx, repoPath, cfg); err != nil {
110110
return errTidyFailed
111111
}
112+
if err := blockLegacyGenerationAndRelease(repoPath, cfg); err != nil {
113+
return err
114+
}
112115
return nil
113116
}
114117

@@ -120,12 +123,12 @@ func runCompleteCleanLibrarianMigration(ctx context.Context, language string, re
120123
return nil, err
121124
}
122125

123-
librarianConfig, err := readConfig(repoPath)
126+
librarianConfig, err := readLegacyConfig(repoPath)
124127
if err != nil {
125128
return nil, err
126129
}
127130

128-
repoConfig, err := readRepoConfig(repoPath)
131+
repoConfig, err := readLegacyGoRepoConfig(repoPath)
129132
if err != nil {
130133
return nil, err
131134
}
@@ -201,6 +204,40 @@ func buildConfigFromLibrarian(ctx context.Context, input *MigrationInput) (*conf
201204
return cfg, nil
202205
}
203206

207+
// blockLegacyGenerationAndRelease ensures that all libraries in the librarian
208+
// config have generation and release blocked in the legacy config, by rewriting
209+
// .librarian/config.yaml. This was previously a file maintained by hand, so a
210+
// comment line is added at the start. This function assumes that the current
211+
// directory is the repository root.
212+
func blockLegacyGenerationAndRelease(repoPath string, cfg *config.Config) error {
213+
legacyConfig, err := readLegacyConfig(repoPath)
214+
if err != nil {
215+
return err
216+
}
217+
for _, lib := range cfg.Libraries {
218+
legacyLib := legacyConfig.LibraryConfigFor(lib.Name)
219+
if legacyLib == nil {
220+
legacyLib = &legacyconfig.LibraryConfig{
221+
LibraryID: lib.Name,
222+
}
223+
legacyConfig.Libraries = append(legacyConfig.Libraries, legacyLib)
224+
}
225+
legacyLib.GenerateBlocked = true
226+
legacyLib.ReleaseBlocked = true
227+
}
228+
configYaml, err := yaml.Marshal(legacyConfig)
229+
if err != nil {
230+
return err
231+
}
232+
comment := "# This file is being migrated to librarian@latest, and is no longer maintained by hand.\n\n"
233+
configYaml = append([]byte(comment), configYaml...)
234+
configFile := filepath.Join(repoPath, librarianDir, librarianConfigFile)
235+
if err := os.WriteFile(configFile, configYaml, 0644); err != nil {
236+
return err
237+
}
238+
return nil
239+
}
240+
204241
func fetchGoogleapis(ctx context.Context) (*config.Source, error) {
205242
return fetchGoogleapisWithCommit(ctx, githubEndpoints, fetch.DefaultBranchMaster)
206243
}
@@ -453,17 +490,23 @@ func isEmptyGoGAPICInfo(info *goGAPICInfo) bool {
453490
!info.NoMetadata
454491
}
455492

493+
// readLegacyState reads the legacylibrarian state file for the given
494+
// repository root directory.
456495
func readState(path string) (*legacyconfig.LibrarianState, error) {
457496
stateFile := filepath.Join(path, librarianDir, librarianStateFile)
458497
return yaml.Read[legacyconfig.LibrarianState](stateFile)
459498
}
460499

461-
func readConfig(path string) (*legacyconfig.LibrarianConfig, error) {
462-
configFile := filepath.Join(path, librarianDir, librarianConfigFile)
500+
// readLegacyConfig reads the legacylibrarian configuration file for the given
501+
// repository root directory.
502+
func readLegacyConfig(repoPath string) (*legacyconfig.LibrarianConfig, error) {
503+
configFile := filepath.Join(repoPath, librarianDir, librarianConfigFile)
463504
return yaml.Read[legacyconfig.LibrarianConfig](configFile)
464505
}
465506

466-
func readRepoConfig(path string) (*RepoConfig, error) {
507+
// readLegacyGoRepoConfig reads the legacylibrary Go-specific repository
508+
// configuration file for the given repository root directory.
509+
func readLegacyGoRepoConfig(path string) (*RepoConfig, error) {
467510
configFile := filepath.Join(path, librarianDir, "generator-input/repo-config.yaml")
468511
if _, err := os.Stat(configFile); err != nil {
469512
if os.IsNotExist(err) {

tool/cmd/migrate/legacylibrarian_test.go

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@ func TestReadRepoConfig(t *testing.T) {
10581058
},
10591059
} {
10601060
t.Run(test.name, func(t *testing.T) {
1061-
got, err := readRepoConfig(test.repoPath)
1061+
got, err := readLegacyGoRepoConfig(test.repoPath)
10621062
if test.wantErr != nil {
10631063
if !errors.Is(err, test.wantErr) {
10641064
t.Errorf("expected error containing %q, got: %v", test.wantErr, err)
@@ -1158,6 +1158,92 @@ func TestToAPIs(t *testing.T) {
11581158
}
11591159
}
11601160

1161+
func TestBlockLegacyGenerationAndRelease(t *testing.T) {
1162+
tempDir := t.TempDir()
1163+
if err := os.Mkdir(filepath.Join(tempDir, librarianDir), 0755); err != nil {
1164+
t.Fatal(err)
1165+
}
1166+
originalConfig := &legacyconfig.LibrarianConfig{
1167+
TagFormat: "xyz",
1168+
Libraries: []*legacyconfig.LibraryConfig{
1169+
{
1170+
LibraryID: "not-migrated",
1171+
},
1172+
{
1173+
LibraryID: "not-migrated-already-generate-blocked",
1174+
GenerateBlocked: true,
1175+
},
1176+
{
1177+
LibraryID: "migrated-already-generate-blocked",
1178+
GenerateBlocked: true,
1179+
},
1180+
{
1181+
LibraryID: "migrated",
1182+
NextVersion: "1.2.3",
1183+
},
1184+
},
1185+
}
1186+
configFile := filepath.Join(tempDir, librarianDir, librarianConfigFile)
1187+
if err := yaml.Write(configFile, originalConfig); err != nil {
1188+
t.Fatal(err)
1189+
}
1190+
migratedConfig := &config.Config{
1191+
Libraries: []*config.Library{
1192+
{Name: "migrated-already-generate-blocked"},
1193+
{Name: "not-previously-in-config"},
1194+
{Name: "migrated"},
1195+
},
1196+
}
1197+
if err := blockLegacyGenerationAndRelease(tempDir, migratedConfig); err != nil {
1198+
t.Fatal(err)
1199+
}
1200+
wantConfig := &legacyconfig.LibrarianConfig{
1201+
TagFormat: "xyz",
1202+
Libraries: []*legacyconfig.LibraryConfig{
1203+
{
1204+
LibraryID: "not-migrated",
1205+
},
1206+
{
1207+
LibraryID: "not-migrated-already-generate-blocked",
1208+
GenerateBlocked: true,
1209+
},
1210+
{
1211+
LibraryID: "migrated-already-generate-blocked",
1212+
GenerateBlocked: true,
1213+
ReleaseBlocked: true,
1214+
},
1215+
{
1216+
LibraryID: "migrated",
1217+
NextVersion: "1.2.3",
1218+
GenerateBlocked: true,
1219+
ReleaseBlocked: true,
1220+
},
1221+
{
1222+
LibraryID: "not-previously-in-config",
1223+
GenerateBlocked: true,
1224+
ReleaseBlocked: true,
1225+
},
1226+
},
1227+
}
1228+
gotConfig, err := readLegacyConfig(tempDir)
1229+
if err != nil {
1230+
t.Fatal(err)
1231+
}
1232+
if diff := cmp.Diff(wantConfig, gotConfig); diff != "" {
1233+
t.Errorf("mismatch (-want +got):\n%s", diff)
1234+
}
1235+
}
1236+
1237+
func TestBlockLegacyGenerationAndRelease_Error(t *testing.T) {
1238+
tempDir := t.TempDir()
1239+
migratedConfig := &config.Config{}
1240+
gotErr := blockLegacyGenerationAndRelease(tempDir, migratedConfig)
1241+
wantErr := os.ErrNotExist
1242+
if !errors.Is(gotErr, wantErr) {
1243+
t.Errorf("blockLegacyGenerationAndRelease error = %v, wantErr %v", gotErr, wantErr)
1244+
}
1245+
}
1246+
11611247
func TestFetchGoogleapisWithCommit(t *testing.T) {
11621248
const (
11631249
wantCommit = "abcd123"

0 commit comments

Comments
 (0)