dsw-tdk 3.26.2__tar.gz → 3.27.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/CHANGELOG.md +9 -2
  2. {dsw-tdk-3.26.2/dsw_tdk.egg-info → dsw-tdk-3.27.1}/PKG-INFO +1 -1
  3. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/api_client.py +2 -2
  4. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/build_info.py +4 -4
  5. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/cli.py +60 -77
  6. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/consts.py +1 -1
  7. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/core.py +14 -8
  8. dsw-tdk-3.27.1/dsw/tdk/templates/LICENSE.j2 +1 -0
  9. dsw-tdk-3.27.1/dsw/tdk/templates/env.j2 +2 -0
  10. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/utils.py +22 -2
  11. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1/dsw_tdk.egg-info}/PKG-INFO +1 -1
  12. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw_tdk.egg-info/SOURCES.txt +3 -0
  13. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/pyproject.toml +1 -1
  14. dsw-tdk-3.27.1/tests/test_cmd_dot-env.py +70 -0
  15. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_cmd_get.py +2 -2
  16. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_cmd_list.py +2 -2
  17. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_cmd_put.py +3 -2
  18. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/LICENSE +0 -0
  19. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/MANIFEST.in +0 -0
  20. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/README.md +0 -0
  21. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/__init__.py +0 -0
  22. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/__main__.py +0 -0
  23. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/model.py +0 -0
  24. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/templates/README.md.j2 +0 -0
  25. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/templates/starter.j2 +0 -0
  26. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw/tdk/validation.py +0 -0
  27. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw_tdk.egg-info/dependency_links.txt +0 -0
  28. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw_tdk.egg-info/entry_points.txt +0 -0
  29. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw_tdk.egg-info/not-zip-safe +0 -0
  30. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw_tdk.egg-info/requires.txt +0 -0
  31. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/dsw_tdk.egg-info/top_level.txt +0 -0
  32. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/setup.cfg +0 -0
  33. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/setup.py +0 -0
  34. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_basic.py +0 -0
  35. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_cmd_new.py +0 -0
  36. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_cmd_package.py +0 -0
  37. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_cmd_unpackage.py +0 -0
  38. {dsw-tdk-3.26.2 → dsw-tdk-3.27.1}/tests/test_cmd_verify.py +0 -0
@@ -8,10 +8,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  ## [Unreleased]
9
9
 
10
10
 
11
- ## [3.26.2]
11
+ ## [3.27.1]
12
12
 
13
13
  Released for version consistency with other DSW tools.
14
14
 
15
+ ## [3.27.0]
16
+
17
+ ### Changed
18
+
19
+ - Removed legacy support for authentication using credentials
20
+
15
21
  ## [3.26.1]
16
22
 
17
23
  Released for version consistency with other DSW tools.
@@ -344,4 +350,5 @@ Initial DSW Template Development Kit (versioned as part of the [DSW platform](ht
344
350
  [3.25.0]: /../../tree/v3.25.0
345
351
  [3.26.0]: /../../tree/v3.26.0
346
352
  [3.26.1]: /../../tree/v3.26.1
347
- [3.26.2]: /../../tree/v3.26.2
353
+ [3.27.0]: /../../tree/v3.27.0
354
+ [3.27.1]: /../../tree/v3.27.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dsw-tdk
3
- Version: 3.26.2
3
+ Version: 3.27.1
4
4
  Summary: Data Stewardship Wizard Template Development Toolkit
5
5
  Author-email: Marek Suchánek <marek.suchanek@ds-wizard.org>
6
6
  License: Apache License 2.0
@@ -81,7 +81,7 @@ class DSWAPIClient:
81
81
  f'{r.reason} (expecting {expected_status})'
82
82
  )
83
83
 
84
- def __init__(self, api_url: str, session=None):
84
+ def __init__(self, api_url: str, api_key: str, session=None):
85
85
  """
86
86
  Exception representing communication error with DSW.
87
87
 
@@ -90,7 +90,7 @@ class DSWAPIClient:
90
90
  session (aiohttp.ClientSession): Optional custom session for HTTP communication.
91
91
  """
92
92
  self.api_url = api_url
93
- self.token = None
93
+ self.token = api_key
94
94
  self.session = session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False))
95
95
 
96
96
  @property
@@ -9,9 +9,9 @@ BuildInfo = namedtuple(
9
9
  )
10
10
 
