From e1cf181b14912759091c2a8b89ef037e1897d119 Mon Sep 17 00:00:00 2001 From: Danick Fort Date: Sun, 6 Mar 2022 10:34:30 +0100 Subject: [PATCH 1/2] SWING-126 Implement Changelog --- {{cookiecutter.project_slug}}/README.md | 28 +++++ {{cookiecutter.project_slug}}/fabfile.py | 109 +++++++++++++++--- .../requirements/base.in | 1 + .../config/settings/base.py | 8 ++ 4 files changed, 130 insertions(+), 16 deletions(-) diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md index 8226bff..2ff4feb 100644 --- a/{{cookiecutter.project_slug}}/README.md +++ b/{{cookiecutter.project_slug}}/README.md @@ -78,3 +78,31 @@ For example, running tests with `scripts/run_tests.sh {{ cookiecutter.project_sl re-creating the database from scratch on each run. {%- endif %} + +## Deploying + + +Before deploying, you should update the CHANGELOG.md file with the latest changes by running: + ``` + docker-compose exec backend fab generate_changelog +``` + +**Note**: this step is not strictly required, but be aware that the CHANGELOG.md file should reflect the current status +of the project. For example, you might not want to update the changelog if you are pushing an urgent hotfix/doing tests. + + +To deploy the site, run: + ``` + docker-compose exec backend fab deploy +``` + +Where __ can either be _prod_ or _staging_. To see all the available Fabric commands, run: + +``` + docker-compose exec backend fab -l +``` + +If the deployment command asks you for a password, make sure you have _ssh-agent_ running on your host and your SSH key +has been added to it (using `ssh-add`) and that it has been forwarded to the box when you SSHed into it. + +Make sure `fab bootstrap` has already been run before the first ever deployment. diff --git a/{{cookiecutter.project_slug}}/fabfile.py b/{{cookiecutter.project_slug}}/fabfile.py index ba0c943..d8aa3a3 100644 --- a/{{cookiecutter.project_slug}}/fabfile.py +++ b/{{cookiecutter.project_slug}}/fabfile.py @@ -360,6 +360,28 @@ def outgoing_commits(c): print_commits(get_outgoing_commits(c)) +@task +@remote +def files_to_deploy(c): + with c.conn.cd(c.conn.project_root): + remote_version = c.conn.git("rev-parse last_master", hide=True).stdout.strip() + new_version = subprocess.run( + "git rev-parse HEAD".split(" "), + text=True, + capture_output=True, + cwd=local_project_root, + ).stdout.strip() + + return [ + line + for line in subprocess.run( + f"git diff --name-only {remote_version}..{new_version}".split(" "), + text=True, capture_output=True + ).stdout.splitlines() + if line.strip() + ] + + def get_local_modifications_count(): return len( [ @@ -372,6 +394,30 @@ def get_local_modifications_count(): ) +@task +@remote +def generate_changelog(c, ignorecheck="n", initialize="n", **kwargs): + local_modification_count = get_local_modifications_count() + check_ignored = ignorecheck.lower() in ("y", "yes") + initialize = initialize.lower() in ("y", "yes") + if not check_ignored and local_modification_count > 0: + print( + f"There are {local_modification_count} local files that are not commited." + + " Please commit or discard changes before generating changelog" + ) + return + jira_release( + c, + "generate_changelog", + **{ + "jira-prefix": jira_prefix, + "environment": c.config.environment, + "git-path": local_project_root, + "initialize": initialize + }, + ) + + @task @remote def log(c): @@ -497,6 +543,38 @@ def import_db(c, dump_file=None, with_media=False): import_media(c) +def jira_release(c, command, **kwargs): + full_kwargs = dict() + + if c.config["environment"] == "prod": + command = "comment_and_close_issues_to_deploy" + else: + command = "comment_after_deploy" + + if "remote-version" not in kwargs and "to-deploy-version" not in kwargs: + with c.conn.cd(c.conn.project_root): + remote_version = c.conn.git("rev-parse last_master", hide=True).stdout.strip() + new_version = subprocess.run( + "git rev-parse HEAD".split(" "), + text=True, + capture_output=True, + cwd=local_project_root, + ).stdout.strip() + + full_kwargs = { + "remote-version": remote_version, + "to-deploy-version": new_version, + } + + full_kwargs.update(kwargs) + + local_command = f"jira_release {command}" + for key, value in full_kwargs.items(): + local_command += f" --{key}={value}" + + subprocess.run(local_command.split(" ")) + + @task @remote def comment_and_close_on_jira(c): @@ -505,22 +583,14 @@ def comment_and_close_on_jira(c): else: command = "comment_after_deploy" - with c.conn.cd(c.conn.project_root): - remote_version = c.conn.git("rev-parse last_master", hide=True).stdout.strip() - new_version = subprocess.run( - "git rev-parse HEAD".split(" "), - text=True, - capture_output=True, - cwd=local_project_root, - ).stdout.strip() - - subprocess.run( - f"jira_release {command} " - f"--jira-prefix={jira_prefix} " - f"--environment={c.config.environment} " - f"--remote-version={remote_version} " - f"--to-deploy-version={new_version} " - f"--git-path={local_project_root}".split(" ") + jira_release( + c, + command, + **{ + "jira-prefix": jira_prefix, + "environment": c.config.environment, + "git-path": local_project_root, + }, ) @@ -562,6 +632,13 @@ def deploy(c, noconfirm=False): ).lower() not in ("y", "yes"): return + if "CHANGELOG.md" not in files_to_deploy(): + if input( + "Warning ! It seems that the CHANGELOG file was not updated for this deployment. " + "Do you want to proceed ? [y/N] " + ).lower() not in ("y", "yes"): + return + _init_last_master(c) compile_assets() push_code_update(c, "HEAD") diff --git a/{{cookiecutter.project_slug}}/requirements/base.in b/{{cookiecutter.project_slug}}/requirements/base.in index 6251d9e..3ff4885 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.in +++ b/{{cookiecutter.project_slug}}/requirements/base.in @@ -3,6 +3,7 @@ Django>=4.0,<4.1 # TODO: Update to 4.2 LTS when it is released (April 2023) psycopg2-binary dj_email_url argon2-cffi +git+https://github.com/danickfort-liip/django-changelogmd.git@main {%- if cookiecutter.use_djangocms == 'y' %} django-cms diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/config/settings/base.py b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/config/settings/base.py index d017a4e..b5e6e34 100644 --- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/config/settings/base.py +++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/config/settings/base.py @@ -206,6 +206,7 @@ "easy_thumbnails", "django.contrib.sites", {% endif -%} + "changelogmd", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", @@ -273,3 +274,10 @@ EMAIL_USE_TLS = email_config["EMAIL_USE_TLS"] EMAIL_USE_SSL = email_config["EMAIL_USE_SSL"] DEFAULT_FROM_EMAIL = get_env_variable("EMAIL_FROM", "webmaster@localhost") + + +################# +# Changelog gen # +################# + +CHANGELOG_MD_PATH = os.path.join(BASE_DIR, "CHANGELOG.md") From 0de547c32f85a7900a3834bc6b4fa886a548c56f Mon Sep 17 00:00:00 2001 From: Danick Fort Date: Wed, 27 Apr 2022 16:56:33 +0200 Subject: [PATCH 2/2] Code review --- {{cookiecutter.project_slug}}/README.md | 2 +- {{cookiecutter.project_slug}}/fabfile.py | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/{{cookiecutter.project_slug}}/README.md b/{{cookiecutter.project_slug}}/README.md index 2ff4feb..94a54e3 100644 --- a/{{cookiecutter.project_slug}}/README.md +++ b/{{cookiecutter.project_slug}}/README.md @@ -84,7 +84,7 @@ re-creating the database from scratch on each run. Before deploying, you should update the CHANGELOG.md file with the latest changes by running: ``` - docker-compose exec backend fab generate_changelog + docker-compose exec backend fab generate-changelog ``` **Note**: this step is not strictly required, but be aware that the CHANGELOG.md file should reflect the current status diff --git a/{{cookiecutter.project_slug}}/fabfile.py b/{{cookiecutter.project_slug}}/fabfile.py index d8aa3a3..6255577 100644 --- a/{{cookiecutter.project_slug}}/fabfile.py +++ b/{{cookiecutter.project_slug}}/fabfile.py @@ -360,7 +360,6 @@ def outgoing_commits(c): print_commits(get_outgoing_commits(c)) -@task @remote def files_to_deploy(c): with c.conn.cd(c.conn.project_root): @@ -396,7 +395,7 @@ def get_local_modifications_count(): @task @remote -def generate_changelog(c, ignorecheck="n", initialize="n", **kwargs): +def generate_changelog(c, ignorecheck=False, initialize=False, **kwargs): local_modification_count = get_local_modifications_count() check_ignored = ignorecheck.lower() in ("y", "yes") initialize = initialize.lower() in ("y", "yes") @@ -411,7 +410,6 @@ def generate_changelog(c, ignorecheck="n", initialize="n", **kwargs): "generate_changelog", **{ "jira-prefix": jira_prefix, - "environment": c.config.environment, "git-path": local_project_root, "initialize": initialize }, @@ -546,11 +544,6 @@ def import_db(c, dump_file=None, with_media=False): def jira_release(c, command, **kwargs): full_kwargs = dict() - if c.config["environment"] == "prod": - command = "comment_and_close_issues_to_deploy" - else: - command = "comment_after_deploy" - if "remote-version" not in kwargs and "to-deploy-version" not in kwargs: with c.conn.cd(c.conn.project_root): remote_version = c.conn.git("rev-parse last_master", hide=True).stdout.strip() @@ -632,7 +625,7 @@ def deploy(c, noconfirm=False): ).lower() not in ("y", "yes"): return - if "CHANGELOG.md" not in files_to_deploy(): + if "CHANGELOG.md" not in files_to_deploy(c): if input( "Warning ! It seems that the CHANGELOG file was not updated for this deployment. " "Do you want to proceed ? [y/N] "