Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions {{cookiecutter.project_slug}}/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <environment> 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 <environment> deploy
```

Where _<environment>_ 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 <environment> bootstrap` has already been run before the first ever deployment.
102 changes: 86 additions & 16 deletions {{cookiecutter.project_slug}}/fabfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,27 @@ def outgoing_commits(c):
print_commits(get_outgoing_commits(c))


@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(
[
Expand All @@ -372,6 +393,29 @@ def get_local_modifications_count():
)


@task
@remote
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")
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,
"git-path": local_project_root,
"initialize": initialize
},
)


@task
@remote
def log(c):
Expand Down Expand Up @@ -497,6 +541,33 @@ def import_db(c, dump_file=None, with_media=False):
import_media(c)


def jira_release(c, command, **kwargs):
full_kwargs = dict()

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):
Expand All @@ -505,22 +576,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,
},
)


Expand Down Expand Up @@ -562,6 +625,13 @@ def deploy(c, noconfirm=False):
).lower() not in ("y", "yes"):
return

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] "
).lower() not in ("y", "yes"):
return

_init_last_master(c)
compile_assets()
push_code_update(c, "HEAD")
Expand Down
1 change: 1 addition & 0 deletions {{cookiecutter.project_slug}}/requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
"easy_thumbnails",
"django.contrib.sites",
{% endif -%}
"changelogmd",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
Expand Down Expand Up @@ -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")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also expose a changelog view in the project template ? Or do you think that this is a project-specific decision ?