11
11
  BUILD_INFO = BuildInfo(
12
- version='v3.26.2~9194676',
13
- built_at='2023-09-20 13:02:07Z',
14
- sha='919467612be55f5f7a352f1282cd31f94bb9ef84',
12
+ version='v3.27.1~4be9747',
13
+ built_at='2023-09-20 13:02:55Z',
14
+ sha='4be974749848a367bb7558c64b2f732e85ed8d75',
15
15
  branch='HEAD',
16
- tag='v3.26.2',
16
+ tag='v3.27.1',
17
17
  )
@@ -1,5 +1,4 @@
1
1
  import asyncio
2
- import sys
3
2
 
4
3
  import click # type: ignore
5
4
  import datetime
@@ -96,6 +95,10 @@ def rectify_url(ctx, param, value) -> str:
96
95
  return value.rstrip('/')
97
96
 
98
97
 
98
+ def rectify_key(ctx, param, value) -> str:
99
+ return value.strip()
100
+
101
+
99
102
  class ClickLogger(logging.Logger):
100
103
 
101
104
  NAME = 'DSW-TDK-CLI'
@@ -169,6 +172,7 @@ class CLIContext:
169
172
 
170
173
  def __init__(self):
171
174
  self.logger = ClickLogger.default()
175
+ self.dot_env_file = None
172
176
 
173
177
  def debug_mode(self):
174
178
  self.logger.show_timestamp = True
@@ -178,37 +182,6 @@ class CLIContext:
178
182
  self.logger.muted = True
179
183
 
180
184
 
181
- class APICredentials:
182
-
183
- def __init__(self, username, password, api_key):
184
- self.username = username
185
- self.password = password
186
- self.api_key = api_key
187
-
188
- def check(self):
189
- if self.api_key is not None:
190
- return
191
- if self.username is not None and self.password is not None:
192
- ClickPrinter.warning('Using username/password credentials, '
193
- 'consider switching to API keys.')
194
- ClickPrinter.warning('Username/password authentication will be '
195
- 'removed in 3.25 as deprecated.')
196
- return False
197
- ClickPrinter.failure('Invalid credentials entered! You need to provide '
198
- 'either API key or username/password credentials.')
199
- sys.exit(1)
200
-
201
- def init_args(self):
202
- if self.api_key is not None:
203
- return {
204
- 'api_key': self.api_key,
205
- }
206
- return {
207
- 'username': self.username,
208
- 'password': self.password,
209
- }
210
-
211
-
212
185
  def interact_formats() -> Dict[str, FormatSpec]:
213
186
  add_format = click.confirm('Do you want to add a format?', default=True)
214
187
  formats = dict() # type: Dict[str, FormatSpec]
@@ -273,13 +246,14 @@ def main(ctx, quiet, debug, dot_env):
273
246
  if pathlib.Path(dot_env).exists():
274
247
  dotenv.load_dotenv(dotenv_path=dot_env)
275
248
  ctx.ensure_object(CLIContext)
249
+ ctx.obj.dot_env_file = dot_env
276
250
  if quiet:
277
251
  ctx.obj.quiet_mode()
278
252
  if debug:
279
253
  ctx.obj.debug_mode()
280
254
 
281
255
 
282
- @main.command(help='Create a new DSW template project.', name='new')
256
+ @main.command(help='Create a new template project.', name='new')
283
257
  @click.argument('TEMPLATE-DIR', type=NEW_DIR_TYPE, default=None, required=False)
284
258
  @click.option('-f', '--force', is_flag=True, help='Overwrite any matching files.')
285
259
  @click.pass_context
@@ -303,30 +277,25 @@ def new_template(ctx, template_dir, force):
303
277
  exit(1)
304
278
 
305
279
 
306
- @main.command(help='Download template from DSW.', name='get')
280
+ @main.command(help='Download template from Wizard.', name='get')
307
281
  @click.argument('TEMPLATE-ID')
308
282
  @click.argument('TEMPLATE-DIR', type=NEW_DIR_TYPE, default=None, required=False)
309
- @click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API',
310
- prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url)
311
- @click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None,
312
- help='Admin username (email) for DSW instance.')
313
- @click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None,
314
- help='Admin password for DSW instance.')
315
- @click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None,
316
- help='API key for DSW instance.')
283
+ @click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL',
284
+ prompt='API URL', help='URL of Wizard server API.', callback=rectify_url)
285
+ @click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY',
286
+ prompt='API Key', help='API key for Wizard instance.', callback=rectify_key,
287
+ hide_input=True)
317
288
  @click.option('-f', '--force', is_flag=True, help='Overwrite any existing files.')
