Skip to content

Commit 705a37b

Browse files
authored
Fix config migration for removed rules (#3810)
1 parent 796ad31 commit 705a37b

File tree

9 files changed

+206
-2
lines changed

9 files changed

+206
-2
lines changed

.golangci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ linters:
175175
# because they all call createZipFromDir on the same path, writing to the same file.
176176
path: private/buf/cmd/buf/workspace_test.go
177177
text: missing the call to method parallel
178+
- linters:
179+
- paralleltest
180+
# This test shouldn't run in parallel as it needs osext.Getwd.
181+
path: private/buf/cmd/buf/command/config/configmigrate/configmigrate_test.go
182+
text: missing the call to method parallel
178183
- linters:
179184
- forbidigo
180185
# This is a legacy usage of os.Getwd we're not bothering to port yet.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Add RISC-V (64-bit) binaries for Linux to releases.
88
- Fix type filtering on `buf generate` for empty files, files with no declared types.
99
- Fix CEL check on `buf lint` for predefined `rules` variables.
10+
- Fix `buf config migrate` to filter out removed rules.
1011

1112
## [v1.53.0] - 2025-04-21
1213

private/buf/bufmigrate/migrator.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
"buf.build/go/bufplugin/check"
2929
"github.com/bufbuild/buf/private/bufpkg/bufcheck"
30+
"github.com/bufbuild/buf/private/bufpkg/bufcheck/bufcheckserver"
3031
"github.com/bufbuild/buf/private/bufpkg/bufconfig"
3132
"github.com/bufbuild/buf/private/bufpkg/bufmodule"
3233
"github.com/bufbuild/buf/private/bufpkg/bufparse"
@@ -761,10 +762,35 @@ func equivalentCheckConfigInV2(
761762
return !ok
762763
},
763764
)
764-
return bufconfig.NewEnabledCheckConfig(
765-
bufconfig.FileVersionV2,
765+
// Filter remaining rules to match the V2 rule set. Any other rules are ignored.
766+
// Theres no additional rules from plugins as plugins didn't exist before v2.
767+
validV2IDsMap := make(map[string]struct{})
768+
for _, ruleSpec := range bufcheckserver.V2Spec.Rules {
769+
if ruleSpec.Type == ruleType {
770+
validV2IDsMap[ruleSpec.ID] = struct{}{}
771+
}
772+
}
773+
for _, categorySpec := range bufcheckserver.V2Spec.Categories {
774+
validV2IDsMap[categorySpec.ID] = struct{}{}
775+
}
776+
useIDsAndCategories := slicesext.Filter(
766777
append(simplyTranslatedCheckConfig.UseIDsAndCategories(), missingIDs...),
778+
func(ruleID string) bool {
779+
_, ok := validV2IDsMap[ruleID]
780+
return ok
781+
},
782+
)
783+
exceptIDsAndCategories := slicesext.Filter(
767784
append(simplyTranslatedCheckConfig.ExceptIDsAndCategories(), extraIDs...),
785+
func(ruleID string) bool {
786+
_, ok := validV2IDsMap[ruleID]
787+
return ok
788+
},
789+
)
790+
return bufconfig.NewEnabledCheckConfig(
791+
bufconfig.FileVersionV2,
792+
useIDsAndCategories,
793+
exceptIDsAndCategories,
768794
simplyTranslatedCheckConfig.IgnorePaths(),
769795
simplyTranslatedCheckConfig.IgnoreIDOrCategoryToPaths(),
770796
simplyTranslatedCheckConfig.DisableBuiltin(),
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2020-2025 Buf Technologies, Inc.
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+
package configmigrate
16+
17+
import (
18+
"bytes"
19+
"context"
20+
"path/filepath"
21+
"testing"
22+
23+
"github.com/bufbuild/buf/private/buf/cmd/buf/internal/internaltesting"
24+
"github.com/bufbuild/buf/private/pkg/app/appcmd"
25+
"github.com/bufbuild/buf/private/pkg/app/appcmd/appcmdtesting"
26+
"github.com/bufbuild/buf/private/pkg/app/appext"
27+
"github.com/bufbuild/buf/private/pkg/osext"
28+
"github.com/bufbuild/buf/private/pkg/storage"
29+
"github.com/bufbuild/buf/private/pkg/storage/storageos"
30+
"github.com/stretchr/testify/assert"
31+
"github.com/stretchr/testify/require"
32+
)
33+
34+
func TestConfigMigrateV1DefaultConfig(t *testing.T) {
35+
// Cannot be parallel since we chdir.
36+
testCompareConfigMigrate(t, "testdata/defaultv1", 0, "")
37+
}
38+
39+
func TestConfigMigrateV1BetaV1DefaultConfig(t *testing.T) {
40+
// Cannot be parallel since we chdir.
41+
testCompareConfigMigrate(t, "testdata/defaultv1beta1", 0, "")
42+
}
43+
44+
func TestConfigMigrateUnknownVersion(t *testing.T) {
45+
// Cannot be parallel since we chdir.
46+
testCompareConfigMigrate(t, "testdata/unknown", 1, "decode buf.yaml: \"version\" is not set. Please add \"version: v2\"")
47+
}
48+
49+
func testCompareConfigMigrate(t *testing.T, dir string, expectCode int, expectStderr string) {
50+
// Setup temporary bucket with input, then compare it to the output.
51+
storageosProvider := storageos.NewProvider()
52+
inputBucket, err := storageosProvider.NewReadWriteBucket(filepath.Join(dir, "input"))
53+
require.NoError(t, err)
54+
tempDir := t.TempDir()
55+
tempBucket, err := storageosProvider.NewReadWriteBucket(tempDir)
56+
require.NoError(t, err)
57+
ctx := context.Background()
58+
_, err = storage.Copy(ctx, inputBucket, tempBucket)
59+
require.NoError(t, err)
60+
var outputBucket storage.ReadWriteBucket
61+
if expectCode == 0 {
62+
outputBucket, err = storageosProvider.NewReadWriteBucket(filepath.Join(dir, "output"))
63+
require.NoError(t, err)
64+
}
65+
// Run in the temp directory.
66+
func() {
67+
pwd, err := osext.Getwd()
68+
require.NoError(t, err)
69+
require.NoError(t, osext.Chdir(tempDir))
70+
defer func() {
71+
r := recover()
72+
assert.NoError(t, osext.Chdir(pwd))
73+
if r != nil {
74+
panic(r)
75+
}
76+
}()
77+
appcmdtesting.Run(
78+
t,
79+
func(use string) *appcmd.Command {
80+
return NewCommand(use, appext.NewBuilder(use))
81+
},
82+
appcmdtesting.WithExpectedExitCode(expectCode),
83+
appcmdtesting.WithExpectedStderr(expectStderr),
84+
appcmdtesting.WithEnv(internaltesting.NewEnvFunc(t)),
85+
)
86+
}()
87+
if expectCode != 0 {
88+
return // Nothing to compare.
89+
}
90+
var diff bytes.Buffer
91+
require.NoError(t, storage.Diff(ctx, &diff, outputBucket, tempBucket))
92+
assert.Empty(t, diff.String())
93+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
version: v1
2+
name: ""
3+
deps: []
4+
build:
5+
excludes: []
6+
lint:
7+
use:
8+
- STANDARD
9+
except: []
10+
ignore: []
11+
ignore_only: {}
12+
allow_comment_ignores: false
13+
enum_zero_value_suffix: _UNSPECIFIED
14+
rpc_allow_same_request_response: false
15+
rpc_allow_google_protobuf_empty_requests: false
16+
rpc_allow_google_protobuf_empty_responses: false
17+
service_suffix: Service
18+
breaking:
19+
use:
20+
- FILE
21+
except: []
22+
ignore: []
23+
ignore_only: {}
24+
ignore_unstable_packages: false
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: v2
2+
lint:
3+
use:
4+
- STANDARD
5+
except:
6+
- FIELD_NOT_REQUIRED
7+
- PACKAGE_NO_IMPORT_CYCLE
8+
enum_zero_value_suffix: _UNSPECIFIED
9+
service_suffix: Service
10+
disallow_comment_ignores: true
11+
breaking:
12+
use:
13+
- FILE
14+
except:
15+
- EXTENSION_NO_DELETE
16+
- FIELD_SAME_DEFAULT
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: v1beta1
2+
name: ""
3+
deps: []
4+
build:
5+
roots:
6+
- .
7+
excludes: []
8+
lint:
9+
use:
10+
- STANDARD
11+
enum_zero_value_suffix: _UNSPECIFIED
12+
rpc_allow_same_request_response: false
13+
rpc_allow_google_protobuf_empty_requests: false
14+
rpc_allow_google_protobuf_empty_responses: false
15+
service_suffix: Service
16+
breaking:
17+
use:
18+
- FILE
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
version: v2
2+
lint:
3+
use:
4+
- STANDARD
5+
except:
6+
- ENUM_FIRST_VALUE_ZERO
7+
- FIELD_NOT_REQUIRED
8+
- IMPORT_USED
9+
- PACKAGE_NO_IMPORT_CYCLE
10+
- PROTOVALIDATE
11+
- SYNTAX_SPECIFIED
12+
enum_zero_value_suffix: _UNSPECIFIED
13+
service_suffix: Service
14+
disallow_comment_ignores: true
15+
breaking:
16+
use:
17+
- FILE
18+
except:
19+
- EXTENSION_NO_DELETE
20+
- FIELD_SAME_DEFAULT
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
name: "empty"

0 commit comments

Comments
 (0)