From 23a4289cef35359a11670efe68fc8481e988d328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 3 Aug 2023 16:50:28 +0200 Subject: [PATCH 1/5] [DSW-2024] feat(tdk): Remove credentials authentication in TDK --- packages/dsw-tdk/dsw/tdk/api_client.py | 4 +- packages/dsw-tdk/dsw/tdk/cli.py | 137 ++++++++---------- packages/dsw-tdk/dsw/tdk/core.py | 22 ++- packages/dsw-tdk/dsw/tdk/templates/LICENSE.j2 | 1 + packages/dsw-tdk/dsw/tdk/templates/env.j2 | 2 + packages/dsw-tdk/dsw/tdk/utils.py | 24 ++- packages/dsw-tdk/tests/conftest.py | 4 +- packages/dsw-tdk/tests/test_cmd_dot-env.py | 70 +++++++++ packages/dsw-tdk/tests/test_cmd_get.py | 4 +- packages/dsw-tdk/tests/test_cmd_list.py | 4 +- packages/dsw-tdk/tests/test_cmd_put.py | 5 +- 11 files changed, 180 insertions(+), 97 deletions(-) create mode 100644 packages/dsw-tdk/dsw/tdk/templates/LICENSE.j2 create mode 100644 packages/dsw-tdk/dsw/tdk/templates/env.j2 create mode 100644 packages/dsw-tdk/tests/test_cmd_dot-env.py diff --git a/packages/dsw-tdk/dsw/tdk/api_client.py b/packages/dsw-tdk/dsw/tdk/api_client.py index d90d709d..11e8877f 100644 --- a/packages/dsw-tdk/dsw/tdk/api_client.py +++ b/packages/dsw-tdk/dsw/tdk/api_client.py @@ -81,7 +81,7 @@ def _check_status(r: aiohttp.ClientResponse, expected_status): f'{r.reason} (expecting {expected_status})' ) - def __init__(self, api_url: str, session=None): + def __init__(self, api_url: str, api_key: str, session=None): """ Exception representing communication error with DSW. @@ -90,7 +90,7 @@ def __init__(self, api_url: str, session=None): session (aiohttp.ClientSession): Optional custom session for HTTP communication. """ self.api_url = api_url - self.token = None + self.token = api_key self.session = session or aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False)) @property diff --git a/packages/dsw-tdk/dsw/tdk/cli.py b/packages/dsw-tdk/dsw/tdk/cli.py index 7e26a00a..3a02fa4c 100644 --- a/packages/dsw-tdk/dsw/tdk/cli.py +++ b/packages/dsw-tdk/dsw/tdk/cli.py @@ -1,5 +1,4 @@ import asyncio -import sys import click # type: ignore import datetime @@ -96,6 +95,10 @@ def rectify_url(ctx, param, value) -> str: return value.rstrip('/') +def rectify_key(ctx, param, value) -> str: + return value.strip() + + class ClickLogger(logging.Logger): NAME = 'DSW-TDK-CLI' @@ -169,6 +172,7 @@ class CLIContext: def __init__(self): self.logger = ClickLogger.default() + self.dot_env_file = None def debug_mode(self): self.logger.show_timestamp = True @@ -178,37 +182,6 @@ def quiet_mode(self): self.logger.muted = True -class APICredentials: - - def __init__(self, username, password, api_key): - self.username = username - self.password = password - self.api_key = api_key - - def check(self): - if self.api_key is not None: - return - if self.username is not None and self.password is not None: - ClickPrinter.warning('Using username/password credentials, ' - 'consider switching to API keys.') - ClickPrinter.warning('Username/password authentication will be ' - 'removed in 3.25 as deprecated.') - return False - ClickPrinter.failure('Invalid credentials entered! You need to provide ' - 'either API key or username/password credentials.') - sys.exit(1) - - def init_args(self): - if self.api_key is not None: - return { - 'api_key': self.api_key, - } - return { - 'username': self.username, - 'password': self.password, - } - - def interact_formats() -> Dict[str, FormatSpec]: add_format = click.confirm('Do you want to add a format?', default=True) formats = dict() # type: Dict[str, FormatSpec] @@ -273,13 +246,14 @@ def main(ctx, quiet, debug, dot_env): if pathlib.Path(dot_env).exists(): dotenv.load_dotenv(dotenv_path=dot_env) ctx.ensure_object(CLIContext) + ctx.obj.dot_env_file = dot_env if quiet: ctx.obj.quiet_mode() if debug: ctx.obj.debug_mode() -@main.command(help='Create a new DSW template project.', name='new') +@main.command(help='Create a new template project.', name='new') @click.argument('TEMPLATE-DIR', type=NEW_DIR_TYPE, default=None, required=False) @click.option('-f', '--force', is_flag=True, help='Overwrite any matching files.') @click.pass_context @@ -303,30 +277,25 @@ def new_template(ctx, template_dir, force): exit(1) -@main.command(help='Download template from DSW.', name='get') +@main.command(help='Download template from Wizard.', name='get') @click.argument('TEMPLATE-ID') @click.argument('TEMPLATE-DIR', type=NEW_DIR_TYPE, default=None, required=False) -@click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API', - prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url) -@click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None, - help='Admin username (email) for DSW instance.') -@click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None, - help='Admin password for DSW instance.') -@click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None, - help='API key for DSW instance.') +@click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL', + prompt='API URL', help='URL of Wizard server API.', callback=rectify_url) +@click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY', + prompt='API Key', help='API key for Wizard instance.', callback=rectify_key, + hide_input=True) @click.option('-f', '--force', is_flag=True, help='Overwrite any existing files.') @click.pass_context -def get_template(ctx, api_server, template_id, template_dir, username, password, api_key, force): +def get_template(ctx, api_url, template_id, template_dir, api_key, force): template_dir = pathlib.Path(template_dir or dir_from_id(template_id)) - creds = APICredentials(username=username, password=password, api_key=api_key) - creds.check() async def main_routine(): tdk = TDKCore(logger=ctx.obj.logger) template_type = 'unknown' zip_data = None try: - await tdk.init_client(api_url=api_server, **creds.init_args()) + await tdk.init_client(api_url=api_url, api_key=api_key) try: await tdk.load_remote(template_id=template_id) template_type = 'draft' @@ -367,23 +336,18 @@ async def main_routine(): loop.run_until_complete(main_routine()) -@main.command(help='Upload template to DSW.', name='put') +@main.command(help='Upload template to Wizard.', name='put') @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False) -@click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API', - prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url) -@click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None, - help='Admin username (email) for DSW instance.') -@click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None, - help='Admin password for DSW instance.') -@click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None, - help='API key for DSW instance.') +@click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL', + prompt='API URL', help='URL of Wizard server API.', callback=rectify_url) +@click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY', + prompt='API Key', help='API key for Wizard instance.', callback=rectify_key, + hide_input=True) @click.option('-f', '--force', is_flag=True, help='Delete template if already exists.') @click.option('-w', '--watch', is_flag=True, help='Enter watch mode to continually upload changes.') @click.pass_context -def put_template(ctx, api_server, template_dir, username, password, api_key, force, watch): +def put_template(ctx, api_url, template_dir, api_key, force, watch): tdk = TDKCore(logger=ctx.obj.logger) - creds = APICredentials(username=username, password=password, api_key=api_key) - creds.check() async def watch_callback(changes): changes = list(changes) @@ -399,10 +363,10 @@ async def watch_callback(changes): async def main_routine(): load_local(tdk, template_dir) try: - await tdk.init_client(api_url=api_server, **creds.init_args()) + await tdk.init_client(api_url=api_url, api_key=api_key) await tdk.store_remote(force=force) ClickPrinter.success(f'Template {tdk.safe_project.safe_template.id} ' - f'uploaded to {api_server}') + f'uploaded to {api_url}') if watch: ClickPrinter.watch('Entering watch mode... (press Ctrl+C to abort)') @@ -427,7 +391,7 @@ async def main_routine(): loop.run_until_complete(main_routine()) -@main.command(help='Create ZIP package for DSW template.', name='package') +@main.command(help='Create ZIP package for a template.', name='package') @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False) @click.option('-o', '--output', default='template.zip', type=click.Path(writable=True), show_default=True, help='Target package file.') @@ -446,7 +410,7 @@ def create_package(ctx, template_dir, output, force: bool): ClickPrinter.success(f'Package {filename} created') -@main.command(help='Extract DSW template from ZIP package', name='unpackage') +@main.command(help='Extract a template from ZIP package', name='unpackage') @click.argument('TEMPLATE-PACKAGE', type=FILE_READ_TYPE, required=False) @click.option('-o', '--output', type=NEW_DIR_TYPE, default=None, required=False, help='Target package file.') @@ -468,29 +432,23 @@ def extract_package(ctx, template_package, output, force: bool): ClickPrinter.success(f'Package {template_package} extracted') -@main.command(help='List templates from DSW via API.', name='list') -@click.option('-s', '--api-server', metavar='API-URL', envvar='DSW_API', - prompt='URL of DSW API', help='URL of DSW server API.', callback=rectify_url) -@click.option('-u', '--username', envvar='DSW_USERNAME', metavar='EMAIL', default=None, - help='Admin username (email) for DSW instance.') -@click.option('-p', '--password', envvar='DSW_PASSWORD', metavar='PASSWORD', default=None, - help='Admin password for DSW instance.') -@click.option('-k', '--api-key', envvar='DSW_API_KEY', metavar='API-KEY', default=None, - help='API key for DSW instance.') +@main.command(help='List templates from Wizard via API.', name='list') +@click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL', + prompt='API URL', help='URL of Wizard server API.', callback=rectify_url) +@click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY', + prompt='API Key', help='API key for Wizard instance.', callback=rectify_key, + hide_input=True) @click.option('--output-format', default=DEFAULT_LIST_FORMAT, metavar='FORMAT', help='Entry format string for printing.') @click.option('-r', '--released-only', is_flag=True, help='List only released templates') @click.option('-d', '--drafts-only', is_flag=True, help='List only template drafts') @click.pass_context -def list_templates(ctx, api_server, username, password, api_key, output_format: str, +def list_templates(ctx, api_url, api_key, output_format: str, released_only: bool, drafts_only: bool): - creds = APICredentials(username=username, password=password, api_key=api_key) - creds.check() - async def main_routine(): tdk = TDKCore(logger=ctx.obj.logger) try: - await tdk.init_client(api_url=api_server, **creds.init_args()) + await tdk.init_client(api_url=api_url, api_key=api_key) if released_only: templates = await tdk.list_remote_templates() for template in templates: @@ -520,7 +478,7 @@ async def main_routine(): loop.run_until_complete(main_routine()) -@main.command(help='Verify DSW template project.', name='verify') +@main.command(help='Verify a template project.', name='verify') @click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False) @click.pass_context def verify_template(ctx, template_dir): @@ -535,3 +493,28 @@ def verify_template(ctx, template_dir): click.echo('Found violations:') for err in errors: click.echo(f' - {err.field_name}: {err.message}') + + +@main.command(help='Create a .env file.', name='dot-env') +@click.argument('TEMPLATE-DIR', type=DIR_TYPE, default=CURRENT_DIR, required=False) +@click.option('-u', '--api-url', metavar='API-URL', envvar='DSW_API_URL', + prompt='API URL', help='URL of Wizard server API.', callback=rectify_url) +@click.option('-k', '--api-key', metavar='API-KEY', envvar='DSW_API_KEY', + prompt='API Key', help='API key for Wizard instance.', callback=rectify_key, + hide_input=True) +@click.option('-f', '--force', is_flag=True, help='Overwrite file if already exists.') +@click.pass_context +def create_dot_env(ctx, template_dir, api_url, api_key, force): + filename = ctx.obj.dot_env_file or '.env' + tdk = TDKCore(logger=ctx.obj.logger) + try: + tdk.create_dot_env( + output=pathlib.Path(template_dir) / filename, + force=force, + api_url=api_url, + api_key=api_key, + ) + except Exception as e: + ClickPrinter.failure('Failed to create dot-env file') + ClickPrinter.error(f'> {e}') + exit(1) diff --git a/packages/dsw-tdk/dsw/tdk/core.py b/packages/dsw-tdk/dsw/tdk/core.py index d80082ba..18ee0896 100644 --- a/packages/dsw-tdk/dsw/tdk/core.py +++ b/packages/dsw-tdk/dsw/tdk/core.py @@ -15,7 +15,7 @@ from .api_client import DSWAPIClient, DSWCommunicationError from .consts import DEFAULT_ENCODING, REGEX_SEMVER from .model import TemplateProject, Template, TemplateFile, TemplateFileType -from .utils import UUIDGen +from .utils import UUIDGen, create_dot_env from .validation import ValidationError, TemplateValidator @@ -99,14 +99,9 @@ def safe_client(self) -> DSWAPIClient: raise RuntimeError('No DSW API client specified') return self.client - async def init_client(self, api_url: str, username: Optional[str] = None, - password: Optional[str] = None, api_key: Optional[str] = None): + async def init_client(self, api_url: str, api_key: str): self.logger.info(f'Connecting to {api_url}') - self.client = DSWAPIClient(api_url=api_url) - if api_key is not None: - self.client.token = api_key # type: ignore - if username is not None and password is not None: - await self.client.login(email=username, password=password) + self.client = DSWAPIClient(api_url=api_url, api_key=api_key) self.remote_version = await self.client.get_api_version() user = await self.client.get_current_user() self.logger.info(f'Successfully authenticated as {user["firstName"]} ' @@ -362,6 +357,17 @@ def extract_package(self, zip_data: bytes, template_dir: Optional[pathlib.Path], target_file.write_text(data=content, encoding=DEFAULT_ENCODING) self.logger.debug('Extracting package done') + def create_dot_env(self, output: pathlib.Path, force: bool, api_url: str, api_key: str): + if output.exists(): + if force: + self.logger.warning(f'Overwriting {output.as_posix()} (forced)') + else: + raise RuntimeError(f'File {output} already exists (not forced)') + output.write_text( + data=create_dot_env(api_url=api_url, api_key=api_key), + encoding=DEFAULT_ENCODING, + ) + async def watch_project(self, callback): async for changes in watchgod.awatch(self.safe_project.template_dir): await callback(( diff --git a/packages/dsw-tdk/dsw/tdk/templates/LICENSE.j2 b/packages/dsw-tdk/dsw/tdk/templates/LICENSE.j2 new file mode 100644 index 00000000..27cdf109 --- /dev/null +++ b/packages/dsw-tdk/dsw/tdk/templates/LICENSE.j2 @@ -0,0 +1 @@ +// TODO: fill text of your license ({{ template.license }}) diff --git a/packages/dsw-tdk/dsw/tdk/templates/env.j2 b/packages/dsw-tdk/dsw/tdk/templates/env.j2 new file mode 100644 index 00000000..f2f091bb --- /dev/null +++ b/packages/dsw-tdk/dsw/tdk/templates/env.j2 @@ -0,0 +1,2 @@ +DSW_API_URL={{ api_url|default("http://localhost:3000") }} +DSW_API_KEY={{ api_key|default("") }} diff --git a/packages/dsw-tdk/dsw/tdk/utils.py b/packages/dsw-tdk/dsw/tdk/utils.py index d4b11344..5ba26caa 100644 --- a/packages/dsw-tdk/dsw/tdk/utils.py +++ b/packages/dsw-tdk/dsw/tdk/utils.py @@ -2,7 +2,7 @@ import pathlib import uuid -from typing import List, Set +from typing import List, Set, Optional from .consts import DEFAULT_ENCODING, DEFAULT_README from .model import Template, TemplateFile, Format, Step, PackageFilter @@ -163,13 +163,33 @@ def build(self) -> Template: self.template.readme = readme self.template.tdk_config.readme_file = DEFAULT_README TemplateValidator.validate(self.template) + for format_spec in self._formats: content = j2_env.get_template('starter.j2').render(template=self.template) self.template.files[format_spec.filename] = TemplateFile( filename=format_spec.filename, content_type='text/plain', - content=content.encode(encoding=DEFAULT_ENCODING) + content=content.encode(encoding=DEFAULT_ENCODING), ) self.template.tdk_config.files.append(str(format_spec.filename)) self.template.allowed_packages.append(PackageFilter()) + + license_file = j2_env.get_template('LICENSE.j2').render(template=self.template) + self.template.tdk_config.files.append('LICENSE') + self.template.files['LICENSE'] = TemplateFile( + filename='LICENSE', + content_type='text/plain', + content=license_file.encode(encoding=DEFAULT_ENCODING), + ) + + self.template.files['.env'] = TemplateFile( + filename='.env', + content_type='text/plain', + content=create_dot_env().encode(encoding=DEFAULT_ENCODING), + ) + return self.template + + +def create_dot_env(api_url: Optional[str] = None, api_key: Optional[str] = None) -> str: + return j2_env.get_template('env.j2').render(api_url=api_url, api_key=api_key) diff --git a/packages/dsw-tdk/tests/conftest.py b/packages/dsw-tdk/tests/conftest.py index da61dd88..0be5c69d 100644 --- a/packages/dsw-tdk/tests/conftest.py +++ b/packages/dsw-tdk/tests/conftest.py @@ -20,7 +20,7 @@ @pytest.fixture(scope='session') def dsw_api_url(): - value = os.environ.get('DSW_API', 'http://localhost:3000') + value = os.environ.get('DSW_API_URL', 'http://localhost:3000') return value @@ -33,7 +33,7 @@ def dsw_api_key(): @pytest.fixture(scope='session') def dsw_env(dsw_api_url: str, dsw_api_key: str): return { - 'DSW_API': dsw_api_url, + 'DSW_API_URL': dsw_api_url, 'DSW_API_KEY': dsw_api_key, } diff --git a/packages/dsw-tdk/tests/test_cmd_dot-env.py b/packages/dsw-tdk/tests/test_cmd_dot-env.py new file mode 100644 index 00000000..47ae18e0 --- /dev/null +++ b/packages/dsw-tdk/tests/test_cmd_dot-env.py @@ -0,0 +1,70 @@ +import pathlib + +import click.testing + +from dsw.tdk import main + + +def test_creates_dot_env(tmp_path: pathlib.Path): + runner = click.testing.CliRunner() + inputs = ['https://example.com', 'mySecretKey'] + with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir: + root_dir = pathlib.Path(isolated_dir) + + result = runner.invoke(main, args=['dot-env', root_dir.as_posix()], input='\n'.join(inputs)) + assert not result.exception + assert result.exit_code == 0 + paths = frozenset(map(lambda x: str(x.relative_to(isolated_dir).as_posix()), tmp_path.rglob('*'))) + assert '.env' in paths + + +def test_dot_env_contents(tmp_path: pathlib.Path): + runner = click.testing.CliRunner() + inputs = ['https://example.com', 'mySecretKey'] + with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir: + root_dir = pathlib.Path(isolated_dir) + dot_env = root_dir / '.env' + + result = runner.invoke(main, args=['dot-env', root_dir.as_posix()], input='\n'.join(inputs)) + assert not result.exception + assert result.exit_code == 0 + paths = frozenset(map(lambda x: str(x.relative_to(isolated_dir).as_posix()), tmp_path.rglob('*'))) + assert '.env' in paths + contents = dot_env.read_text(encoding='utf-8') + assert 'DSW_API_URL=https://example.com' in contents + assert 'DSW_API_KEY=mySecretKey' in contents + + +def test_dot_env_no_force(tmp_path: pathlib.Path): + runner = click.testing.CliRunner() + inputs = ['https://example.com', 'mySecretKey'] + with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir: + root_dir = pathlib.Path(isolated_dir) + dot_env = root_dir / '.env' + dot_env.write_text('test') + + result = runner.invoke(main, args=['dot-env', root_dir.as_posix()], input='\n'.join(inputs)) + assert result.exception + assert result.exit_code == 1 + + contents = dot_env.read_text(encoding='utf-8') + assert 'test' in contents + + +def test_dot_env_overwrites(tmp_path: pathlib.Path): + runner = click.testing.CliRunner() + inputs = ['https://example.com', 'mySecretKey'] + with runner.isolated_filesystem(temp_dir=tmp_path) as isolated_dir: + root_dir = pathlib.Path(isolated_dir) + dot_env = root_dir / '.env' + dot_env.write_text('test') + + result = runner.invoke(main, args=['dot-env', root_dir.as_posix(), '--force'], input='\n'.join(inputs)) + print(result.stdout) + assert not result.exception + assert result.exit_code == 0 + paths = frozenset(map(lambda x: str(x.relative_to(isolated_dir).as_posix()), tmp_path.rglob('*'))) + assert '.env' in paths + contents = dot_env.read_text(encoding='utf-8') + assert 'DSW_API_URL=https://example.com' in contents + assert 'DSW_API_KEY=mySecretKey' in contents diff --git a/packages/dsw-tdk/tests/test_cmd_get.py b/packages/dsw-tdk/tests/test_cmd_get.py index c049031b..d7dd562f 100644 --- a/packages/dsw-tdk/tests/test_cmd_get.py +++ b/packages/dsw-tdk/tests/test_cmd_get.py @@ -57,7 +57,7 @@ def test_get_draft_custom_dir(tmp_path: pathlib.Path, dsw_env: dict): @pytest.mark.vcr def test_put_bad_token(dsw_api_url: str): env_vars = { - 'DSW_API': dsw_api_url, + 'DSW_API_URL': dsw_api_url, 'DSW_API_KEY': 'foo', } runner = click.testing.CliRunner() @@ -68,7 +68,7 @@ def test_put_bad_token(dsw_api_url: str): @pytest.mark.vcr def test_put_bad_url(dsw_api_key: str): env_vars = { - 'DSW_API': 'http://localhost:33333', + 'DSW_API_URL': 'http://localhost:33333', 'DSW_API_KEY': dsw_api_key, } runner = click.testing.CliRunner() diff --git a/packages/dsw-tdk/tests/test_cmd_list.py b/packages/dsw-tdk/tests/test_cmd_list.py index d149afb4..dcc38e32 100644 --- a/packages/dsw-tdk/tests/test_cmd_list.py +++ b/packages/dsw-tdk/tests/test_cmd_list.py @@ -34,7 +34,7 @@ def test_list_released_only(dsw_env: dict): @pytest.mark.vcr def test_put_bad_token(dsw_api_url: str): env_vars = { - 'DSW_API': dsw_api_url, + 'DSW_API_URL': dsw_api_url, 'DSW_API_KEY': 'foo', } runner = click.testing.CliRunner() @@ -45,7 +45,7 @@ def test_put_bad_token(dsw_api_url: str): @pytest.mark.vcr def test_put_bad_url(dsw_api_key: str): env_vars = { - 'DSW_API': 'http://localhost:33333', + 'DSW_API_URL': 'http://localhost:33333', 'DSW_API_KEY': dsw_api_key, } runner = click.testing.CliRunner() diff --git a/packages/dsw-tdk/tests/test_cmd_put.py b/packages/dsw-tdk/tests/test_cmd_put.py index 2a886d17..8ba8b186 100644 --- a/packages/dsw-tdk/tests/test_cmd_put.py +++ b/packages/dsw-tdk/tests/test_cmd_put.py @@ -11,6 +11,7 @@ def test_put_ok(fixtures_path: pathlib.Path, dsw_env: dict): runner = click.testing.CliRunner() template_path = fixtures_path / 'test_example01' result = runner.invoke(main, args=['put', template_path.as_posix()], env=dsw_env) + print(result.stdout) assert result.exit_code == 0 @@ -35,7 +36,7 @@ def test_put_bad_token(fixtures_path: pathlib.Path, dsw_api_url: str): runner = click.testing.CliRunner() template_path = fixtures_path / 'test_example01' env_vars = { - 'DSW_API': dsw_api_url, + 'DSW_API_URL': dsw_api_url, 'DSW_API_KEY': 'foo', } 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): runner = click.testing.CliRunner() template_path = fixtures_path / 'test_example01' env_vars = { - 'DSW_API': 'http://localhost:33333', + 'DSW_API_URL': 'http://localhost:33333', 'DSW_API_KEY': dsw_api_key, } result = runner.invoke(main, args=['put', template_path.as_posix()], env=env_vars) From db543d1aeb484301a33d381e8db030d22cf2cda3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 1 Aug 2023 15:31:52 +0200 Subject: [PATCH 2/5] [DSW-2017] feat(mailer): Add notification emails about API keys --- packages/dsw-mailer/dsw/mailer/templates.py | 18 +++- .../wizard/apiKeyCreated/message.html.j2 | 92 +++++++++++++++++++ .../wizard/apiKeyCreated/message.json | 16 ++++ .../wizard/apiKeyCreated/message.txt.j2 | 12 +++ .../wizard/apiKeyExpiration/message.html.j2 | 91 ++++++++++++++++++ .../wizard/apiKeyExpiration/message.json | 16 ++++ .../wizard/apiKeyExpiration/message.txt.j2 | 11 +++ 7 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 packages/dsw-mailer/templates/wizard/apiKeyCreated/message.html.j2 create mode 100644 packages/dsw-mailer/templates/wizard/apiKeyCreated/message.json create mode 100644 packages/dsw-mailer/templates/wizard/apiKeyCreated/message.txt.j2 create mode 100644 packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.html.j2 create mode 100644 packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.json create mode 100644 packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.txt.j2 diff --git a/packages/dsw-mailer/dsw/mailer/templates.py b/packages/dsw-mailer/dsw/mailer/templates.py index 1cd100fa..507118cc 100644 --- a/packages/dsw-mailer/dsw/mailer/templates.py +++ b/packages/dsw-mailer/dsw/mailer/templates.py @@ -1,9 +1,11 @@ +import datetime +import dateutil.parser import jinja2 import json import logging import pathlib -from typing import Optional +from typing import Optional, Union from .config import MailerConfig, MailConfig from .consts import DEFAULT_ENCODING @@ -68,8 +70,14 @@ def __init__(self, cfg: MailerConfig, workdir: pathlib.Path): extensions=['jinja2.ext.do'], ) self.templates = dict() # type: dict[str, MailTemplate] + self._set_filters() self._load_templates() + def _set_filters(self): + self.j2_env.filters.update({ + 'datetime_format': datetime_format, + }) + def _load_jinja2(self, file_path: pathlib.Path) -> Optional[jinja2.Template]: if file_path.exists() and file_path.is_file(): return self.j2_env.get_template( @@ -153,3 +161,11 @@ def render(self, rq: MessageRequest, cfg: MailConfig) -> MailMessage: mail_name=used_cfg.name, mail_from=used_cfg.email, ) + + +def datetime_format(iso_timestamp: Union[None, datetime.datetime, str], fmt: str): + if iso_timestamp is None: + return '' + if not isinstance(iso_timestamp, datetime.datetime): + iso_timestamp = dateutil.parser.isoparse(iso_timestamp) + return iso_timestamp.strftime(fmt) diff --git a/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.html.j2 b/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.html.j2 new file mode 100644 index 00000000..97c18a5f --- /dev/null +++ b/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.html.j2 @@ -0,0 +1,92 @@ +{% extends '_common/layout.html.j2' %} +{% block body %} + + + + + + +
+ + + + + + + + +
+

