Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new version email #65

Merged
merged 21 commits into from
Feb 15, 2024
Merged
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
Empty file.
16 changes: 16 additions & 0 deletions .github/scripts/python/notify-new-contribution-agreement/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "==2.31.0"

[dev-packages]
black = "==23.1.0"
pytest = "==7.2.1"
mypy = "==1.6.1"
pylint = "==3.0.2"

[requires]
python_version = "3.11"
342 changes: 342 additions & 0 deletions .github/scripts/python/notify-new-contribution-agreement/Pipfile.lock

Large diffs are not rendered by default.

215 changes: 215 additions & 0 deletions .github/scripts/python/notify-new-contribution-agreement/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
"""
© Ocado Group
Created on 10/01/2024 at 17:16:57(+00:00).

Notify all contributors that a new version of the contribution agreement has
been released.
"""

import os
import re
import subprocess
import typing as t
from email.utils import parseaddr

import requests

Contributors = t.Set[str]

CONTRIBUTING_FILE_NAME = "CONTRIBUTING.md"
AGREEMENT_END_LINE = "## Become a Contributor"
CONTRIBUTORS_HEADER = "### 👨\u200d💻 Contributors 👩\u200d💻"
CAMPAIGN_ID = 1512393


def get_previous_agreement_end_line_index():
"""Get the index of the previous agreement's end line.

Returns:
The index of the previous agreement's end line.
"""

# Get previous agreement.
previous_contributing = subprocess.run(
[
"git",
"--no-pager",
"show",
f"HEAD~1:{CONTRIBUTING_FILE_NAME}",
],
check=True,
stdout=subprocess.PIPE,
).stdout.decode("utf-8")

print(previous_contributing)

# Get index of line where previous agreement ended.
# NOTE: +1 to convert 0 based indexing to 1.
return previous_contributing.splitlines().index(AGREEMENT_END_LINE) + 1


def agreement_is_different():
"""Checks that the contributor agreement is different.

Returns:
A flag designating if the contributor agreement is different.
"""

# Get diff file names.
diff_output = subprocess.run(
[
"git",
"--no-pager",
"diff",
"--name-only",
"HEAD~1",
],
check=True,
stdout=subprocess.PIPE,
).stdout.decode("utf-8")

print(diff_output)

# Check if the contributing file is different.
if all(file != CONTRIBUTING_FILE_NAME for file in diff_output.splitlines()):
print(f"{CONTRIBUTING_FILE_NAME} is not different.")
return False

previous_agreement_end_line_index = get_previous_agreement_end_line_index()

# Get diff between current and previous contributing file.
diff_output = subprocess.run(
[
"git",
"--no-pager",
"diff",
f"HEAD~1:{CONTRIBUTING_FILE_NAME}",
CONTRIBUTING_FILE_NAME,
],
check=True,
stdout=subprocess.PIPE,
).stdout.decode("utf-8")

print(diff_output)

# Split diffs following git's diff format.
# NOTE: We're capturing the index of the diff's start line.
# NOTE: [1:] because we don't need the diff context info.
diffs = re.split(
r"^\@\@ -(\d+),\d+ \+\d+,\d+ \@\@.*$\n",
diff_output,
flags=re.MULTILINE,
)[1:]

# Parse the split diff-data.
for diff_start_line_index, diff in zip(
[int(diff_start_line_index) for diff_start_line_index in diffs[::2]],
diffs[1::2],
):
# Only want to know which lines were removed or edited.
diff_lines = [line for line in diff.splitlines() if not line.startswith("+")]

try:
# Get index of first line that was removed or edited in previous file.
diff_line_index = next(
diff_start_line_index + diff_line_index
for diff_line_index, diff_line in enumerate(diff_lines)
if diff_line.startswith("-")
)

# Check if line came before the end of the agreement.
if diff_line_index < previous_agreement_end_line_index:
return True

except StopIteration:
pass

print("All differences are after the end of the agreement.")
return False


