Skip to content

Commit 732a2de

Browse files
committed
Turn deploy into a context-managed function
This lets us perform the initial error-checking for deploying before building the MkDocs site, so we waste less time if something was misconfigured.
1 parent 1b272a0 commit 732a2de

File tree

4 files changed

+107
-36
lines changed

4 files changed

+107
-36
lines changed

mike/commands.py

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import http.server
22
import os
33
import posixpath
4+
from contextlib import contextmanager
45
from jinja2 import Template
56
from pkg_resources import resource_stream
67

@@ -49,6 +50,7 @@ def make_nojekyll():
4950
return git_utils.FileInfo('.nojekyll', '')
5051

5152

53+
@contextmanager
5254
def deploy(cfg, version, title=None, aliases=[], update_aliases=False,
5355
redirect=True, template=None, *, branch='gh-pages', message=None,
5456
prefix=''):
@@ -70,6 +72,9 @@ def deploy(cfg, version, title=None, aliases=[], update_aliases=False,
7072
destdir = os.path.join(prefix, version_str)
7173
alias_destdirs = [os.path.join(prefix, i) for i in info.aliases]
7274

75+
# Let the caller perform the build.
76+
yield
77+
7378
if redirect and info.aliases:
7479
t = _redirect_template(template)
7580

mike/driver.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,12 @@ def check_remote_status(args, strict=False):
119119
def deploy(args):
120120
cfg = load_mkdocs_config(args, strict=True)
121121
check_remote_status(args, strict=True)
122-
with mkdocs_utils.inject_plugin(args.config_file) as config_file:
123-
mkdocs_utils.build(config_file, args.version)
124-
commands.deploy(cfg, args.version, args.title, args.alias,
125-
args.update_aliases, args.redirect, args.template,
126-
branch=args.branch, message=args.message,
127-
prefix=args.prefix)
122+
with commands.deploy(cfg, args.version, args.title, args.alias,
123+
args.update_aliases, args.redirect, args.template,
124+
branch=args.branch, message=args.message,
125+
prefix=args.prefix):
126+
with mkdocs_utils.inject_plugin(args.config_file) as config_file:
127+
mkdocs_utils.build(config_file, args.version)
128128
if args.push:
129129
git_utils.push_branch(args.remote, args.branch, args.force)
130130

test/__init__.py

+27-6
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,33 @@ def pushd(dirname):
3636
os.chdir(old)
3737

3838

39-
def copytree(src, dst):
40-
for i in os.listdir(src):
41-
curr_src = os.path.join(src, i)
42-
curr_dst = os.path.join(dst, i)
43-
if os.path.isdir(curr_src):
44-
shutil.copytree(curr_src, curr_dst)
39+
def copytree(src, dst, ignore_hidden=True):
40+
def accumulate(path):
41+
for i in os.listdir(os.path.join(src, path)):
42+
if ignore_hidden and i[0] == '.':
43+
continue
44+
45+
curr_path = os.path.join(path, i)
46+
if os.path.isdir(os.path.join(src, curr_path)):
47+
yield (curr_path, True)
48+
yield from accumulate(curr_path)
49+
else:
50+
yield (curr_path, False)
51+
52+
# Make a list of files to copy *before* starting to copy, so that we can
53+
# put our copy inside the src directory.
54+
to_copy = list(accumulate(''))
55+
seen_dirs = set()
56+
57+
os.makedirs(dst, exist_ok=True)
58+
for path, isdir in to_copy:
59+
curr_src = os.path.join(src, path)
60+
curr_dst = os.path.join(dst, path)
61+
62+
if isdir:
63+
if path not in seen_dirs:
64+
seen_dirs.add(path)
65+
os.makedirs(curr_dst, exist_ok=True)
4566
else:
4667
shutil.copy2(curr_src, curr_dst)
4768

test/unit/test_commands.py

+69-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import re
3+
import shutil
34
import unittest
45
from collections.abc import Collection
56
from unittest import mock
@@ -76,6 +77,13 @@ def _test_state(self, expected_message, expected_versions, redirect=True,
7677
class TestDeploy(TestBase):
7778
stage_dir = 'deploy'
7879

80+
def setUp(self):
81+
super().setUp()
82+
self.cfg.site_dir = os.path.join(self.cfg.site_dir, 'site')
83+
84+
def _mock_build(self):
85+
copytree(self.stage, self.cfg.site_dir)
86+
7987
def _test_deploy(self, expected_message=None,
8088
expected_versions=[versions.VersionInfo('1.0')],
8189
**kwargs):
@@ -86,6 +94,8 @@ def _test_deploy(self, expected_message=None,
8694
.format(rev, expected_versions[0].version)
8795
)
8896

97+
if os.path.exists(self.cfg.site_dir):
98+
shutil.rmtree(self.cfg.site_dir)
8999
self._test_state(expected_message, expected_versions, **kwargs)
90100

91101
def _mock_commit(self):
@@ -101,19 +111,22 @@ def _mock_commit(self):
101111
commit.add_file(git_utils.FileInfo('latest/dir/index.html', ''))
102112

103113
def test_default(self):
104-
commands.deploy(self.cfg, '1.0')
114+
with commands.deploy(self.cfg, '1.0'):
115+
self._mock_build()
105116
check_call_silent(['git', 'checkout', 'gh-pages'])
106117
self._test_deploy()
107118

108119
def test_title(self):
109-
commands.deploy(self.cfg, '1.0', '1.0.0')
120+
with commands.deploy(self.cfg, '1.0', '1.0.0'):
121+
self._mock_build()
110122
check_call_silent(['git', 'checkout', 'gh-pages'])
111123
self._test_deploy(expected_versions=[
112124
versions.VersionInfo('1.0', '1.0.0')
113125
])
114126

115127
def test_aliases(self):
116-
commands.deploy(self.cfg, '1.0', aliases=['latest'])
128+
with commands.deploy(self.cfg, '1.0', aliases=['latest']):
129+
self._mock_build()
117130
check_call_silent(['git', 'checkout', 'gh-pages'])
118131
self._test_deploy(expected_versions=[
119132
versions.VersionInfo('1.0', aliases=['latest'])
@@ -126,7 +139,8 @@ def test_aliases(self):
126139

127140
def test_aliases_no_directory_urls(self):
128141
self.cfg.use_directory_urls = False
129-
commands.deploy(self.cfg, '1.0', aliases=['latest'])
142+
with commands.deploy(self.cfg, '1.0', aliases=['latest']):
143+
self._mock_build()
130144
check_call_silent(['git', 'checkout', 'gh-pages'])
131145
self._test_deploy(expected_versions=[
132146
versions.VersionInfo('1.0', aliases=['latest'])
@@ -138,17 +152,24 @@ def test_aliases_no_directory_urls(self):
138152
self.assertRegex(f.read(), match_redir('../../1.0/dir/index.html'))
139153

140154
def test_aliases_copy(self):
141-
commands.deploy(self.cfg, '1.0', aliases=['latest'], redirect=False)
155+
with commands.deploy(self.cfg, '1.0', aliases=['latest'],
156+
redirect=False):
157+
self._mock_build()
142158
check_call_silent(['git', 'checkout', 'gh-pages'])
143159
self._test_deploy(expected_versions=[
144160
versions.VersionInfo('1.0', aliases=['latest'])
145161
], redirect=False)
146162

147163
def test_aliases_custom_redirect(self):
164+
real_open = open
148165
with mock.patch('builtins.open',
149166
mock.mock_open(read_data=b'{{href}}')):
150-
commands.deploy(self.cfg, '1.0', aliases=['latest'],
151-
template='template.html')
167+
with commands.deploy(self.cfg, '1.0', aliases=['latest'],
168+
template='template.html'):
169+
# Un-mock `open` so we can copy files for real.
170+
with mock.patch('builtins.open', real_open):
171+
self._mock_build()
172+
152173
check_call_silent(['git', 'checkout', 'gh-pages'])
153174
self._test_deploy(expected_versions=[
154175
versions.VersionInfo('1.0', aliases=['latest'])
@@ -160,17 +181,21 @@ def test_aliases_custom_redirect(self):
160181
self.assertEqual(f.read(), '../../1.0/dir/')
161182

162183
def test_branch(self):
163-
commands.deploy(self.cfg, '1.0', branch='branch')
184+
with commands.deploy(self.cfg, '1.0', branch='branch'):
185+
self._mock_build()
164186
check_call_silent(['git', 'checkout', 'branch'])
165187
self._test_deploy()
166188

167189
def test_commit_message(self):
168-
commands.deploy(self.cfg, '1.0', message='commit message')
190+
with commands.deploy(self.cfg, '1.0', message='commit message'):
191+
self._mock_build()
169192
check_call_silent(['git', 'checkout', 'gh-pages'])
170193
self._test_deploy('^commit message$')
171194

172195
def test_prefix(self):
173-
commands.deploy(self.cfg, '1.0', aliases=['latest'], prefix='prefix')
196+
with commands.deploy(self.cfg, '1.0', aliases=['latest'],
197+
prefix='prefix'):
198+
self._mock_build()
174199
check_call_silent(['git', 'checkout', 'gh-pages'])
175200
self._test_deploy(expected_versions=[
176201
versions.VersionInfo('1.0', aliases=['latest'])
@@ -185,23 +210,26 @@ def test_overwrite_version(self):
185210
commit.add_file(git_utils.FileInfo('1.0/old-page.html', ''))
186211
commit.add_file(git_utils.FileInfo('latest/old-page.html', ''))
187212

188-
commands.deploy(self.cfg, '1.0', '1.0.1', ['greatest'])
213+
with commands.deploy(self.cfg, '1.0', '1.0.1', ['greatest']):
214+
self._mock_build()
189215
check_call_silent(['git', 'checkout', 'gh-pages'])
190216
self._test_deploy(expected_versions=[
191217
versions.VersionInfo('1.0', '1.0.1', ['latest', 'greatest'])
192218
])
193219

194220
def test_overwrite_same_alias(self):
195221
self._mock_commit()
196-
commands.deploy(self.cfg, '1.0', '1.0.1', ['latest'])
222+
with commands.deploy(self.cfg, '1.0', '1.0.1', ['latest']):
223+
self._mock_build()
197224
check_call_silent(['git', 'checkout', 'gh-pages'])
198225
self._test_deploy(expected_versions=[
199226
versions.VersionInfo('1.0', '1.0.1', ['latest'])
200227
])
201228

202229
def test_overwrite_include_same_alias(self):
203230
self._mock_commit()
204-
commands.deploy(self.cfg, '1.0', '1.0.1', ['latest', 'greatest'])
231+
with commands.deploy(self.cfg, '1.0', '1.0.1', ['latest', 'greatest']):
232+
self._mock_build()
205233
check_call_silent(['git', 'checkout', 'gh-pages'])
206234
self._test_deploy(expected_versions=[
207235
versions.VersionInfo('1.0', '1.0.1', ['latest', 'greatest'])
@@ -210,15 +238,18 @@ def test_overwrite_include_same_alias(self):
210238
def test_overwrite_alias_error(self):
211239
self._mock_commit()
212240
with self.assertRaises(ValueError):
213-
commands.deploy(self.cfg, '2.0', '2.0.0', ['latest'])
241+
with commands.deploy(self.cfg, '2.0', '2.0.0', ['latest']):
242+
raise AssertionError('should not get here')
214243
check_call_silent(['git', 'checkout', 'gh-pages'])
215244
self._test_deploy('add versions.json', [
216245
versions.VersionInfo('1.0', '1.0', ['latest'])
217246
])
218247

219248
def test_update_aliases(self):
220249
self._mock_commit()
221-
commands.deploy(self.cfg, '2.0', '2.0.0', ['latest'], True)
250+
with commands.deploy(self.cfg, '2.0', '2.0.0', ['latest'],
251+
update_aliases=True):
252+
self._mock_build()
222253
check_call_silent(['git', 'checkout', 'gh-pages'])
223254
self._test_deploy('.*', [
224255
versions.VersionInfo('2.0', '2.0.0', ['latest']),
@@ -230,9 +261,11 @@ class TestDelete(TestBase):
230261
stage_dir = 'delete'
231262

232263
def _deploy(self, branch='gh-pages', prefix=''):
233-
commands.deploy(self.cfg, '1.0', aliases=['stable'], branch=branch,
234-
prefix=prefix)
235-
commands.deploy(self.cfg, '2.0', branch=branch, prefix=prefix)
264+
with commands.deploy(self.cfg, '1.0', aliases=['stable'],
265+
branch=branch, prefix=prefix):
266+
pass
267+
with commands.deploy(self.cfg, '2.0', branch=branch, prefix=prefix):
268+
pass
236269

237270
def _test_delete(self, expected_message=None,
238271
expected_versions=[versions.VersionInfo('2.0')],
@@ -306,8 +339,9 @@ class TestAlias(TestBase):
306339
stage_dir = 'alias'
307340

308341
def _deploy(self, branch='gh-pages', prefix=''):
309-
commands.deploy(self.cfg, '1.0', aliases=['latest'], branch=branch,
310-
prefix=prefix)
342+
with commands.deploy(self.cfg, '1.0', aliases=['latest'],
343+
branch=branch, prefix=prefix):
344+
pass
311345

312346
def _test_alias(self, expected_message=None, expected_src='1.0',
313347
expected_aliases=['greatest'], **kwargs):
@@ -385,7 +419,8 @@ def test_alias_overwrite_include_same(self):
385419

386420
def test_alias_overwrite_error(self):
387421
self._deploy()
388-
commands.deploy(self.cfg, '2.0')
422+
with commands.deploy(self.cfg, '2.0'):
423+
pass
389424
with self.assertRaises(ValueError):
390425
commands.alias(self.cfg, '2.0', ['latest'])
391426
check_call_silent(['git', 'checkout', 'gh-pages'])
@@ -395,7 +430,15 @@ def test_alias_overwrite_error(self):
395430
])
396431

397432
def test_alias_update(self):
398-
pass
433+
self._deploy()
434+
with commands.deploy(self.cfg, '2.0'):
435+
pass
436+
commands.alias(self.cfg, '2.0', ['latest'], update_aliases=True)
437+
check_call_silent(['git', 'checkout', 'gh-pages'])
438+
self._test_state(r'^Copied 2\.0 to latest', [
439+
versions.VersionInfo('2.0', '2.0', ['latest']),
440+
versions.VersionInfo('1.0', '1.0'),
441+
])
399442

400443
def test_branch(self):
401444
self._deploy('branch')
@@ -431,7 +474,8 @@ def setUp(self):
431474
commit_files(['file.txt'])
432475

433476
def _deploy(self, branch='gh-pages', prefix=''):
434-
commands.deploy(self.cfg, '1.0', branch=branch, prefix=prefix)
477+
with commands.deploy(self.cfg, '1.0', branch=branch, prefix=prefix):
478+
pass
435479

436480
def _test_retitle(self, expected_message=None, directory='.'):
437481
message = check_output(['git', 'log', '-1', '--pretty=%B']).rstrip()
@@ -492,7 +536,8 @@ def setUp(self):
492536
commit_files(['file.txt'])
493537

494538
def _deploy(self, branch='gh-pages', prefix=''):
495-
commands.deploy(self.cfg, '1.0', branch=branch, prefix=prefix)
539+
with commands.deploy(self.cfg, '1.0', branch=branch, prefix=prefix):
540+
pass
496541

497542
def _test_default(self, expr=r'window\.location\.replace\("1\.0/"\)',
498543
expected_message=None, directory='.'):

0 commit comments

Comments
 (0)