+ Dear {{ ctx.userFirstName }},

+ A new API key named {{ ctx.tokenName }} has been created for your account.
+ It will expire on {{ ctx.tokenExpiresAt|datetime_format("%B %-d, %Y (at %H:%M %Z)") }}. +

+
+ + +
+ + + + + + +
+ + + + + + +
+ Manage API Keys +
+
+ + + + + + +
+ + + + + + + + +
+

+ {% if ctx.supportEmail %} + If you did not create this API key or encounter any issues, please contact us via {{ ctx.supportEmail }}. + {% endif %}

+ Thank you for using the DSW!

+ {% if ctx.appTitle %}{{ ctx.appTitle }} team{% endif %} +

+
+ + +
+{% endblock %} diff --git a/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.json b/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.json new file mode 100644 index 00000000..cd4f58af --- /dev/null +++ b/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.json @@ -0,0 +1,16 @@ +{ + "id": "wizard:apiKeyCreated", + "subject": "A new API key has been created", + "subjectPrefix": true, + "defaultSenderName": "DSW", + "parts": [ + { + "type": "html", + "file": "message.html.j2" + }, + { + "type": "plain", + "file": "message.txt.j2" + } + ] +} diff --git a/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.txt.j2 b/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.txt.j2 new file mode 100644 index 00000000..7f802588 --- /dev/null +++ b/packages/dsw-mailer/templates/wizard/apiKeyCreated/message.txt.j2 @@ -0,0 +1,12 @@ +Dear {{ ctx.userFirstName }}, + +A new API key named "{{ ctx.tokenName }}" has been created for your account. +It will expire on {{ ctx.tokenExpiresAt|datetime_format("%B %-d, %Y (at %H:%M %Z)") }}. + +You can manage your API keys here: {{ ctx.clientUrl }}/users/edit/current/api-keys + +{% if ctx.supportEmail %} +If you did not initiate this login attempt, please contact us via {{ ctx.supportEmail }}. +{% endif %} + +{% include '_common/footer.txt.j2' %} diff --git a/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.html.j2 b/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.html.j2 new file mode 100644 index 00000000..f68f235d --- /dev/null +++ b/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.html.j2 @@ -0,0 +1,91 @@ +{% extends '_common/layout.html.j2' %} +{% block body %} + + + + + + +
+ + + + + + + + +
+