318
289
  @click.pass_context
319
- def get_template(ctx, api_server, template_id, template_dir, username, password, api_key, force):
290
+ def get_template(ctx, api_url, template_id, template_dir, api_key, force):
320
291
  template_dir = pathlib.Path(template_dir or dir_from_id(template_id))
321
- creds = APICredentials(username=username, password=password, api_key=api_key)
322
- creds.check()
323
292
 
324
293
  async def main_routine():
325
294
  tdk = TDKCore(logger=ctx.obj.logger)
326
295
  template_type = 'unknown'
327
296
  zip_data = None
328
297
  try:
329
- await tdk.init_client(api_url=api_server, **creds.init_args())
298
+ await tdk.init_client(api_url=api_url, api_key=api_key)
330
299
  try:
331
300
  await tdk.load_remote(template_id=template_id)
332
301
  template_type = 'draft'
@@ -367,23 +336,18 @@ def get_template(ctx, api_server, template_id, template_dir, username, password,
367
336
  loop.run_until_complete(main_routine())
368
337
 
369
338
 
370
- @main.command(help='Upload template to DSW.', name='put')
339
+ @main.command(help='Upload template to Wizard.', name='put')
371
340
  @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False)
372
- @click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API',
373
- prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url)
374
- @click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None,
375
- help='Admin username (email) for DSW instance.')
376
- @click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None,
377
- help='Admin password for DSW instance.')
378
- @click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None,
379
- help='API key for DSW instance.')
341
+ @click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL',
342
+ prompt='API URL', help='URL of Wizard server API.', callback=rectify_url)
343
+ @click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY',
344
+ prompt='API Key', help='API key for Wizard instance.', callback=rectify_key,
345
+ hide_input=True)
380
346
  @click.option('-f', '--force', is_flag=True, help='Delete template if already exists.')
381
347
  @click.option('-w', '--watch', is_flag=True, help='Enter watch mode to continually upload changes.')
382
348
  @click.pass_context
383
- def put_template(ctx, api_server, template_dir, username, password, api_key, force, watch):
349
+ def put_template(ctx, api_url, template_dir, api_key, force, watch):
384
350
  tdk = TDKCore(logger=ctx.obj.logger)
385
- creds = APICredentials(username=username, password=password, api_key=api_key)
386
- creds.check()
387
351
 
388
352
  async def watch_callback(changes):
389
353
  changes = list(changes)
@@ -399,10 +363,10 @@ def put_template(ctx, api_server, template_dir, username, password, api_key, for
399
363
  async def main_routine():
400
364
  load_local(tdk, template_dir)
401
365
  try:
402
- await tdk.init_client(api_url=api_server, **creds.init_args())
366
+ await tdk.init_client(api_url=api_url, api_key=api_key)
403
367
  await tdk.store_remote(force=force)
404
368
  ClickPrinter.success(f'Template {tdk.safe_project.safe_template.id} '
405
- f'uploaded to {api_server}')
369
+ f'uploaded to {api_url}')
406
370
 
407
371
  if watch:
408
372
  ClickPrinter.watch('Entering watch mode... (press Ctrl+C to abort)')
@@ -427,7 +391,7 @@ def put_template(ctx, api_server, template_dir, username, password, api_key, for
427
391
  loop.run_until_complete(main_routine())
428
392
 
429
393
 
430
- @main.command(help='Create ZIP package for DSW template.', name='package')
394
+ @main.command(help='Create ZIP package for a template.', name='package')
431
395
  @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False)
432
396
  @click.option('-o', '--output', default='template.zip', type=click.Path(writable=True),
433
397
  show_default=True, help='Target package file.')
@@ -446,7 +410,7 @@ def create_package(ctx, template_dir, output, force: bool):
446
410
  ClickPrinter.success(f'Package {filename} created')
447
411
 
448
412
 
449
- @main.command(help='Extract DSW template from ZIP package', name='unpackage')
413
+ @main.command(help='Extract a template from ZIP package', name='unpackage')
450
414
  @click.argument('TEMPLATE-PACKAGE', type=FILE_READ_TYPE, required=False)