def get_inputs():
"""Get script's inputs.

Returns:
The auth header used when making requests to DotDigital's API.
"""

auth = os.environ["AUTH"]

return auth


def get_contributors() -> Contributors:
"""Gets the contributors' email addresses.

Returns:
A set of the contributors' email addresses.
"""

with open(
f"../../../../{CONTRIBUTING_FILE_NAME}",
"r",
encoding="utf-8",
) as contributing:
lines = contributing.read().splitlines()

# NOTE: +2 because we don't want the header or the space after it.
return {
parseaddr(contributor)[1]
for contributor in lines[lines.index(CONTRIBUTORS_HEADER) + 2 :]
}


def send_emails(auth: str, contributors: Contributors):
"""Send an email to all contributors that a new version of the contribution
agreement has been released.

Args:
auth: The auth header used when making requests to DotDigital's API.
contributors: The email addresses to send the email to.
"""

failed_sends = False

for contributor in contributors:
try:
response = requests.post(
url="https://r1-api.dotdigital.com/v2/email/triggered-campaign",
headers={
"accept": "text/plain",
"authorization": auth,
},
json={
"campaignId": CAMPAIGN_ID,
"toAddresses": [contributor],
},
timeout=30,
)

assert response.ok, response.json()

print(f"✅ Sent email to {contributor}.")

# pylint: disable-next=broad-exception-caught
except Exception as ex:
print(f'❌ Failed to send email to {contributor} due to exception: "{ex}".')

failed_sends = True

assert not failed_sends, "Failed to send emails to some contributors."


def main():
"""Entry point."""

if agreement_is_different():
auth = get_inputs()

contributors = get_contributors()

send_emails(auth, contributors)


if __name__ == "__main__":
main()
33 changes: 33 additions & 0 deletions .github/workflows/notify-new-contribution-agreement.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Notify New Contribution Agreement

on:
push:
branches:
- main
paths:
- CONTRIBUTING.md

jobs:
run-script:
runs-on: ubuntu-latest
env:
PYTHON_VERSION: 3.11
WORKING_DIR: .github/scripts/python/notify-new-contribution-agreement
steps:
- name: 🛫 Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2 # get current and previous commit

- name: 🐍 Set up Python ${{ env.PYTHON_VERSION }} Environment
uses: ocadotechnology/codeforlife-workspace/.github/actions/python/setup-environment@main
with:
checkout: 'false'
python-version: ${{ env.PYTHON_VERSION }}
working-directory: ${{ env.WORKING_DIR }}

- name: 🏃 Run Script
working-directory: ${{ env.WORKING_DIR }}
run: pipenv run python .
env:
AUTH: ${{ secrets.DOTDIGITAL_API_USER_AUTH }}
18 changes: 11 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,13 @@ To sign, you must:
how to do this on GitHub. Note that you only need to fork the **main**
branch.

1. On the **main** branch of your forked repo, create a new line at the *bottom*
of this file (press **Enter**). Note that you must not make any other edits.
1. On the **main** branch of your forked repo, write your email address on a new
line at the *bottom* of this file. Note that you must not make any other
edits.

1. Write your email address on the second last line.
```md
<[email protected]>
```

1. Commit your changes.

Expand All @@ -167,12 +170,13 @@ To sign, you must:
how to do this on GitHub.

1. To affirm that you own the email address you provided, an email will be sent
to the email address. The email will contain a link to the commit that added
the email address as a contributor. You must respond to the email from the
same email address stating:
to the email address after your pull request has been reviewed and approved by
a member of our team. The email will contain a link to the pull request that
added the email address as a contributor. You must forward the email to
<[email protected]> from the same email address and state:

```txt
I confirm that I made this commit and I agree to being a contributor to the Code for Life project under the terms found in my commit.
I confirm that I created this pull request and I agree to being a contributor to the Code for Life project.
```

Your email address is now approved to make contributions! 🥳
Expand Down
Loading