@@ -32,10 +32,110 @@ def main() -> None:
32
32
"""Run the migration steps."""
33
33
# Add a separation line like this one after each migration step.
34
34
print ("=" * 72 )
35
+ regroup_dependabot ()
36
+ print ("=" * 72 )
35
37
print ("Migration script finished. Remember to follow any manual instructions." )
36
38
print ("=" * 72 )
37
39
38
40
41
+ def regroup_dependabot () -> None :
42
+ """Use new dependabot groups to separate dependencies that break often."""
43
+ print ("Using new dependabot groups to separate dependencies that break often..." )
44
+ # Dependabot configuration file
45
+ dependabot_file = Path (".github/dependabot.yml" )
46
+
47
+ # Skip if the file doesn't exist
48
+ if not dependabot_file .exists ():
49
+ manual_step (
50
+ "Dependabot configuration file not found, not excluding "
51
+ "frequenz-repo-config from group updates. Please consider adding a "
52
+ "dependabot configuration file."
53
+ )
54
+ return
55
+
56
+ dependabot_content = dependabot_file .read_text (encoding = "utf-8" )
57
+
58
+ new_groups = """\
59
+ # We group patch updates as they should always work.
60
+ # We also group minor updates, as it works too for most libraries,
61
+ # typically except libraries that don't have a stable release yet (v0.x.x
62
+ # branch), so we make some exceptions for them.
63
+ # Major updates and dependencies excluded by the above groups are still
64
+ # managed, but they'll create one PR per dependency, as breakage is
65
+ # expected, so it might need manual intervention.
66
+ # Finally, we group some dependencies that are related to each other, and
67
+ # usually need to be updated together.
68
+ groups:
69
+ patch:
70
+ update-types:
71
+ - "patch"
72
+ exclude-patterns:
73
+ # pydoclint has shipped breaking changes in patch updates often
74
+ - "pydoclint"
75
+ minor:
76
+ update-types:
77
+ - "minor"
78
+ exclude-patterns:
79
+ - "async-solipsism"
80
+ - "frequenz-repo-config*"
81
+ - "markdown-callouts"
82
+ - "mkdocs-gen-files"
83
+ - "mkdocs-literate-nav"
84
+ - "mkdocstrings*"
85
+ - "pydoclint"
86
+ - "pytest-asyncio"
87
+ # We group repo-config updates as it uses optional dependencies that are
88
+ # considered different dependencies otherwise, and will create one PR for
89
+ # each if we don't group them.
90
+ repo-config:
91
+ patterns:
92
+ - "frequenz-repo-config*"
93
+ mkdocstrings:
94
+ patterns:
95
+ - "mkdocstrings*"
96
+ """
97
+
98
+ marker = " open-pull-requests-limit: 10"
99
+ if marker not in dependabot_content :
100
+ manual_step (
101
+ f"Could not file marker ({ marker !r} ) in { dependabot_file } , "
102
+ "can't update automatically. Please consider using these new groups "
103
+ "in the dependabot configuration file:"
104
+ )
105
+ print (new_groups )
106
+ return
107
+
108
+ text_to_replace = ""
109
+ found_marker = False
110
+ for line in dependabot_content .splitlines ():
111
+ if line == marker :
112
+ found_marker = True
113
+ continue
114
+ if not found_marker :
115
+ continue
116
+ if line == "" and found_marker :
117
+ break
118
+ text_to_replace += line + "\n "
119
+ print (text_to_replace )
120
+
121
+ if not text_to_replace :
122
+ manual_step (
123
+ "Could not find the text to replace with the new depenndabot "
124
+ "groups. Please consider using these new groups in the dependabot "
125
+ "configuration file:"
126
+ )
127
+ print (new_groups )
128
+ return
129
+
130
+ replace_file_contents_atomically (
131
+ dependabot_file ,
132
+ text_to_replace ,
133
+ new_groups ,
134
+ count = 1 ,
135
+ content = dependabot_content ,
136
+ )
137
+
138
+
39
139
def apply_patch (patch_content : str ) -> None :
40
140
"""Apply a patch using the patch utility."""
41
141
subprocess .run (["patch" , "-p1" ], input = patch_content .encode (), check = True )
0 commit comments