451
415
  @click.option('-o', '--output', type=NEW_DIR_TYPE, default=None, required=False,
452
416
  help='Target package file.')
@@ -468,29 +432,23 @@ def extract_package(ctx, template_package, output, force: bool):
468
432
  ClickPrinter.success(f'Package {template_package} extracted')
469
433
 
470
434
 
471
- @main.command(help='List templates from DSW via API.', name='list')
472
- @click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API',
473
- prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url)
474
- @click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None,
475
- help='Admin username (email) for DSW instance.')
476
- @click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None,
477
- help='Admin password for DSW instance.')
478
- @click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None,
479
- help='API key for DSW instance.')
435
+ @main.command(help='List templates from Wizard via API.', name='list')
436
+ @click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL',
437
+ prompt='API URL', help='URL of Wizard server API.', callback=rectify_url)
438
+ @click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY',
439
+ prompt='API Key', help='API key for Wizard instance.', callback=rectify_key,
440
+ hide_input=True)
480
441
  @click.option('--output-format', default=DEFAULT_LIST_FORMAT,
481
442
  metavar='FORMAT', help='Entry format string for printing.')
482
443
  @click.option('-r', '--released-only', is_flag=True, help='List only released templates')
483
444
  @click.option('-d', '--drafts-only', is_flag=True, help='List only template drafts')
484
445
  @click.pass_context
485
- def list_templates(ctx, api_server, username, password, api_key, output_format: str,
446
+ def list_templates(ctx, api_url, api_key, output_format: str,
486
447
  released_only: bool, drafts_only: bool):
487
- creds = APICredentials(username=username, password=password, api_key=api_key)
488
- creds.check()
489
-
490
448
  async def main_routine():
491
449
  tdk = TDKCore(logger=ctx.obj.logger)
492
450
  try:
493
- await tdk.init_client(api_url=api_server, **creds.init_args())
451
+ await tdk.init_client(api_url=api_url, api_key=api_key)
494
452
  if released_only:
495
453
  templates = await tdk.list_remote_templates()
496
454
  for template in templates:
@@ -520,7 +478,7 @@ def list_templates(ctx, api_server, username, password, api_key, output_format:
520
478
  loop.run_until_complete(main_routine())
521
479
 
522
480
 
523
- @main.command(help='Verify DSW template project.', name='verify')
481
+ @main.command(help='Verify a template project.', name='verify')
524
482
  @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False)
525
483
  @click.pass_context
526
484
  def verify_template(ctx, template_dir):
@@ -535,3 +493,28 @@ def verify_template(ctx, template_dir):
535
493
  click.echo('Found violations:')
536
494
  for err in errors:
537
495
  click.echo(f' - {err.field_name}: {err.message}')
496
+
497
+
498
+ @main.command(help='Create a .env file.', name='dot-env')
499
+ @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False)
500
+ @click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL',
501
+ prompt='API URL', help='URL of Wizard server API.', callback=rectify_url)
502
+ @click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY',
503
+ prompt='API Key', help='API key for Wizard instance.', callback=rectify_key,
504
+ hide_input=True)
505
+ @click.option('-f', '--force', is_flag=True, help='Overwrite file if already exists.')
506
+ @click.pass_context
507
+ def create_dot_env(ctx, template_dir, api_url, api_key, force):
508
+ filename = ctx.obj.dot_env_file or '.env'
509
+ tdk = TDKCore(logger=ctx.obj.logger)
510
+ try:
511
+ tdk.create_dot_env(
512
+ output=pathlib.Path(template_dir) / filename,
513
+ force=force,
514
+ api_url=api_url,
515
+ api_key=api_key,
516
+ )
517
+ except Exception as e:
518
+ ClickPrinter.failure('Failed to create dot-env file')
519
+ ClickPrinter.error(f'> {e}')
520
+ exit(1)
@@ -3,7 +3,7 @@ import pathspec # type: ignore
3
3
  import re
4
4
 
5
5
  APP = 'dsw-tdk'
6
- VERSION = '3.26.2'
6
+ VERSION = '3.27.1'
7
7
  METAMODEL_VERSION = 11
8
8
 
9
9
  REGEX_SEMVER = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+$')
@@ -15,7 +15,7 @@ from typing import List, Optional, Tuple
15
15
  from .api_client import DSWAPIClient, DSWCommunicationError