+ Dear {{ ctx.userFirstName }},

+ Your API key, identified as {{ ctx.tokenName }}, is scheduled to expire on {{ ctx.tokenExpiresAt|datetime_format("%B %-d, %Y (at %H:%M %Z)") }}. +

+
+ + +
+ + + + + + +
+ + + + + + +
+ Manage API Keys +
+
+ + + + + + +
+ + + + + + + + +
+

+ {% if ctx.supportEmail %} + If you encounter any issues, please contact us via {{ ctx.supportEmail }}. + {% endif %}

+ Thank you for using the DSW!

+ {% if ctx.appTitle %}{{ ctx.appTitle }} team{% endif %} +

+
+ + +
+{% endblock %} diff --git a/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.json b/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.json new file mode 100644 index 00000000..840726f4 --- /dev/null +++ b/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.json @@ -0,0 +1,16 @@ +{ + "id": "wizard:apiKeyExpiration", + "subject": "Your API key will expire soon", + "subjectPrefix": true, + "defaultSenderName": "DSW", + "parts": [ + { + "type": "html", + "file": "message.html.j2" + }, + { + "type": "plain", + "file": "message.txt.j2" + } + ] +} diff --git a/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.txt.j2 b/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.txt.j2 new file mode 100644 index 00000000..595c72cf --- /dev/null +++ b/packages/dsw-mailer/templates/wizard/apiKeyExpiration/message.txt.j2 @@ -0,0 +1,11 @@ +Dear {{ ctx.userFirstName }}, + +Your API key, identified as {{ ctx.tokenName }}, is scheduled to expire on {{ ctx.tokenExpiresAt|datetime_format("%B %-d, %Y (at %H:%M %Z)") }}. + +You can manage your API keys here: {{ ctx.clientUrl }}/users/edit/current/api-keys + +{% if ctx.supportEmail %} +If you did not initiate this login attempt, please contact us via {{ ctx.supportEmail }}. +{% endif %} + +{% include '_common/footer.txt.j2' %} From 2505dde3b56ef91ded487edbf2fcccefe88bf635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 10 Aug 2023 09:22:25 +0200 Subject: [PATCH 3/5] Update dependencies --- packages/dsw-command-queue/requirements.txt | 4 +- packages/dsw-config/requirements.txt | 4 +- packages/dsw-data-seeder/requirements.txt | 8 +-- packages/dsw-database/requirements.txt | 4 +- packages/dsw-document-worker/requirements.txt | 14 ++-- packages/dsw-mailer/requirements.txt | 10 +-- packages/dsw-models/requirements.txt | 1 - packages/dsw-storage/requirements.txt | 2 +- requirements.txt | 28 ++++---- scripts/update-deps.py | 66 +++++++++++++++++++ 10 files changed, 103 insertions(+), 38 deletions(-) create mode 100644 scripts/update-deps.py diff --git a/packages/dsw-command-queue/requirements.txt b/packages/dsw-command-queue/requirements.txt index 31089512..d307ded8 100644 --- a/packages/dsw-command-queue/requirements.txt +++ b/packages/dsw-command-queue/requirements.txt @@ -1,5 +1,5 @@ -psycopg==3.1.9 -psycopg-binary==3.1.9 +psycopg==3.1.10 +psycopg-binary==3.1.10 PyYAML==6.0.1 tenacity==8.2.2 typing_extensions==4.7.1 diff --git a/packages/dsw-config/requirements.txt b/packages/dsw-config/requirements.txt index 62c7d059..80b9f9ae 100644 --- a/packages/dsw-config/requirements.txt +++ b/packages/dsw-config/requirements.txt @@ -1,4 +1,4 @@ certifi==2023.7.22 PyYAML==6.0.1 -sentry-sdk==1.28.1 -urllib3==1.26.16 +sentry-sdk==1.29.2 +urllib3==2.0.4 diff --git a/packages/dsw-data-seeder/requirements.txt b/packages/dsw-data-seeder/requirements.txt index 7a5f3e4d..dd2618a3 100644 --- a/packages/dsw-data-seeder/requirements.txt +++ b/packages/dsw-data-seeder/requirements.txt @@ -2,12 +2,12 @@ certifi==2023.7.22 click==8.1.6 minio==7.1.15 python-dateutil==2.8.2 -psycopg==3.1.9 -psycopg-binary==3.1.9 +psycopg==3.1.10 +psycopg-binary==3.1.10 PyYAML==6.0.1 -sentry-sdk==1.28.1 +sentry-sdk==1.29.2 six==1.16.0 tenacity==8.2.2 typing_extensions==4.7.1 tzdata==2023.3 -urllib3==1.26.16 +urllib3==2.0.4 diff --git a/packages/dsw-database/requirements.txt b/packages/dsw-database/requirements.txt index 31089512..d307ded8 100644 --- a/packages/dsw-database/requirements.txt +++ b/packages/dsw-database/requirements.txt @@ -1,5 +1,5 @@ -psycopg==3.1.9 -psycopg-binary==3.1.9 +psycopg==3.1.10 +psycopg-binary==3.1.10 PyYAML==6.0.1 tenacity==8.2.2 typing_extensions==4.7.1 diff --git a/packages/dsw-document-worker/requirements.txt b/packages/dsw-document-worker/requirements.txt index bb985f1b..a14cf1a4 100644 --- a/packages/dsw-document-worker/requirements.txt +++ b/packages/dsw-document-worker/requirements.txt @@ -4,7 +4,7 @@ cffi==1.15.1 charset-normalizer==3.2.0 click==8.1.6 cssselect2==0.7.0 -fonttools==4.41.1 +fonttools==4.42.0 html5lib==1.1 idna==3.4 isodate==0.6.1 @@ -15,9 +15,9 @@ mdx-breakless-lists==1.0.1 minio==7.1.15 pathvalidate==3.1.0 pdfrw==0.4 -Pillow==9.5.0 -psycopg==3.1.9 -psycopg-binary==3.1.9 +Pillow==10.0.0 +psycopg==3.1.10 +psycopg-binary==3.1.10 pycparser==2.21 pydyf==0.7.0 pyparsing==3.1.1 @@ -25,17 +25,17 @@ pyphen==0.14.0 python-dateutil==2.8.2 python-slugify==8.0.1 PyYAML==6.0.1 -rdflib==6.3.2 +rdflib==7.0.0 rdflib-jsonld==0.6.2 requests==2.31.0 -sentry-sdk==1.28.1 +sentry-sdk==1.29.2 six==1.16.0 tenacity==8.2.2 text-unidecode==1.3 tinycss2==1.2.1 typing_extensions==4.7.1 tzdata==2023.3 -urllib3==1.26.16 +urllib3==2.0.4 weasyprint==59.0 webencodings==0.5.1 XlsxWriter==3.1.2 diff --git a/packages/dsw-mailer/requirements.txt b/packages/dsw-mailer/requirements.txt index e6c71289..c8f9d13f 100644 --- a/packages/dsw-mailer/requirements.txt +++ b/packages/dsw-mailer/requirements.txt @@ -1,17 +1,17 @@ certifi==2023.7.22 click==8.1.6 dkimpy==1.1.5 -dnspython==2.4.1 +dnspython==2.4.2 Jinja2==3.1.2 MarkupSafe==2.1.3 pathvalidate==3.1.0 -psycopg==3.1.9 -psycopg-binary==3.1.9 +psycopg==3.1.10 +psycopg-binary==3.1.10 python-dateutil==2.8.2 PyYAML==6.0.1 -sentry-sdk==1.28.1 +sentry-sdk==1.29.2 six==1.16.0 tenacity==8.2.2 typing_extensions==4.7.1 tzdata==2023.3 -urllib3==1.26.16 +urllib3==2.0.4 diff --git a/packages/dsw-models/requirements.txt b/packages/dsw-models/requirements.txt index 0d386161..e69de29b 100644 --- a/packages/dsw-models/requirements.txt +++ b/packages/dsw-models/requirements.txt @@ -1 +0,0 @@ -# No requirements at this point diff --git a/packages/dsw-storage/requirements.txt b/packages/dsw-storage/requirements.txt index 1dc1a2bc..58f3436c 100644 --- a/packages/dsw-storage/requirements.txt +++ b/packages/dsw-storage/requirements.txt @@ -2,4 +2,4 @@ certifi==2023.7.22 minio==7.1.15 PyYAML==6.0.1 tenacity==8.2.2 -urllib3==1.26.16 +urllib3==2.0.4 diff --git a/requirements.txt b/requirements.txt index c1ebacdc..7e2d56c4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,9 @@ -Brotli==1.0.9 -Jinja2==3.1.2 -Markdown==3.4.4 -MarkupSafe==2.1.3 -Pillow==9.5.0 -PyYAML==6.0.1 -XlsxWriter==3.1.2 aiohttp==3.8.5 aiosignal==1.3.1 anyio==3.7.1 async-timeout==4.0.2 attrs==23.1.0 +Brotli==1.0.9 certifi==2023.7.22 cffi==1.15.1 charset-normalizer==3.2.0 @@ -17,21 +11,25 @@ click==8.1.6 colorama==0.4.6 cssselect2==0.7.0 dkimpy==1.1.5 -dnspython==2.4.1 -fonttools==4.41.1 +dnspython==2.4.2 +fonttools==4.42.0 frozenlist==1.4.0 html5lib==1.1 humanize==4.7.0 idna==3.4 isodate==0.6.1 +Jinja2==3.1.2 +Markdown==3.4.4 +MarkupSafe==2.1.3 mdx-breakless-lists==1.0.1 minio==7.1.15 multidict==6.0.4 pathspec==0.11.2 pathvalidate==3.1.0 pdfrw==0.4 -psycopg-binary==3.1.9 -psycopg==3.1.9 +Pillow==10.0.0 +psycopg==3.1.10 +psycopg-binary==3.1.10 pycparser==2.21 pydyf==0.7.0 pyparsing==3.1.1 @@ -39,10 +37,11 @@ pyphen==0.14.0 python-dateutil==2.8.2 python-dotenv==1.0.0 python-slugify==8.0.1 +PyYAML==6.0.1 +rdflib==7.0.0 rdflib-jsonld==0.6.2 -rdflib==6.3.2 requests==2.31.0 -sentry-sdk==1.28.1 +sentry-sdk==1.29.2 six==1.16.0 sniffio==1.3.0 tenacity==8.2.2 @@ -50,9 +49,10 @@ text-unidecode==1.3 tinycss2==1.2.1 typing_extensions==4.7.1 tzdata==2023.3 -urllib3==1.26.16 +urllib3==2.0.4 watchgod==0.8.2 weasyprint==59.0 webencodings==0.5.1 +XlsxWriter==3.1.2 yarl==1.9.2 zopfli==0.2.2 diff --git a/scripts/update-deps.py b/scripts/update-deps.py new file mode 100644 index 00000000..8379f618 --- /dev/null +++ b/scripts/update-deps.py @@ -0,0 +1,66 @@ +import pathlib +import shutil +import subprocess +import venv + +ENC = 'utf-8' + + +def run_update(root_dir: pathlib.Path): + _update_root_requirements(root_dir) + _update_packages(root_dir) + +def _update_root_requirements(root_dir: pathlib.Path): + env_dir = root_dir / 'env-deps' + pip = env_dir / 'bin' / 'pip' + pip_upgrade = env_dir / 'bin' / 'pip-upgrade' + requirements_file = root_dir / 'requirements.txt' + reqs = requirements_file.read_text(ENC) + reqs.replace('==', '>=') + requirements_file.write_text(reqs, ENC) + venv.create( + env_dir=env_dir, + system_site_packages=False, + clear=True, + with_pip=True, + ) + p = subprocess.Popen( + args=[pip, 'install', 'pip-upgrader'], + ) + p.wait() + p = subprocess.Popen( + args=[pip_upgrade, requirements_file.as_posix()], + ) + p.wait() + shutil.rmtree(env_dir) + +def _update_packages(root_dir: pathlib.Path): + requirements_file = root_dir / 'requirements.txt' + packages_dir = root_dir / 'packages' + deps = _load_deps(requirements_file) + for path in packages_dir.rglob('**/requirements.txt'): + _update_pkg_requirements(path, deps) + +def _update_pkg_requirements(requirements_file: pathlib.Path, deps: dict[str, str]): + lines = [] + for line in requirements_file.read_text(ENC).splitlines(): + parts = line.split('==') + if len(parts) != 2: + continue + dep = parts[0] + ver = deps.get(dep, parts[1]) + lines.append(f'{dep}=={ver}') + lines.append('') + requirements_file.write_text('\n'.join(lines), ENC) + +def _load_deps(requirements_file: pathlib.Path) -> dict[str, str]: + result = {} + for line in requirements_file.read_text(ENC).splitlines(): + parts = line.split('==') + if len(parts) == 2: + result[parts[0]] = parts[1] + return result + + +if __name__ == '__main__': + run_update(pathlib.Path(__file__).parent.parent) From 86f5de800b110aa9f94f51b1aeac684da63aa695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 27 Aug 2023 20:23:38 +0200 Subject: [PATCH 4/5] Release 3.27.0-RC.1 --- packages/dsw-command-queue/CHANGELOG.md | 5 +++++ packages/dsw-command-queue/pyproject.toml | 4 ++-- packages/dsw-config/CHANGELOG.md | 5 +++++ packages/dsw-config/pyproject.toml | 2 +- packages/dsw-data-seeder/CHANGELOG.md | 5 +++++ packages/dsw-data-seeder/dsw/data_seeder/consts.py | 2 +- packages/dsw-data-seeder/pyproject.toml | 10 +++++----- packages/dsw-data-seeder/requirements.txt | 2 +- packages/dsw-database/CHANGELOG.md | 5 +++++ packages/dsw-database/pyproject.toml | 4 ++-- packages/dsw-document-worker/CHANGELOG.md | 5 +++++ .../dsw-document-worker/dsw/document_worker/consts.py | 2 +- packages/dsw-document-worker/pyproject.toml | 10 +++++----- packages/dsw-document-worker/requirements.txt | 2 +- packages/dsw-mailer/CHANGELOG.md | 7 +++++++ packages/dsw-mailer/dsw/mailer/consts.py | 2 +- packages/dsw-mailer/pyproject.toml | 8 ++++---- packages/dsw-mailer/requirements.txt | 2 +- packages/dsw-models/CHANGELOG.md | 5 +++++ packages/dsw-models/pyproject.toml | 2 +- packages/dsw-storage/CHANGELOG.md | 5 +++++ packages/dsw-storage/pyproject.toml | 4 ++-- packages/dsw-tdk/CHANGELOG.md | 7 +++++++ packages/dsw-tdk/dsw/tdk/consts.py | 2 +- packages/dsw-tdk/pyproject.toml | 2 +- packages/dsw-tdk/requirements.txt | 2 +- 26 files changed, 80 insertions(+), 31 deletions(-) diff --git a/packages/dsw-command-queue/CHANGELOG.md b/packages/dsw-command-queue/CHANGELOG.md index 390b24bb..0c21529f 100644 --- a/packages/dsw-command-queue/CHANGELOG.md +++ b/packages/dsw-command-queue/CHANGELOG.md @@ -8,6 +8,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +Released for version consistency with other DSW tools. + ## [3.26.1] Released for version consistency with other DSW tools. @@ -132,3 +136,4 @@ Released for version consistency with other DSW tools. [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-command-queue/pyproject.toml b/packages/dsw-command-queue/pyproject.toml index 6467f3fc..355be5a4 100644 --- a/packages/dsw-command-queue/pyproject.toml +++ b/packages/dsw-command-queue/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-command-queue' -version = "3.26.1" +version = "3.26.0rc1" description = 'Library for working with command queue and persistent commands' readme = 'README.md' keywords = ['dsw', 'subscriber', 'publisher', 'database', 'queue', 'processing'] @@ -25,7 +25,7 @@ classifiers = [ requires-python = '>=3.10, <4' dependencies = [ # DSW - "dsw-database==3.26.1", + "dsw-database==3.26.0rc1", ] [project.urls] diff --git a/packages/dsw-config/CHANGELOG.md b/packages/dsw-config/CHANGELOG.md index d6139a40..ad462cde 100644 --- a/packages/dsw-config/CHANGELOG.md +++ b/packages/dsw-config/CHANGELOG.md @@ -8,6 +8,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +Released for version consistency with other DSW tools. + ## [3.26.1] Released for version consistency with other DSW tools. @@ -140,3 +144,4 @@ Released for version consistency with other DSW tools. [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-config/pyproject.toml b/packages/dsw-config/pyproject.toml index f8283f3c..32c88a1e 100644 --- a/packages/dsw-config/pyproject.toml +++ b/packages/dsw-config/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-config' -version = "3.26.1" +version = "3.26.0rc1" description = 'Library for DSW config manipulation' readme = 'README.md' keywords = ['dsw', 'config', 'yaml', 'parser'] diff --git a/packages/dsw-data-seeder/CHANGELOG.md b/packages/dsw-data-seeder/CHANGELOG.md index 193c9052..46a8e6c1 100644 --- a/packages/dsw-data-seeder/CHANGELOG.md +++ b/packages/dsw-data-seeder/CHANGELOG.md @@ -8,6 +8,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +Released for version consistency with other DSW tools. + ## [3.26.1] Released for version consistency with other DSW tools. @@ -180,3 +184,4 @@ Released for version consistency with other DSW tools. [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-data-seeder/dsw/data_seeder/consts.py b/packages/dsw-data-seeder/dsw/data_seeder/consts.py index 78a1a184..d62fc27e 100644 --- a/packages/dsw-data-seeder/dsw/data_seeder/consts.py +++ b/packages/dsw-data-seeder/dsw/data_seeder/consts.py @@ -6,4 +6,4 @@ DEFAULT_PLACEHOLDER = '<<|APP-ID|>>' NULL_UUID = '00000000-0000-0000-0000-000000000000' PROG_NAME = 'dsw-data-seeder' -VERSION = '3.26.1' +VERSION = '3.27.0' diff --git a/packages/dsw-data-seeder/pyproject.toml b/packages/dsw-data-seeder/pyproject.toml index cb5cbab5..980f21bc 100644 --- a/packages/dsw-data-seeder/pyproject.toml +++ b/packages/dsw-data-seeder/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-data-seeder' -version = "3.26.1" +version = "3.26.0rc1" description = 'Worker for seeding DSW data' readme = 'README.md' keywords = ['data', 'database', 'seed', 'storage'] @@ -29,10 +29,10 @@ dependencies = [ 'sentry-sdk', 'tenacity', # DSW - "dsw-command-queue==3.26.1", - "dsw-config==3.26.1", - "dsw-database==3.26.1", - "dsw-storage==3.26.1", + "dsw-command-queue==3.26.0rc1", + "dsw-config==3.26.0rc1", + "dsw-database==3.26.0rc1", + "dsw-storage==3.26.0rc1", ] [project.urls] diff --git a/packages/dsw-data-seeder/requirements.txt b/packages/dsw-data-seeder/requirements.txt index dd2618a3..8fc81f4d 100644 --- a/packages/dsw-data-seeder/requirements.txt +++ b/packages/dsw-data-seeder/requirements.txt @@ -1,5 +1,5 @@ certifi==2023.7.22 -click==8.1.6 +click==8.1.7 minio==7.1.15 python-dateutil==2.8.2 psycopg==3.1.10 diff --git a/packages/dsw-database/CHANGELOG.md b/packages/dsw-database/CHANGELOG.md index 9dac025c..e7a05934 100644 --- a/packages/dsw-database/CHANGELOG.md +++ b/packages/dsw-database/CHANGELOG.md @@ -8,6 +8,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +Released for version consistency with other DSW tools. + ## [3.26.1] Released for version consistency with other DSW tools. @@ -147,3 +151,4 @@ Released for version consistency with other DSW tools. [3.25.1]: /../../tree/v3.25.1 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-database/pyproject.toml b/packages/dsw-database/pyproject.toml index e67fe3e2..b13d0b84 100644 --- a/packages/dsw-database/pyproject.toml +++ b/packages/dsw-database/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-database' -version = "3.26.1" +version = "3.26.0rc1" description = 'Library for managing DSW database' readme = 'README.md' keywords = ['dsw', 'database'] @@ -26,7 +26,7 @@ dependencies = [ 'psycopg[binary]', 'tenacity', # DSW - "dsw-config==3.26.1", + "dsw-config==3.26.0rc1", ] [project.urls] diff --git a/packages/dsw-document-worker/CHANGELOG.md b/packages/dsw-document-worker/CHANGELOG.md index 0946c736..2c764e5e 100644 --- a/packages/dsw-document-worker/CHANGELOG.md +++ b/packages/dsw-document-worker/CHANGELOG.md @@ -8,6 +8,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +Released for version consistency with other DSW tools. + ## [3.26.1] Released for version consistency with other DSW tools. @@ -171,3 +175,4 @@ Released for version consistency with other DSW tools. [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-document-worker/dsw/document_worker/consts.py b/packages/dsw-document-worker/dsw/document_worker/consts.py index 0964a007..024b0970 100644 --- a/packages/dsw-document-worker/dsw/document_worker/consts.py +++ b/packages/dsw-document-worker/dsw/document_worker/consts.py @@ -6,7 +6,7 @@ EXIT_SUCCESS = 0 NULL_UUID = '00000000-0000-0000-0000-000000000000' PROG_NAME = 'docworker' -VERSION = '3.26.1' +VERSION = '3.27.0' class DocumentState: diff --git a/packages/dsw-document-worker/pyproject.toml b/packages/dsw-document-worker/pyproject.toml index 4bf1a046..6d0a23c8 100644 --- a/packages/dsw-document-worker/pyproject.toml +++ b/packages/dsw-document-worker/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-document-worker' -version = "3.26.1" +version = "3.26.0rc1" description = 'Worker for assembling and transforming documents' readme = 'README.md' keywords = ['documents', 'generation', 'jinja2', 'pandoc', 'worker'] @@ -40,10 +40,10 @@ dependencies = [ 'weasyprint', 'XlsxWriter', # DSW - "dsw-command-queue==3.26.1", - "dsw-config==3.26.1", - "dsw-database==3.26.1", - "dsw-storage==3.26.1", + "dsw-command-queue==3.26.0rc1", + "dsw-config==3.26.0rc1", + "dsw-database==3.26.0rc1", + "dsw-storage==3.26.0rc1", ] [project.urls] diff --git a/packages/dsw-document-worker/requirements.txt b/packages/dsw-document-worker/requirements.txt index a14cf1a4..c4a90712 100644 --- a/packages/dsw-document-worker/requirements.txt +++ b/packages/dsw-document-worker/requirements.txt @@ -2,7 +2,7 @@ Brotli==1.0.9 certifi==2023.7.22 cffi==1.15.1 charset-normalizer==3.2.0 -click==8.1.6 +click==8.1.7 cssselect2==0.7.0 fonttools==4.42.0 html5lib==1.1 diff --git a/packages/dsw-mailer/CHANGELOG.md b/packages/dsw-mailer/CHANGELOG.md index 5ed38578..6fa894c6 100644 --- a/packages/dsw-mailer/CHANGELOG.md +++ b/packages/dsw-mailer/CHANGELOG.md @@ -8,6 +8,12 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +### Added + +- Notification emails about API keys + ## [3.26.1] ### Fixed @@ -155,3 +161,4 @@ Released for version consistency with other DSW tools. [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-mailer/dsw/mailer/consts.py b/packages/dsw-mailer/dsw/mailer/consts.py index a615ac94..0a3883b8 100644 --- a/packages/dsw-mailer/dsw/mailer/consts.py +++ b/packages/dsw-mailer/dsw/mailer/consts.py @@ -5,4 +5,4 @@ DEFAULT_ENCODING = 'utf-8' NULL_UUID = '00000000-0000-0000-0000-000000000000' PROG_NAME = 'dsw-mailer' -VERSION = '3.26.1' +VERSION = '3.27.0' diff --git a/packages/dsw-mailer/pyproject.toml b/packages/dsw-mailer/pyproject.toml index 4f313d26..c1a6038a 100644 --- a/packages/dsw-mailer/pyproject.toml +++ b/packages/dsw-mailer/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-mailer' -version = "3.26.1" +version = "3.26.0rc1" description = 'Worker for sending email notifications' readme = 'README.md' keywords = ['email', 'jinja2', 'notification', 'template'] @@ -31,9 +31,9 @@ dependencies = [ 'sentry-sdk', 'tenacity', # DSW - "dsw-command-queue==3.26.1", - "dsw-config==3.26.1", - "dsw-database==3.26.1", + "dsw-command-queue==3.26.0rc1", + "dsw-config==3.26.0rc1", + "dsw-database==3.26.0rc1", ] [project.urls] diff --git a/packages/dsw-mailer/requirements.txt b/packages/dsw-mailer/requirements.txt index c8f9d13f..eb82ca2c 100644 --- a/packages/dsw-mailer/requirements.txt +++ b/packages/dsw-mailer/requirements.txt @@ -1,5 +1,5 @@ certifi==2023.7.22 -click==8.1.6 +click==8.1.7 dkimpy==1.1.5 dnspython==2.4.2 Jinja2==3.1.2 diff --git a/packages/dsw-models/CHANGELOG.md b/packages/dsw-models/CHANGELOG.md index f1b8f62b..c8c9ff97 100644 --- a/packages/dsw-models/CHANGELOG.md +++ b/packages/dsw-models/CHANGELOG.md @@ -8,6 +8,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +Released for version consistency with other DSW tools. + ## [3.26.1] Released for version consistency with other DSW tools. @@ -65,3 +69,4 @@ Released for version consistency with other DSW tools. [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-models/pyproject.toml b/packages/dsw-models/pyproject.toml index 973993d3..a4f0ca03 100644 --- a/packages/dsw-models/pyproject.toml +++ b/packages/dsw-models/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-models' -version = "3.26.1" +version = "3.26.0rc1" description = 'Library with DSW models and basic IO operations' readme = 'README.md' keywords = ['dsw', 'config', 'yaml', 'parser'] diff --git a/packages/dsw-storage/CHANGELOG.md b/packages/dsw-storage/CHANGELOG.md index 7ca3eb05..e7984041 100644 --- a/packages/dsw-storage/CHANGELOG.md +++ b/packages/dsw-storage/CHANGELOG.md @@ -8,6 +8,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [3.27.0] + +Released for version consistency with other DSW tools. + ## [3.26.1] Released for version consistency with other DSW tools. @@ -127,3 +131,4 @@ Released for version consistency with other DSW tools. [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-storage/pyproject.toml b/packages/dsw-storage/pyproject.toml index 3c2fd149..f2f28362 100644 --- a/packages/dsw-storage/pyproject.toml +++ b/packages/dsw-storage/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-storage' -version = "3.26.1" +version = "3.26.0rc1" description = 'Library for managing DSW S3 storage' readme = 'README.md' keywords = ['dsw', 's3', 'bucket', 'storage'] @@ -26,7 +26,7 @@ dependencies = [ 'minio', 'tenacity', # DSW - "dsw-config==3.26.1", + "dsw-config==3.26.0rc1", ] [project.urls] diff --git a/packages/dsw-tdk/CHANGELOG.md b/packages/dsw-tdk/CHANGELOG.md index 48450cc1..7d0d660c 100644 --- a/packages/dsw-tdk/CHANGELOG.md +++ b/packages/dsw-tdk/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.27.0] + +### Changed + +- Removed legacy support for authentication using credentials + ## [3.26.1] Released for version consistency with other DSW tools. @@ -340,3 +346,4 @@ Initial DSW Template Development Kit (versioned as part of the [DSW platform](ht [3.25.0]: /../../tree/v3.25.0 [3.26.0]: /../../tree/v3.26.0 [3.26.1]: /../../tree/v3.26.1 +[3.27.0]: /../../tree/v3.27.0 diff --git a/packages/dsw-tdk/dsw/tdk/consts.py b/packages/dsw-tdk/dsw/tdk/consts.py index e941b298..9fcaaa48 100644 --- a/packages/dsw-tdk/dsw/tdk/consts.py +++ b/packages/dsw-tdk/dsw/tdk/consts.py @@ -3,7 +3,7 @@ import re APP = 'dsw-tdk' -VERSION = '3.26.1' +VERSION = '3.27.0' METAMODEL_VERSION = 11 REGEX_SEMVER = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+$') diff --git a/packages/dsw-tdk/pyproject.toml b/packages/dsw-tdk/pyproject.toml index c16a8d68..9f19acdf 100644 --- a/packages/dsw-tdk/pyproject.toml +++ b/packages/dsw-tdk/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-tdk' -version = "3.26.1" +version = "3.26.0rc1" description = 'Data Stewardship Wizard Template Development Toolkit' readme = 'README.md' keywords = ['documents', 'dsw', 'jinja2', 'template', 'toolkit'] diff --git a/packages/dsw-tdk/requirements.txt b/packages/dsw-tdk/requirements.txt index 6f6d454f..14242f95 100644 --- a/packages/dsw-tdk/requirements.txt +++ b/packages/dsw-tdk/requirements.txt @@ -4,7 +4,7 @@ anyio==3.7.1 async-timeout==4.0.2 attrs==23.1.0 charset-normalizer==3.2.0 -click==8.1.6 +click==8.1.7 colorama==0.4.6 frozenlist==1.4.0 humanize==4.7.0 From 0b4f28113135e74617ae1318ae03baa2d6254f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 5 Sep 2023 08:23:26 +0200 Subject: [PATCH 5/5] Release 3.27.0 --- packages/dsw-command-queue/pyproject.toml | 4 ++-- packages/dsw-config/pyproject.toml | 2 +- packages/dsw-data-seeder/pyproject.toml | 10 +++++----- packages/dsw-database/pyproject.toml | 4 ++-- packages/dsw-document-worker/pyproject.toml | 10 +++++----- packages/dsw-mailer/pyproject.toml | 8 ++++---- packages/dsw-models/pyproject.toml | 2 +- packages/dsw-storage/pyproject.toml | 4 ++-- packages/dsw-tdk/pyproject.toml | 2 +- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/dsw-command-queue/pyproject.toml b/packages/dsw-command-queue/pyproject.toml index 355be5a4..ba08c3d3 100644 --- a/packages/dsw-command-queue/pyproject.toml +++ b/packages/dsw-command-queue/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-command-queue' -version = "3.26.0rc1" +version = "3.27.0" description = 'Library for working with command queue and persistent commands' readme = 'README.md' keywords = ['dsw', 'subscriber', 'publisher', 'database', 'queue', 'processing'] @@ -25,7 +25,7 @@ classifiers = [ requires-python = '>=3.10, <4' dependencies = [ # DSW - "dsw-database==3.26.0rc1", + "dsw-database==3.27.0", ] [project.urls] diff --git a/packages/dsw-config/pyproject.toml b/packages/dsw-config/pyproject.toml index 32c88a1e..6ed23146 100644 --- a/packages/dsw-config/pyproject.toml +++ b/packages/dsw-config/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-config' -version = "3.26.0rc1" +version = "3.27.0" description = 'Library for DSW config manipulation' readme = 'README.md' keywords = ['dsw', 'config', 'yaml', 'parser'] diff --git a/packages/dsw-data-seeder/pyproject.toml b/packages/dsw-data-seeder/pyproject.toml index 980f21bc..943d155a 100644 --- a/packages/dsw-data-seeder/pyproject.toml +++ b/packages/dsw-data-seeder/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-data-seeder' -version = "3.26.0rc1" +version = "3.27.0" description = 'Worker for seeding DSW data' readme = 'README.md' keywords = ['data', 'database', 'seed', 'storage'] @@ -29,10 +29,10 @@ dependencies = [ 'sentry-sdk', 'tenacity', # DSW - "dsw-command-queue==3.26.0rc1", - "dsw-config==3.26.0rc1", - "dsw-database==3.26.0rc1", - "dsw-storage==3.26.0rc1", + "dsw-command-queue==3.27.0", + "dsw-config==3.27.0", + "dsw-database==3.27.0", + "dsw-storage==3.27.0", ] [project.urls] diff --git a/packages/dsw-database/pyproject.toml b/packages/dsw-database/pyproject.toml index b13d0b84..3502a183 100644 --- a/packages/dsw-database/pyproject.toml +++ b/packages/dsw-database/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-database' -version = "3.26.0rc1" +version = "3.27.0" description = 'Library for managing DSW database' readme = 'README.md' keywords = ['dsw', 'database'] @@ -26,7 +26,7 @@ dependencies = [ 'psycopg[binary]', 'tenacity', # DSW - "dsw-config==3.26.0rc1", + "dsw-config==3.27.0", ] [project.urls] diff --git a/packages/dsw-document-worker/pyproject.toml b/packages/dsw-document-worker/pyproject.toml index 6d0a23c8..d42379b8 100644 --- a/packages/dsw-document-worker/pyproject.toml +++ b/packages/dsw-document-worker/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-document-worker' -version = "3.26.0rc1" +version = "3.27.0" description = 'Worker for assembling and transforming documents' readme = 'README.md' keywords = ['documents', 'generation', 'jinja2', 'pandoc', 'worker'] @@ -40,10 +40,10 @@ dependencies = [ 'weasyprint', 'XlsxWriter', # DSW - "dsw-command-queue==3.26.0rc1", - "dsw-config==3.26.0rc1", - "dsw-database==3.26.0rc1", - "dsw-storage==3.26.0rc1", + "dsw-command-queue==3.27.0", + "dsw-config==3.27.0", + "dsw-database==3.27.0", + "dsw-storage==3.27.0", ] [project.urls] diff --git a/packages/dsw-mailer/pyproject.toml b/packages/dsw-mailer/pyproject.toml index c1a6038a..45a79be3 100644 --- a/packages/dsw-mailer/pyproject.toml +++ b/packages/dsw-mailer/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-mailer' -version = "3.26.0rc1" +version = "3.27.0" description = 'Worker for sending email notifications' readme = 'README.md' keywords = ['email', 'jinja2', 'notification', 'template'] @@ -31,9 +31,9 @@ dependencies = [ 'sentry-sdk', 'tenacity', # DSW - "dsw-command-queue==3.26.0rc1", - "dsw-config==3.26.0rc1", - "dsw-database==3.26.0rc1", + "dsw-command-queue==3.27.0", + "dsw-config==3.27.0", + "dsw-database==3.27.0", ] [project.urls] diff --git a/packages/dsw-models/pyproject.toml b/packages/dsw-models/pyproject.toml index a4f0ca03..794a1027 100644 --- a/packages/dsw-models/pyproject.toml +++ b/packages/dsw-models/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-models' -version = "3.26.0rc1" +version = "3.27.0" description = 'Library with DSW models and basic IO operations' readme = 'README.md' keywords = ['dsw', 'config', 'yaml', 'parser'] diff --git a/packages/dsw-storage/pyproject.toml b/packages/dsw-storage/pyproject.toml index f2f28362..03cdc665 100644 --- a/packages/dsw-storage/pyproject.toml +++ b/packages/dsw-storage/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-storage' -version = "3.26.0rc1" +version = "3.27.0" description = 'Library for managing DSW S3 storage' readme = 'README.md' keywords = ['dsw', 's3', 'bucket', 'storage'] @@ -26,7 +26,7 @@ dependencies = [ 'minio', 'tenacity', # DSW - "dsw-config==3.26.0rc1", + "dsw-config==3.27.0", ] [project.urls] diff --git a/packages/dsw-tdk/pyproject.toml b/packages/dsw-tdk/pyproject.toml index 9f19acdf..467a75d1 100644 --- a/packages/dsw-tdk/pyproject.toml +++ b/packages/dsw-tdk/pyproject.toml @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta' [project] name = 'dsw-tdk' -version = "3.26.0rc1" +version = "3.27.0" description = 'Data Stewardship Wizard Template Development Toolkit' readme = 'README.md' keywords = ['documents', 'dsw', 'jinja2', 'template', 'toolkit']