Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | 7796 |
Merged at revision: | 7692 |
Proposed branch: | lp:brz/3.3 |
Merge into: | lp:brz |
Diff against target: |
504 lines (+67/-154) 12 files modified
breezy/git/branch.py (+1/-2) breezy/git/interrepo.py (+10/-6) breezy/git/refs.py (+6/-40) breezy/plugin.py (+4/-26) breezy/plugins/bash_completion/tests/test_bashcomp.py (+6/-3) breezy/plugins/launchpad/lp_directory.py (+11/-4) breezy/tests/__init__.py (+8/-3) breezy/tests/features.py (+0/-1) breezy/tests/test_plugins.py (+1/-60) breezy/tests/test_selftest.py (+14/-3) breezy/tests/test_transport.py (+3/-3) pyproject.toml (+3/-3) |
To merge this branch: | bzr merge lp:brz/3.3 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+440187@code.launchpad.net |
Commit message
Merge lp:brz/3.3
Description of the change
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/git/branch.py' |
2 | --- breezy/git/branch.py 2023-03-09 13:47:07 +0000 |
3 | +++ breezy/git/branch.py 2023-03-31 22:11:54 +0000 |
4 | @@ -40,8 +40,7 @@ |
5 | from .mapping import decode_git_path, encode_git_path |
6 | from .push import remote_divergence |
7 | from .refs import (branch_name_to_ref, is_tag, ref_to_branch_name, |
8 | - ref_to_tag_name, remote_refs_dict_to_tag_refs, |
9 | - tag_name_to_ref) |
10 | + ref_to_tag_name, tag_name_to_ref) |
11 | from .unpeel_map import UnpeelMap |
12 | from .urls import bzr_url_to_git_url, git_url_to_bzr_url |
13 | |
14 | |
15 | === modified file 'breezy/git/interrepo.py' |
16 | --- breezy/git/interrepo.py 2023-03-09 13:47:07 +0000 |
17 | +++ breezy/git/interrepo.py 2023-03-31 22:11:54 +0000 |
18 | @@ -24,7 +24,11 @@ |
19 | from dulwich.object_store import ObjectStoreGraphWalker |
20 | from dulwich.pack import PACK_SPOOL_FILE_MAX_SIZE |
21 | from dulwich.protocol import CAPABILITY_THIN_PACK, ZERO_SHA |
22 | -from dulwich.refs import ANNOTATED_TAG_SUFFIX, SYMREF |
23 | +from dulwich.refs import SYMREF |
24 | +try: |
25 | + from dulwich.refs import PEELED_TAG_SUFFIX |
26 | +except ImportError: # dulwich < 0.21.3 |
27 | + from dulwich.refs import ANNOTATED_TAG_SUFFIX as PEELED_TAG_SUFFIX |
28 | from dulwich.walk import Walker |
29 | |
30 | from .. import config, trace, ui |
31 | @@ -378,12 +382,12 @@ |
32 | def determine_wants(refs): |
33 | unpeel_lookup = {} |
34 | for k, v in refs.items(): |
35 | - if k.endswith(ANNOTATED_TAG_SUFFIX): |
36 | - unpeel_lookup[v] = refs[k[:-len(ANNOTATED_TAG_SUFFIX)]] |
37 | + if k.endswith(PEELED_TAG_SUFFIX): |
38 | + unpeel_lookup[v] = refs[k[:-len(PEELED_TAG_SUFFIX)]] |
39 | potential = {unpeel_lookup.get(w, w) for w in wants} |
40 | if include_tags: |
41 | for k, sha in refs.items(): |
42 | - if k.endswith(ANNOTATED_TAG_SUFFIX): |
43 | + if k.endswith(PEELED_TAG_SUFFIX): |
44 | continue |
45 | try: |
46 | tag_name = ref_to_tag_name(k) |
47 | @@ -686,7 +690,7 @@ |
48 | if value == ZERO_SHA: |
49 | continue |
50 | |
51 | - if name.endswith(ANNOTATED_TAG_SUFFIX): |
52 | + if name.endswith(PEELED_TAG_SUFFIX): |
53 | continue |
54 | |
55 | if name in branches or (include_tags and is_tag(name)): |
56 | @@ -697,7 +701,7 @@ |
57 | def determine_wants_all(self, refs): |
58 | potential = { |
59 | v for k, v in refs.items() |
60 | - if not v == ZERO_SHA and not k.endswith(ANNOTATED_TAG_SUFFIX)} |
61 | + if not v == ZERO_SHA and not k.endswith(PEELED_TAG_SUFFIX)} |
62 | return list(potential - self._target_has_shas(potential)) |
63 | |
64 | |
65 | |
66 | === modified file 'breezy/git/refs.py' |
67 | --- breezy/git/refs.py 2023-01-31 01:05:40 +0000 |
68 | +++ breezy/git/refs.py 2023-03-31 22:11:54 +0000 |
69 | @@ -17,8 +17,11 @@ |
70 | """Conversion between refs and Bazaar revision pointers.""" |
71 | |
72 | from dulwich.objects import Tag, object_class |
73 | -from dulwich.refs import (ANNOTATED_TAG_SUFFIX, LOCAL_BRANCH_PREFIX, |
74 | - LOCAL_TAG_PREFIX) |
75 | +from dulwich.refs import (LOCAL_BRANCH_PREFIX, LOCAL_TAG_PREFIX) |
76 | +try: |
77 | + from dulwich.refs import PEELED_TAG_SUFFIX |
78 | +except ImportError: |
79 | + from dulwich.refs import ANNOTATED_TAG_SUFFIX as PEELED_TAG_SUFFIX |
80 | from dulwich.repo import RefsContainer |
81 | |
82 | from .. import controldir, errors, osutils |
83 | @@ -29,27 +32,8 @@ |
84 | return x.startswith(LOCAL_TAG_PREFIX) |
85 | |
86 | |
87 | -def is_head(x): |
88 | - return x.startswith(LOCAL_BRANCH_PREFIX) |
89 | - |
90 | - |
91 | def is_peeled(x): |
92 | - return x.endswith(ANNOTATED_TAG_SUFFIX) |
93 | - |
94 | - |
95 | -def gather_peeled(refs): |
96 | - ret = {} |
97 | - for k, v in refs.items(): |
98 | - if is_peeled(k): |
99 | - continue |
100 | - try: |
101 | - peeled = refs[k + ANNOTATED_TAG_SUFFIX] |
102 | - unpeeled = v |
103 | - except KeyError: |
104 | - peeled = v |
105 | - unpeeled = None |
106 | - ret[k] = (peeled, unpeeled) |
107 | - return ret |
108 | + return x.endswith(PEELED_TAG_SUFFIX) |
109 | |
110 | |
111 | def branch_name_to_ref(name): |
112 | @@ -192,21 +176,3 @@ |
113 | if fn is not None: |
114 | return fn() |
115 | return BazaarRefsContainer(controldir, object_store) |
116 | - |
117 | - |
118 | -def remote_refs_dict_to_tag_refs(refs_dict): |
119 | - base = {} |
120 | - peeled = {} |
121 | - for k, v in refs_dict.items(): |
122 | - if is_peeled(k): |
123 | - peeled[k[:-3]] = v |
124 | - else: |
125 | - base[k] = v |
126 | - peeled[k] = v |
127 | - all_keys = set().union(base.keys(), peeled.keys()) |
128 | - for n in all_keys: |
129 | - try: |
130 | - tag_name = ref_to_tag_name(n) |
131 | - except ValueError: |
132 | - continue |
133 | - yield (n, tag_name, peeled.get(n), base.get(n)) |
134 | |
135 | === modified file 'breezy/plugin.py' |
136 | --- breezy/plugin.py 2023-01-31 01:05:40 +0000 |
137 | +++ breezy/plugin.py 2023-03-31 22:11:54 +0000 |
138 | @@ -87,9 +87,7 @@ |
139 | from breezy.plugins import __path__ as path |
140 | |
141 | state.plugin_warnings = {} |
142 | - _load_plugins_from_path(state, path) |
143 | - if (None, 'entrypoints') in _env_plugin_path(): |
144 | - _load_plugins_from_entrypoints(state) |
145 | + _load_plugins(state, path) |
146 | state.plugins = plugins() |
147 | if warn_load_problems: |
148 | for plugin, errors in state.plugin_warnings.items(): |
149 | @@ -97,25 +95,6 @@ |
150 | trace.warning('%s', error) |
151 | |
152 | |
153 | -def _load_plugins_from_entrypoints(state): |
154 | - try: |
155 | - from importlib.metadata import entry_points |
156 | - except ModuleNotFoundError: |
157 | - # No importlib.metadata, no entrypoints. |
158 | - pass |
159 | - else: |
160 | - try: |
161 | - eps = entry_points(group='breezy.plugin') |
162 | - except TypeError: # python < 3.10 didn't support group argument |
163 | - eps = [ep[0] for ep in entry_points().values() |
164 | - if ep[0].group == 'breezy.plugin'] |
165 | - for ep in eps: |
166 | - fullname = _MODULE_PREFIX + ep.name |
167 | - if fullname in sys.modules: |
168 | - continue |
169 | - sys.modules[fullname] = ep.load() |
170 | - |
171 | - |
172 | def plugin_name(module_name): |
173 | """Gives unprefixed name from module_name or None.""" |
174 | if module_name.startswith(_MODULE_PREFIX): |
175 | @@ -216,7 +195,7 @@ |
176 | """Gives list of paths and contexts for plugins from environ key. |
177 | |
178 | Each entry is either a specific path to load plugins from and the value |
179 | - 'path', or None and one of the values 'user', 'core', 'entrypoints', 'site'. |
180 | + 'path', or None and one of the three values 'user', 'core', 'site'. |
181 | """ |
182 | path_details = [] |
183 | env = os.environ.get(key) |
184 | @@ -224,7 +203,6 @@ |
185 | "user": not env, |
186 | "core": True, |
187 | "site": True, |
188 | - 'entrypoints': False, |
189 | } |
190 | if env: |
191 | # Add paths specified by user in order |
192 | @@ -238,7 +216,7 @@ |
193 | path_details.append((p, 'path')) |
194 | |
195 | # Add any remaining default paths |
196 | - for name in ('user', 'core', 'entrypoints', 'site'): |
197 | + for name in ('user', 'core', 'site'): |
198 | if defaults[name]: |
199 | path_details.append((None, name)) |
200 | |
201 | @@ -272,7 +250,7 @@ |
202 | sys.meta_path.insert(2, finder) |
203 | |
204 | |
205 | -def _load_plugins_from_path(state, paths): |
206 | +def _load_plugins(state, paths): |
207 | """Do the importing all plugins from paths.""" |
208 | imported_names = set() |
209 | for name, path in _iter_possible_plugins(paths): |
210 | |
211 | === modified file 'breezy/plugins/bash_completion/tests/test_bashcomp.py' |
212 | --- breezy/plugins/bash_completion/tests/test_bashcomp.py 2023-01-31 01:05:40 +0000 |
213 | +++ breezy/plugins/bash_completion/tests/test_bashcomp.py 2023-03-31 22:11:54 +0000 |
214 | @@ -59,9 +59,12 @@ |
215 | input += b"IFS=$'\\n'\n" |
216 | input += b'echo "${COMPREPLY[*]}"\n' |
217 | (out, err) = proc.communicate(input) |
218 | - if b'' != err: |
219 | + errlines = [ |
220 | + line for line in err.splitlines() |
221 | + if not line.startswith(b'brz: warning: ')] |
222 | + if [] != errlines: |
223 | raise AssertionError('Unexpected error message:\n%s' % err) |
224 | - self.assertEqual(b'', err, 'No messages to standard error') |
225 | + self.assertEqual(b'', b''.join(errlines), 'No messages to standard error') |
226 | #import sys |
227 | #print >>sys.stdout, '---\n%s\n---\n%s\n---\n' % (input, out) |
228 | lines = out.split(b'\n') |
229 | @@ -167,7 +170,7 @@ |
230 | |
231 | def get_script(self): |
232 | s = super().get_script() |
233 | - s = s.replace("$(brz ", "$('%s' " % self.get_brz_path()) |
234 | + s = s.replace("$(brz ", "$(%s " % ' '.join(self.get_brz_command())) |
235 | s = s.replace("2>/dev/null", "") |
236 | return s |
237 | |
238 | |
239 | === modified file 'breezy/plugins/launchpad/lp_directory.py' |
240 | --- breezy/plugins/launchpad/lp_directory.py 2023-01-31 01:05:40 +0000 |
241 | +++ breezy/plugins/launchpad/lp_directory.py 2023-03-31 22:11:54 +0000 |
242 | @@ -20,7 +20,7 @@ |
243 | |
244 | from ... import debug, errors, trace, transport |
245 | from ...i18n import gettext |
246 | -from ...urlutils import InvalidURL |
247 | +from ...urlutils import InvalidURL, split, join |
248 | from .account import get_lp_login |
249 | from .uris import DEFAULT_INSTANCE, LAUNCHPAD_DOMAINS, LPNET_SERVICE_ROOT |
250 | |
251 | @@ -63,10 +63,17 @@ |
252 | def _resolve_via_api(path, url, api_base_url=LPNET_SERVICE_ROOT): |
253 | from .lp_api import connect_launchpad |
254 | lp = connect_launchpad(api_base_url, version='devel') |
255 | - lp_branch = lp.branches.getByPath(path=path) |
256 | + subpaths = [] |
257 | + while path: |
258 | + lp_branch = lp.branches.getByPath(path=path) |
259 | + if lp_branch: |
260 | + break |
261 | + path, subpath = split(path) |
262 | + subpaths.insert(0, subpath) |
263 | if not lp_branch: |
264 | - raise InvalidURL("Unknown Launchpad path: %s" % path) |
265 | - return {'urls': [lp_branch.composePublicURL(scheme='bzr+ssh'), lp_branch.composePublicURL(scheme='http')]} |
266 | + raise errors.InvalidURL("Unknown Launchpad path: %s" % url) |
267 | + return {'urls': [join(lp_branch.composePublicURL(scheme='bzr+ssh'), *subpaths), |
268 | + join(lp_branch.composePublicURL(scheme='http'), *subpaths)]} |
269 | |
270 | |
271 | class LaunchpadDirectory: |
272 | |
273 | === modified file 'breezy/tests/__init__.py' |
274 | --- breezy/tests/__init__.py 2023-01-31 01:05:40 +0000 |
275 | +++ breezy/tests/__init__.py 2023-03-31 22:11:54 +0000 |
276 | @@ -2207,8 +2207,6 @@ |
277 | for env_var, value in old_env.items(): |
278 | osutils.set_or_unset_env(env_var, value) |
279 | |
280 | - bzr_path = self.get_brz_path() |
281 | - |
282 | cwd = None |
283 | if working_dir is not None: |
284 | cwd = osutils.getcwd() |
285 | @@ -2222,7 +2220,7 @@ |
286 | # Include the subprocess's log file in the test details, in case |
287 | # the test fails due to an error in the subprocess. |
288 | self._add_subprocess_log(trace._get_brz_log_filename()) |
289 | - command = [bzr_path] |
290 | + command = self.get_brz_command() |
291 | if not allow_plugins: |
292 | command.append('--no-plugins') |
293 | command.extend(process_args) |
294 | @@ -2284,6 +2282,13 @@ |
295 | brz_path = sys.argv[0] |
296 | return brz_path |
297 | |
298 | + def get_brz_command(self): |
299 | + bzr_path = self.get_brz_path() |
300 | + if bzr_path.endswith('__main__.py'): |
301 | + return [sys.executable, '-m', 'breezy'] |
302 | + else: |
303 | + return [bzr_path] |
304 | + |
305 | def finish_brz_subprocess(self, process, retcode=0, send_signal=None, |
306 | universal_newlines=False, process_args=None): |
307 | """Finish the execution of process. |
308 | |
309 | === modified file 'breezy/tests/features.py' |
310 | --- breezy/tests/features.py 2023-01-31 01:05:40 +0000 |
311 | +++ breezy/tests/features.py 2023-03-31 22:11:54 +0000 |
312 | @@ -400,7 +400,6 @@ |
313 | flake8 = ModuleAvailableFeature('flake8.api.legacy') |
314 | |
315 | lsprof_feature = ModuleAvailableFeature('breezy.lsprof') |
316 | -importlib_metadata_feature = ModuleAvailableFeature('importlib.metadata') |
317 | |
318 | pyinotify = ModuleAvailableFeature('pyinotify') |
319 | |
320 | |
321 | === modified file 'breezy/tests/test_plugins.py' |
322 | --- breezy/tests/test_plugins.py 2023-01-31 01:05:40 +0000 |
323 | +++ breezy/tests/test_plugins.py 2023-03-31 22:11:54 +0000 |
324 | @@ -28,7 +28,6 @@ |
325 | import breezy |
326 | |
327 | from .. import osutils, plugin, tests |
328 | -from ..tests.features import importlib_metadata_feature |
329 | |
330 | # TODO: Write a test for plugin decoration of commands. |
331 | |
332 | @@ -610,7 +609,6 @@ |
333 | user = "USER" |
334 | core = "CORE" |
335 | site = "SITE" |
336 | - entrypoints = "ENTRYPOINTS" |
337 | |
338 | def check_path(self, expected_dirs, setting_dirs): |
339 | if setting_dirs is None: |
340 | @@ -636,10 +634,6 @@ |
341 | self.check_path([self.user, self.site, self.core], |
342 | ['+user', '+site', '+core']) |
343 | |
344 | - def test_enable_entrypoints(self): |
345 | - self.check_path([self.user, self.core, self.site, self.entrypoints], |
346 | - ['+user', '+core', '+site', '+entrypoints']) |
347 | - |
348 | def test_disable_user(self): |
349 | self.check_path([self.core, self.site], ['-user']) |
350 | |
351 | @@ -681,9 +675,7 @@ |
352 | ['mycore', '-core']) |
353 | |
354 | def test_my_plugin_only(self): |
355 | - self.check_path( |
356 | - ['myplugin'], |
357 | - ['myplugin', '-user', '-core', '-site', '-entrypoints']) |
358 | + self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site']) |
359 | |
360 | def test_my_plugin_first(self): |
361 | self.check_path(['myplugin', self.core, self.site, self.user], |
362 | @@ -917,54 +909,3 @@ |
363 | Hi there |
364 | |
365 | """, ''.join(plugin.describe_plugins(state=self))) |
366 | - |
367 | - |
368 | -class DummyPlugin: |
369 | - """Plugin.""" |
370 | - |
371 | - |
372 | -class TestLoadEnvPlugin(BaseTestPlugins): |
373 | - |
374 | - _test_needs_features = [importlib_metadata_feature] |
375 | - |
376 | - def setup_plugin(self, source=""): |
377 | - # This test tests a new plugin appears in breezy.plugin.plugins(). |
378 | - # check the plugin is not loaded already |
379 | - self.assertPluginUnknown('plugin') |
380 | - # write a plugin that _cannot_ fail to load. |
381 | - from importlib.metadata import Distribution, EntryPoint, entry_points |
382 | - class DummyDistribution: |
383 | - |
384 | - def __init__(self, name, entry_points): |
385 | - self._normalized_name = self.name = name |
386 | - self.entry_points = entry_points |
387 | - ep = EntryPoint(name='plugin', group='breezy.plugin', |
388 | - value=__name__ + ':DummyPlugin') |
389 | - d = DummyDistribution('lala', [ep]) |
390 | - old_discover = Distribution.discover |
391 | - def override_discover(**kwargs): |
392 | - yield from old_discover(**kwargs) |
393 | - yield d |
394 | - self.overrideAttr(Distribution, 'discover', override_discover) |
395 | - try: |
396 | - eps = entry_points(group='breezy.plugin') |
397 | - except TypeError: # python < 3.10 |
398 | - eps = [ep[0] for ep in entry_points().values() |
399 | - if ep[0].group == 'breezy.plugin'] |
400 | - self.assertEqual(['plugin'], [ep.name for ep in eps]) |
401 | - self.load_with_paths(['.']) |
402 | - |
403 | - def test_plugin_loaded(self): |
404 | - self.assertPluginUnknown('plugin') |
405 | - self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints') |
406 | - self.setup_plugin() |
407 | - p = self.plugins['plugin'] |
408 | - self.assertIsInstance(p, breezy.plugin.PlugIn) |
409 | - self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin']) |
410 | - |
411 | - def test_plugin_loaded_disabled(self): |
412 | - self.assertPluginUnknown('plugin') |
413 | - self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints') |
414 | - self.overrideEnv('BRZ_DISABLE_PLUGINS', 'plugin') |
415 | - self.setup_plugin() |
416 | - self.assertNotIn('plugin', self.plugins) |
417 | |
418 | === modified file 'breezy/tests/test_selftest.py' |
419 | --- breezy/tests/test_selftest.py 2023-01-31 01:05:40 +0000 |
420 | +++ breezy/tests/test_selftest.py 2023-03-31 22:11:54 +0000 |
421 | @@ -2618,14 +2618,25 @@ |
422 | def test_run_brz_subprocess_no_plugins(self): |
423 | self.assertRaises(_DontSpawnProcess, self.start_brz_subprocess, []) |
424 | command = self._popen_args[0] |
425 | - self.assertEqual(self.get_brz_path(), command[0]) |
426 | - self.assertEqual(['--no-plugins'], command[1:]) |
427 | + if self.get_brz_path().endswith('__main__.py'): |
428 | + self.assertEqual(sys.executable, command[0]) |
429 | + self.assertEqual('-m', command[1]) |
430 | + self.assertEqual('breezy', command[2]) |
431 | + rest = command[3:] |
432 | + else: |
433 | + self.assertEqual(self.get_brz_path(), command[0]) |
434 | + rest = command[1:] |
435 | + self.assertEqual(['--no-plugins'], rest) |
436 | |
437 | def test_allow_plugins(self): |
438 | self.assertRaises(_DontSpawnProcess, self.start_brz_subprocess, [], |
439 | allow_plugins=True) |
440 | command = self._popen_args[0] |
441 | - self.assertEqual([], command[2:]) |
442 | + if self.get_brz_path().endswith('__main__.py'): |
443 | + rest = command[3:] |
444 | + else: |
445 | + rest = command[1:] |
446 | + self.assertEqual([], rest) |
447 | |
448 | def test_set_env(self): |
449 | self.assertFalse('EXISTANT_ENV_VAR' in os.environ) |
450 | |
451 | === modified file 'breezy/tests/test_transport.py' |
452 | --- breezy/tests/test_transport.py 2023-01-31 01:05:40 +0000 |
453 | +++ breezy/tests/test_transport.py 2023-03-31 22:11:54 +0000 |
454 | @@ -1048,8 +1048,8 @@ |
455 | self.start_server(ssh_server) |
456 | port = ssh_server.port |
457 | |
458 | - bzr_remote_path = self.get_brz_path() |
459 | - self.overrideEnv('BZR_REMOTE_PATH', bzr_remote_path) |
460 | + bzr_remote_command = self.get_brz_command() |
461 | + self.overrideEnv('BZR_REMOTE_PATH', ' '.join(bzr_remote_command)) |
462 | self.overrideEnv('PYTHONPATH', ':'.join(sys.path)) |
463 | |
464 | # Access the branch via a bzr+ssh URL. The BZR_REMOTE_PATH environment |
465 | @@ -1066,7 +1066,7 @@ |
466 | |
467 | self.assertEqual( |
468 | [b'%s serve --inet --directory=/ --allow-writes' % |
469 | - bzr_remote_path.encode()], |
470 | + ' '.join(bzr_remote_command).encode()], |
471 | self.command_executed) |
472 | # Make sure to disconnect, so that the remote process can stop, and we |
473 | # can cleanup. Then pause the test until everything is shutdown |
474 | |
475 | === modified file 'pyproject.toml' |
476 | --- pyproject.toml 2023-03-09 13:21:34 +0000 |
477 | +++ pyproject.toml 2023-03-31 22:11:54 +0000 |
478 | @@ -31,7 +31,7 @@ |
479 | "fastbencode", |
480 | "patiencediff", |
481 | "merge3", |
482 | - "dulwich>=0.21.2", |
483 | + "dulwich>=0.21.3", |
484 | "urllib3>=1.24.1", |
485 | "pyyaml", |
486 | ] |
487 | @@ -43,7 +43,7 @@ |
488 | |
489 | [project.optional-dependencies] |
490 | fastimport = ["fastimport"] |
491 | -git = ["dulwich>=0.21.2"] |
492 | +git = ["dulwich>=0.21.3"] |
493 | launchpad = ["launchpadlib>=1.6.3"] |
494 | workspace = ["pyinotify"] |
495 | doc = [ |
496 | @@ -67,7 +67,7 @@ |
497 | "testtools", |
498 | "testscenarios", |
499 | "python-subunit", |
500 | - "dulwich>=0.21.2", |
501 | + "dulwich>=0.21.3", |
502 | ] |
503 | |
504 | [tool.setuptools] |
There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.