16
16
  from .consts import DEFAULT_ENCODING, REGEX_SEMVER
17
17
  from .model import TemplateProject, Template, TemplateFile, TemplateFileType
18
- from .utils import UUIDGen
18
+ from .utils import UUIDGen, create_dot_env
19
19
  from .validation import ValidationError, TemplateValidator
20
20
 
21
21
 
@@ -99,14 +99,9 @@ class TDKCore:
99
99
  raise RuntimeError('No DSW API client specified')
100
100
  return self.client
101
101
 
102
- async def init_client(self, api_url: str, username: Optional[str] = None,
103
- password: Optional[str] = None, api_key: Optional[str] = None):
102
+ async def init_client(self, api_url: str, api_key: str):
104
103
  self.logger.info(f'Connecting to {api_url}')
105
- self.client = DSWAPIClient(api_url=api_url)
106
- if api_key is not None:
107
- self.client.token = api_key # type: ignore
108
- if username is not None and password is not None:
109
- await self.client.login(email=username, password=password)
104
+ self.client = DSWAPIClient(api_url=api_url, api_key=api_key)
110
105
  self.remote_version = await self.client.get_api_version()
111
106
  user = await self.client.get_current_user()
112
107
  self.logger.info(f'Successfully authenticated as {user["firstName"]} '
@@ -362,6 +357,17 @@ class TDKCore:
362
357
  target_file.write_text(data=content, encoding=DEFAULT_ENCODING)
363
358
  self.logger.debug('Extracting package done')
364
359
 
360
+ def create_dot_env(self, output: pathlib.Path, force: bool, api_url: str, api_key: str):
361
+ if output.exists():
362
+ if force:
363
+ self.logger.warning(f'Overwriting {output.as_posix()} (forced)')
364
+ else:
365
+ raise RuntimeError(f'File {output} already exists (not forced)')
366
+ output.write_text(
367
+ data=create_dot_env(api_url=api_url, api_key=api_key),
368
+ encoding=DEFAULT_ENCODING,
369
+ )
370
+
365
371
  async def watch_project(self, callback):
366
372
  async for changes in watchgod.awatch(self.safe_project.template_dir):
367
373
  await callback((
@@ -0,0 +1 @@
1
+ // TODO: fill text of your license ({{ template.license }})
@@ -0,0 +1,2 @@
1
+ DSW_API_URL={{ api_url|default("http://localhost:3000") }}
2
+ DSW_API_KEY={{ api_key|default("") }}
@@ -2,7 +2,7 @@ import jinja2 # type: ignore
2
2
  import pathlib
3
3
  import uuid
4
4
 
5
- from typing import List, Set
5
+ from typing import List, Set, Optional
6
6
 
7
7
  from .consts import DEFAULT_ENCODING, DEFAULT_README
8
8
  from .model import Template, TemplateFile, Format, Step, PackageFilter
@@ -163,13 +163,33 @@ class TemplateBuilder:
163
163
  self.template.readme = readme
164
164
  self.template.tdk_config.readme_file = DEFAULT_README
165
165
  TemplateValidator.validate(self.template)
166
+
166
167
  for format_spec in self._formats:
167
168
  content = j2_env.get_template('starter.j2').render(template=self.template)
168
169
  self.template.files[format_spec.filename] = TemplateFile(
169
170
  filename=format_spec.filename,
170
171
  content_type='text/plain',
171
- content=content.encode(encoding=DEFAULT_ENCODING)
172
+ content=content.encode(encoding=DEFAULT_ENCODING),
172
173
  )
173
174
  self.template.tdk_config.files.append(str(format_spec.filename))
174
175
  self.template.allowed_packages.append(PackageFilter())
176
+
177
+ license_file = j2_env.get_template('LICENSE.j2').render(template=self.template)
178
+ self.template.tdk_config.files.append('LICENSE')
179
+ self.template.files['LICENSE'] = TemplateFile(
180
+ filename='LICENSE',
181
+ content_type='text/plain',
182
+ content=license_file.encode(encoding=DEFAULT_ENCODING),
183
+ )
184
+
185
+ self.template.files['.env'] = TemplateFile(
186
+ filename='.env',
187
+ content_type='text/plain',
188
+ content=create_dot_env().encode(encoding=DEFAULT_ENCODING),
189
+ )
190
+
175
191
  return self.template
192
+
193
+
194
+ def create_dot_env(api_url: Optional[str] = None, api_key: Optional[str] = None) -> str:
195
+ return j2_env.get_template('env.j2').render(api_url=api_url, api_key=api_key)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dsw-tdk
3
- Version: 3.26.2
3
+ Version: 3.27.1
4
4
  Summary: Data Stewardship Wizard Template Development Toolkit
5
5
  Author-email: Marek Suchánek <marek.suchanek@ds-wizard.org>
6
6
  License: Apache License 2.0
@@ -14,7 +14,9 @@ dsw/tdk/core.py
14
14
  dsw/tdk/model.py
15
15
  dsw/tdk/utils.py
16
16
  dsw/tdk/validation.py
17
+ dsw/tdk/templates/LICENSE.j2
17
18
  dsw/tdk/templates/README.md.j2
19
+ dsw/tdk/templates/env.j2
18
20
  dsw/tdk/templates/starter.j2
19
21
  dsw_tdk.egg-info/PKG-INFO
20
22
  dsw_tdk.egg-info/SOURCES.txt
@@ -24,6 +26,7 @@ dsw_tdk.egg-info/not-zip-safe
24
26
  dsw_tdk.egg-info/requires.txt
25
27
  dsw_tdk.egg-info/top_level.txt
26
28
  tests/test_basic.py
29
+ tests/test_cmd_dot-env.py
27
30
  tests/test_cmd_get.py
28
31
  tests/test_cmd_list.py
29
32
  tests/test_cmd_new.py
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'dsw-tdk'
7
- version = "3.26.2"
7
+ version = "3.27.1"
8
8
  description = 'Data Stewardship Wizard Template Development Toolkit'
9
9
  readme = 'README.md'
10
10
  keywords = ['documents', 'dsw', 'jinja2', 'template', 'toolkit']
@@ -0,0 +1,70 @@
1
+ import pathlib
2
+
3
+ import click.testing
4
+
5
+ from dsw.tdk import main
6
+
7
+
8
+ def test_creates_dot_env(tmp_path: pathlib.Path):
9
+ runner = click.testing.CliRunner()
10
+ inputs = ['https://example.com', 'mySecretKey']
11
+ with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir:
12
+ root_dir = pathlib.Path(isolated_dir)
13
+
14
+ result = runner.invoke(main, args=['dot-env', root_dir.as_posix()], input='\n'.join(inputs))
15
+ assert not result.exception
16
+ assert result.exit_code == 0
17
+ paths = frozenset(map(lambda x: str(x.relative_to(isolated_dir).as_posix()), tmp_path.rglob('*')))
18
+ assert '.env' in paths
19
+
20
+
21
+ def test_dot_env_contents(tmp_path: pathlib.Path):
22
+ runner = click.testing.CliRunner()
23
+ inputs = ['https://example.com', 'mySecretKey']
24
+ with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir:
25
+ root_dir = pathlib.Path(isolated_dir)
26
+ dot_env = root_dir / '.env'
27
+
28
+ result = runner.invoke(main, args=['dot-env', root_dir.as_posix()], input='\n'.join(inputs))
29
+ assert not result.exception
30
+ assert result.exit_code == 0
31
+ paths = frozenset(map(lambda x: str(x.relative_to(isolated_dir).as_posix()), tmp_path.rglob('*')))
32
+ assert '.env' in paths
33
+ contents = dot_env.read_text(encoding='utf-8')
34
+ assert 'DSW_API_URL=https://example.com' in contents
35
+ assert 'DSW_API_KEY=mySecretKey' in contents
36
+
37
+
38
+ def test_dot_env_no_force(tmp_path: pathlib.Path):
39
+ runner = click.testing.CliRunner()
40
+ inputs = ['https://example.com', 'mySecretKey']
41
+ with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir:
42
+ root_dir = pathlib.Path(isolated_dir)
43
+ dot_env = root_dir / '.env'
44
+ dot_env.write_text('test')
45
+
46
+ result = runner.invoke(main, args=['dot-env', root_dir.as_posix()], input='\n'.join(inputs))
47
+ assert result.exception
48
+ assert result.exit_code == 1
49
+
50
+ contents = dot_env.read_text(encoding='utf-8')
51
+ assert 'test' in contents
52
+
53
+
54
+ def test_dot_env_overwrites(tmp_path: pathlib.Path):
55
+ runner = click.testing.CliRunner()
56
+ inputs = ['https://example.com', 'mySecretKey']
57
+ with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir:
58
+ root_dir = pathlib.Path(isolated_dir)
59
+ dot_env = root_dir / '.env'
60
+ dot_env.write_text('test')
61
+
62
+ result = runner.invoke(main, args=['dot-env', root_dir.as_posix(), '--force'], input='\n'.join(inputs))
63
+ print(result.stdout)
64
+ assert not result.exception
65
+ assert result.exit_code == 0
66
+ paths = frozenset(map(lambda x: str(x.relative_to(isolated_dir).as_posix()), tmp_path.rglob('*')))
67
+ assert '.env' in paths
68
+ contents = dot_env.read_text(encoding='utf-8')
69
+ assert 'DSW_API_URL=https://example.com' in contents
70
+ assert 'DSW_API_KEY=mySecretKey' in contents
@@ -57,7 +57,7 @@ def test_get_draft_custom_dir(tmp_path: pathlib.Path, dsw_env: dict):
57
57
  @pytest.mark.vcr
58
58
  def test_put_bad_token(dsw_api_url: str):
59
59
  env_vars = {
60
- 'DSW_API': dsw_api_url,
60
+ 'DSW_API_URL': dsw_api_url,
61
61
  'DSW_API_KEY': 'foo',
62
62
  }
63
63
  runner = click.testing.CliRunner()
@@ -68,7 +68,7 @@ def test_put_bad_token(dsw_api_url: str):
68
68
  @pytest.mark.vcr
69
69
  def test_put_bad_url(dsw_api_key: str):
70
70
  env_vars = {
71
- 'DSW_API': 'http://localhost:33333',
71
+ 'DSW_API_URL': 'http://localhost:33333',
72
72
  'DSW_API_KEY': dsw_api_key,
73
73
  }
74
74
  runner = click.testing.CliRunner()
@@ -34,7 +34,7 @@ def test_list_released_only(dsw_env: dict):
34
34
  @pytest.mark.vcr
35
35
  def test_put_bad_token(dsw_api_url: str):
36
36
  env_vars = {
37
- 'DSW_API': dsw_api_url,
37
+ 'DSW_API_URL': dsw_api_url,
38
38
  'DSW_API_KEY': 'foo',
39
39
  }
40
40
  runner = click.testing.CliRunner()
@@ -45,7 +45,7 @@ def test_put_bad_token(dsw_api_url: str):
45
45
  @pytest.mark.vcr
46
46
  def test_put_bad_url(dsw_api_key: str):
47
47
  env_vars = {
48
- 'DSW_API': 'http://localhost:33333',
48
+ 'DSW_API_URL': 'http://localhost:33333',
49
49
  'DSW_API_KEY': dsw_api_key,
50
50
  }
51
51
  runner = click.testing.CliRunner()
@@ -11,6 +11,7 @@ def test_put_ok(fixtures_path: pathlib.Path, dsw_env: dict):
11
11
  runner = click.testing.CliRunner()
12
12
  template_path = fixtures_path / 'test_example01'
13
13
  result = runner.invoke(main, args=['put', template_path.as_posix()], env=dsw_env)
14
+ print(result.stdout)
14
15
  assert result.exit_code == 0
15
16
 
16
17
 
@@ -35,7 +36,7 @@ def test_put_bad_token(fixtures_path: pathlib.Path, dsw_api_url: str):
35
36
  runner = click.testing.CliRunner()
36
37
  template_path = fixtures_path / 'test_example01'
37
38
  env_vars = {
38
- 'DSW_API': dsw_api_url,
39
+ 'DSW_API_URL': dsw_api_url,
39
40
  'DSW_API_KEY': 'foo',
40
41
  }
41
42
  result = runner.invoke(main, args=['put', template_path.as_posix()], env=env_vars)
@@ -47,7 +48,7 @@ def test_put_bad_url(fixtures_path: pathlib.Path, dsw_api_key: str):
47
48
  runner = click.testing.CliRunner()
48
49
  template_path = fixtures_path / 'test_example01'
49
50
  env_vars = {
50
- 'DSW_API': 'http://localhost:33333',
51
+ 'DSW_API_URL': 'http://localhost:33333',
51
52
  'DSW_API_KEY': dsw_api_key,
52
53
  }
53
54
  result = runner.invoke(main, args=['put', template_path.as_posix()], env=env_vars)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes