From 3d4151188044ab5676766d8694271a0aaa4fd7eb Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Sun, 21 Sep 2025 09:12:03 +0100 Subject: [PATCH 1/9] xlsx file should include num_mentees column data --- tools/samples/mentors.xlsx | Bin 10673 -> 12599 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/samples/mentors.xlsx b/tools/samples/mentors.xlsx index 87917e99cf84fb0d15081cacd0dbbe4fdc5a319b..02bc2ff3d74ea7eb8d166f312f79f7d7b13005d6 100644 GIT binary patch literal 12599 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 From e7a60581a7df9601dd2583aad0ece7e5e64f1efa Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Sun, 21 Sep 2025 09:14:31 +0100 Subject: [PATCH 2/9] ensure new mentors use the correct sort depending on the cycle timeline --- .../{automation.py => automation_mentors.py} | 88 +++++++++++++------ ...tomation.bat => run_mentor_automation.bat} | 7 +- ...automation.sh => run_mentor_automation.sh} | 7 +- tools/tests/automation_functional_test.py | 4 +- tools/tests/mentorship_type_test.py | 2 +- 5 files changed, 74 insertions(+), 34 deletions(-) rename tools/{automation.py => automation_mentors.py} (83%) rename tools/{run_automation.bat => run_mentor_automation.bat} (62%) rename tools/{run_automation.sh => run_mentor_automation.sh} (58%) diff --git a/tools/automation.py b/tools/automation_mentors.py similarity index 83% rename from tools/automation.py rename to tools/automation_mentors.py index 63dd549a..8a2fa778 100644 --- a/tools/automation.py +++ b/tools/automation_mentors.py @@ -9,6 +9,7 @@ import textwrap from enum import Enum +import numpy as np import pandas as pd from ruamel.yaml import YAML from ruamel.yaml.scalarstring import LiteralScalarString @@ -37,6 +38,10 @@ IMAGE_FILE_PATH = "assets/images/mentors" IMAGE_SUFFIX = ".jpeg" +# Mentorship cycle periods +LONG_TERM_REG_PERIOD = "long-term" # long-term registrations period only +DEFAULT_PERIOD = "default" # rest of the cycle, ad-hoc periods + class WriteMode(Enum): # Create new a file @@ -130,23 +135,39 @@ def get_multiline_string(long_text_arg): multiline_str = LiteralScalarString(textwrap.dedent(long_text_arg)) return multiline_str -def get_sort(mentorship_type, num_mentee): +def is_available_for_long_term(mentorship_type): + return mentorship_type == type_long_term[0] or mentorship_type == TYPE_BOTH + +def is_available_for_ad_hoc(mentorship_type): + return mentorship_type == type_ad_hoc[0] or mentorship_type == TYPE_BOTH + +def sort_for_long_term_reg(num_mentee): + """ + Return sort value for mentors available for long-term, based on number of mentees they can take. + Applies only during long-term registration period. + if no mentees, sort to 10; if num_mentees is 1, sort to 100; 2, sort to 200; if >2, sort to highest 500 + """ + + mentee_sort_map = { + 0: 10, + 1: 100, + 2: 200 + } + return mentee_sort_map.get(num_mentee, 500) + + +def get_sort(mentorship_type, num_mentee, current_period): """ Get mentor's sort value + Rules: https://docs.google.com/document/d/1GwlleBNScHCQ3K8rgvYIB3upIr1BylgWjGR2jxwYWtI/edit?usp=sharing """ - if mentorship_type == TYPE_BOTH or mentorship_type == type_long_term[0]: - if num_mentee > 2: - return 600 - if num_mentee == 2: - return 550 - if num_mentee == 1: - return 500 - return 200 - if mentorship_type == type_ad_hoc[0]: - #todo: (if availability == next month) then adjust the sort value: + if current_period == LONG_TERM_REG_PERIOD and is_available_for_long_term(mentorship_type): + sort_for_long_term_reg(num_mentee) + + if current_period == DEFAULT_PERIOD and is_available_for_ad_hoc(mentorship_type): return 100 - + return 10 def get_mentorship_type(mentorship_type_str): @@ -237,13 +258,24 @@ def read_yml_file(file_path): return yml_dict +def get_num_mentee_from_row(mentor_row, default): + """ + Extract num_mentee from mentor_row, or use default if invalid. + """ + val = mentor_row.iloc[44] + + return ( + int(val) if pd.notna(val) and isinstance(val, (int, np.integer)) + else default + ) def xlsx_to_yaml_parser(mentor_row, mentor_index, + current_period, mentor_disabled=False, mentor_sort=0, mentor_matched=False, - num_mentee=1): + num_mentee=0): """ Prepare mentor's excel data for yaml format """ @@ -259,7 +291,9 @@ def xlsx_to_yaml_parser(mentor_row, mentor_type = get_mentorship_type(mentor_row.iloc[4]) if mentor_sort == 0: - mentor_sort = get_sort(mentor_type, num_mentee) + num_mentee = get_num_mentee_from_row(mentor_row, num_mentee) + + mentor_sort = get_sort(mentor_type, num_mentee, current_period) if not pd.isna(mentor_row.iloc[9]): mentor_position = f"{mentor_row.iloc[8].strip()}, {mentor_row.iloc[9].strip()}" @@ -329,7 +363,7 @@ def get_yml_data(yml_file_path): return df_yml_data -def get_all_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=0): +def get_all_mentors_in_yml_format(yml_file_path, xlsx_file_path, current_period, skip_rows=0): """ Read all mentors from Excel sheet: - if mentor is in current mentors.yml, use existing values for index, disabled, sort, matched and num_mentee. @@ -356,6 +390,7 @@ def get_all_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=0): if not df_yml_row.empty: mentor = xlsx_to_yaml_parser(df_mentors.iloc[row], df_yml_row['Index'].item(), + current_period, df_yml_row['Disabled'].item(), df_yml_row['Sort'].item(), df_yml_row['Matched'].item(), @@ -363,7 +398,8 @@ def get_all_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=0): logging.info(f"For {mentor_name} use index, disabled and sort from mentors.yml file") else: mentor = xlsx_to_yaml_parser(df_mentors.iloc[row], - new_index) + new_index, + current_period) new_index += 1 mentors.append(mentor) @@ -372,7 +408,7 @@ def get_all_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=0): return mentors -def get_new_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=1): +def get_new_mentors_in_yml_format(yml_file_path, xlsx_file_path, current_period, skip_rows=1): """ Read just new mentors from Excel sheet: - start reading xlsx Mentors from the row 1 (from the date 03/04/2024) @@ -397,7 +433,7 @@ def get_new_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=1): mentor_name = df_mentors.iloc[row].values[2].strip().lower() if df_yml.loc[df_yml.Name == mentor_name].empty: - mentor = xlsx_to_yaml_parser(df_mentors.iloc[row], new_index) + mentor = xlsx_to_yaml_parser(df_mentors.iloc[row], new_index, current_period) new_index += 1 mentors.append(mentor) @@ -411,25 +447,27 @@ def get_new_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=1): def run_automation(): logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - if len(sys.argv) == 5: + if len(sys.argv) == 6: xlsx_file_path = sys.argv[1] yml_file_path = sys.argv[2] - mode = WriteMode(sys.argv[3]) - skip_rows = int(sys.argv[4]) + current_period = sys.argv[3] + mode = WriteMode(sys.argv[4]) + skip_rows = int(sys.argv[5]) - logging.info("Params: xlsx: %s yml: %s mode: %s skip_rows: %s", xlsx_file_path, yml_file_path, mode, skip_rows) + logging.info("Params: xlsx: %s yml: %s current_period: %s mode: %s skip_rows: %s", xlsx_file_path, yml_file_path, current_period, mode, skip_rows) else: xlsx_file_path = "samples/mentors.xlsx" yml_file_path = "samples/mentors.yml" + current_period = "default" mode = WriteMode.APPEND skip_rows = 0 - logging.info("Default values: xlsx: %s yml:: %s mode: %s", xlsx_file_path, yml_file_path, mode) + logging.info("Default values: xlsx: %s yml:: %s current_period: %s mode: %s", xlsx_file_path, yml_file_path, current_period, mode) if mode == WriteMode.APPEND: logging.info("Appending option selected.") - list_of_mentors = get_new_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=skip_rows) + list_of_mentors = get_new_mentors_in_yml_format(yml_file_path, xlsx_file_path, current_period, skip_rows=skip_rows) logging.info("New Mentors size: %d", len(list_of_mentors)) @@ -439,7 +477,7 @@ def run_automation(): elif mode == WriteMode.WRITE: logging.info("Recreate yml - Write option selected.") - list_of_mentors = get_all_mentors_in_yml_format(yml_file_path, xlsx_file_path, skip_rows=skip_rows) + list_of_mentors = get_all_mentors_in_yml_format(yml_file_path, xlsx_file_path, current_period, skip_rows=skip_rows) write_yml_file(yml_file_path, list_of_mentors, WriteMode.WRITE) diff --git a/tools/run_automation.bat b/tools/run_mentor_automation.bat similarity index 62% rename from tools/run_automation.bat rename to tools/run_mentor_automation.bat index 586bbd30..ec5d247a 100644 --- a/tools/run_automation.bat +++ b/tools/run_mentor_automation.bat @@ -10,10 +10,11 @@ echo Installing dependencies... pip install -r requirements.txt setlocal -echo Enter arguments for Python script: FILE_PATH_MENTORS_XLSX FILE_PATH_MENTORS_YML MODE SKIP_ROWS -echo Example: mentors_test.xlsx mentors_test.yml a 1 +echo Enter arguments for Python script: FILE_PATH_MENTORS_XLSX FILE_PATH_MENTORS_YML CURRENT_PERIOD MODE SKIP_ROWS +echo Example: mentors_test.xlsx mentors_test.yml default a 1 +echo CURRENT_PERIOD: use 'default' or 'long-term' ('long-term' if during long-term registration period) echo MODE: a - to append new mentors from the xlsx table to mentors.yml echo MODE: w - to create a new mentors.yml file with all mentors that are in the xlsx table echo SKIP_ROWS: To start XLSX in the line 1 -python automation.py samples/mentors.xlsx samples/mentors.yml a 1 +python automation_mentors.py samples/mentors.xlsx samples/mentors.yml default a 1 @echo on \ No newline at end of file diff --git a/tools/run_automation.sh b/tools/run_mentor_automation.sh similarity index 58% rename from tools/run_automation.sh rename to tools/run_mentor_automation.sh index baf613e1..50785640 100644 --- a/tools/run_automation.sh +++ b/tools/run_mentor_automation.sh @@ -7,8 +7,9 @@ source myenv/bin/activate # Install packages pip install -r requirements.txt -# Enter the parameters: FILE_PATH_MENTORS_XLSX FILE_PATH_MENTORS_YML MODE SKIP_ROWS -# Example: samples/mentors.xlsx samples/mentors.yml a +# Enter the parameters: FILE_PATH_MENTORS_XLSX FILE_PATH_MENTORS_YML CURRENT_PERIOD MODE SKIP_ROWS +# Example: samples/mentors.xlsx samples/mentors.yml default a 0 # mode "a" for APPEND new mentors from the xlsx table to the existing mentors.yml # mode "w" for WRITE all mentors from the xlsx table to mentors.yml -python3 automation.py samples/mentors.xlsx ../_data/mentors.yml a 1 \ No newline at end of file +# CURRENT_PERIOD: use "default" or "long-term" ("long-term" if during long-term registration period) +python3 automation_mentors.py samples/mentors.xlsx ../_data/mentors.yml default a 0 \ No newline at end of file diff --git a/tools/tests/automation_functional_test.py b/tools/tests/automation_functional_test.py index 12bc585b..321a3271 100644 --- a/tools/tests/automation_functional_test.py +++ b/tools/tests/automation_functional_test.py @@ -3,7 +3,7 @@ import sys import pytest from file_utils import TOOLS_PATH -from automation import run_automation, read_yml_file, WriteMode +from automation_mentors import run_automation, read_yml_file, WriteMode MENTOR_2 = "Mentor2 Name" MENTOR_3 = "Mentor3 Name" @@ -13,7 +13,7 @@ def test_write_mentors_skip_zero_rows(monkeypatch): with tempfile.NamedTemporaryFile(suffix='yml', delete=False) as tmpfile: tmp_filename = tmpfile.name - test_args = ['automation.py', os.path.join(TOOLS_PATH, "samples", "mentors.xlsx"), tmp_filename, WriteMode.WRITE, '0'] + test_args = ['automation_mentors.py', os.path.join(TOOLS_PATH, "samples", "mentors.xlsx"), tmp_filename, "default", WriteMode.WRITE, '0'] monkeypatch.setattr(sys, 'argv', test_args) run_automation() diff --git a/tools/tests/mentorship_type_test.py b/tools/tests/mentorship_type_test.py index 7aa84c49..ef6a8ac8 100644 --- a/tools/tests/mentorship_type_test.py +++ b/tools/tests/mentorship_type_test.py @@ -1,5 +1,5 @@ import unittest -from automation import get_mentorship_type, type_ad_hoc, type_long_term, TYPE_BOTH +from automation_mentors import get_mentorship_type, type_ad_hoc, type_long_term, TYPE_BOTH class TestMentorAutomation(unittest.TestCase): AD_HOC_1 = "Ad-Hoc Format" From 76fb565385397e72bf9ef3db1b31e064b3dd1d07 Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Sun, 21 Sep 2025 09:21:47 +0100 Subject: [PATCH 3/9] update download image script + remove TODO that could cause errors if forgotten --- tools/automation_mentors.py | 2 +- tools/download_image.py | 4 ++-- tools/run_download_automation.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/automation_mentors.py b/tools/automation_mentors.py index 8a2fa778..cc3bc6c1 100644 --- a/tools/automation_mentors.py +++ b/tools/automation_mentors.py @@ -286,7 +286,7 @@ def xlsx_to_yaml_parser(mentor_row, # Left commented since the code might be used in the later versions # to add default picture until the mentor's image is not available # mentor_image = os.path.join(IMAGE_FILE_PATH, str(mentor_index) + IMAGE_SUFFIX) - mentor_image = f"{IMAGE_FILE_PATH}/{mentor_row.iloc[2].strip().lower().replace(' ', '_')}{IMAGE_SUFFIX} # TODO: Run download_image script to actually download the image" + mentor_image = f"{IMAGE_FILE_PATH}/{mentor_row.iloc[2].strip().lower().replace(' ', '_')}{IMAGE_SUFFIX}" mentor_type = get_mentorship_type(mentor_row.iloc[4]) diff --git a/tools/download_image.py b/tools/download_image.py index 71b2374a..d8c94a64 100644 --- a/tools/download_image.py +++ b/tools/download_image.py @@ -32,8 +32,8 @@ def download_image(url, mentor_name): def run_automation(): if len(sys.argv) == 3: - url = sys.argv[1] - mentor_name = sys.argv[2] + mentor_name = sys.argv[1] + url = sys.argv[2] image_path = download_image(url, mentor_name) if image_path: print(f"Image saved to {image_path}") diff --git a/tools/run_download_automation.sh b/tools/run_download_automation.sh index 36502860..c04001a0 100644 --- a/tools/run_download_automation.sh +++ b/tools/run_download_automation.sh @@ -8,4 +8,4 @@ source myenv/bin/activate pip install -r requirements.txt # Enter the parameters: IMAGE_URL MENTOR_NAME -python3 download_image.py "https://media.licdn.com/dms/image/v2/D4E03AQFLzC76FGXhiQ/profile-displayphoto-shrink_400_400/profile-displayphoto-shrink_400_400/0/1711114395505?e=1729728000&v=beta&t=P3FN1bSt0aMtt42YyJfiZCRxSqOPllf8U7O9jr2Ki_U" "Samuela Smolorz" \ No newline at end of file +python3 download_image.py "Mentor Name" "image_url_here" \ No newline at end of file From 74698209a31e4acad7ecfb506c475dcdd42678f6 Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Sun, 21 Sep 2025 09:22:42 +0100 Subject: [PATCH 4/9] update README with important details on running each script --- tools/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/README.md b/tools/README.md index c3d83541..9c2c5857 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1,7 +1,6 @@ ## How to Run Python Scripts -There are two automation scripts: -1) `automation.py`: appends new mentors in `samples/mentors.xslx` to `_data/mentor.yml` +1) `automation_mentors.py`: appends new mentors in `samples/mentors.xslx` to `_data/mentor.yml` (or updates all existing mentors if using WRITE mode) 2) `download_image.py`: downloads image from a specified URL and saves in `assets/images/mentors` @@ -17,15 +16,18 @@ python 3.11 or above ### How to Execute on Mac -#### A) `automation.py` +#### A) `automation_mentors.py` ```shell -sh run_automation.sh +sh run_mentor_automation.sh ``` **Note:** - Ensure to update `mentors.xslx` with the new spreadsheet containing the mentors to be added, **OR** -- adjust the `FILE_PATH_MENTORS_XLSX` parameter in [the script](run_automation.sh) to match the file path for the new spreadsheet. +- adjust the `FILE_PATH_MENTORS_XLSX` parameter in [the script](run_mentor_automation.sh) to match the file path for the new spreadsheet. +- adjust the `CURRENT_PERIOD` parameter in [the script](run_mentor_automation.sh) if running during long-term registration period (use "long-term") +- After running the script, you **HAVE** to run the [run_download_automation script](run_download_automation.sh) to download images for each new mentor. Else, the image links will be broken as they do not exist yet. +- If using the script to update all mentors, update `run_mentor_automation.sh` to use WRITE mode #### B) `download_image.py` From 6836b0264a2699d95cfb1c6b2338457483da5433 Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Sun, 28 Sep 2025 10:04:25 +0100 Subject: [PATCH 5/9] update download_image script to use excel file and download images for all rows + readme update --- tools/README.md | 15 ++++++----- tools/download_image.py | 42 ++++++++++++++++++++++--------- tools/run_download_automation.sh | 5 ++-- tools/samples/mentors.xlsx | Bin 12599 -> 13670 bytes 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/tools/README.md b/tools/README.md index 9c2c5857..25fd7e9e 100644 --- a/tools/README.md +++ b/tools/README.md @@ -2,7 +2,7 @@ 1) `automation_mentors.py`: appends new mentors in `samples/mentors.xslx` to `_data/mentor.yml` (or updates all existing mentors if using WRITE mode) -2) `download_image.py`: downloads image from a specified URL and saves in `assets/images/mentors` +2) `download_image.py`: downloads image for each mentor from a specified URL and saves in `assets/images/mentors`. It uses data from `samples/mentors.xlsx` sheetname `Mentors Images`. 3) `meetup_import.py`: imports new upcoming events from the WCC MeetUp page using the iCal feed: https://www.meetup.com/women-coding-community/events/ical/ @@ -22,18 +22,17 @@ python 3.11 or above sh run_mentor_automation.sh ``` **Note:** -- Ensure to update `mentors.xslx` with the new spreadsheet containing the mentors to be added, **OR** -- adjust the `FILE_PATH_MENTORS_XLSX` parameter in [the script](run_mentor_automation.sh) to match the file path for the new spreadsheet. -- adjust the `CURRENT_PERIOD` parameter in [the script](run_mentor_automation.sh) if running during long-term registration period (use "long-term") +- Ensure to update `mentors.xslx` sheetname `WCC All Approved Mentors` with new data containing the mentors to be added, **OR** +- If using another file source, adjust the `FILE_PATH_MENTORS_XLSX` parameter in [the script](run_mentor_automation.sh) to match the file path. +- If running this script during long-term registration period, adjust the `CURRENT_PERIOD` parameter in [the script](run_mentor_automation.sh) to "long-term" -- After running the script, you **HAVE** to run the [run_download_automation script](run_download_automation.sh) to download images for each new mentor. Else, the image links will be broken as they do not exist yet. +- After running the script, you **HAVE** to run the [run_download_automation script](run_download_automation.sh) to download images for the new mentors. Else, the image links will be broken as they do not exist yet. - If using the script to update all mentors, update `run_mentor_automation.sh` to use WRITE mode #### B) `download_image.py` -**Before running the script, make sure** to update the `IMAGE_URL` and `MENTOR_NAME` parameters in the [run_download_automation script](run_download_automation.sh) with: -- the URL you want to download the mentor's image from, **AND** -- the mentor's name as it appears in the spreadsheet e.g 'Adriana Zencke' +**Before running the script, make sure** to update `mentors.xslx` sheetname `Mentors Images` with the data for the new mentors that you want to download their images +If you want to use another file source, adjust `XLSX_FILE_PATH` parameter in the [script](run_download_automation.sh) to match the file path. You can then run: ```shell diff --git a/tools/download_image.py b/tools/download_image.py index d8c94a64..b2fb718d 100644 --- a/tools/download_image.py +++ b/tools/download_image.py @@ -2,10 +2,12 @@ import sys import requests import logging +import pandas as pd logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') IMAGE_FILE_PATH='../assets/images/mentors' +SHEET_NAME = "Mentors Images" def download_image(url, mentor_name): """ @@ -17,31 +19,47 @@ def download_image(url, mentor_name): os.makedirs(IMAGE_FILE_PATH, exist_ok=True) - response = requests.get(url, stream=True) + response = requests.get(url, stream=True, timeout=10) response.raise_for_status() with open(image_path, 'wb') as out_file: out_file.write(response.content) - logging.info(f"Image for {mentor_name} downloaded successfully to {image_path}") return image_path except requests.exceptions.RequestException as e: - logging.error(f"Failed to download image from {url}: {e}") + logging.error(f"Failed to download image for {mentor_name}: {e}") return None def run_automation(): - if len(sys.argv) == 3: - mentor_name = sys.argv[1] - url = sys.argv[2] - image_path = download_image(url, mentor_name) - if image_path: - print(f"Image saved to {image_path}") - else: - print("Failed to download the image.") + if len(sys.argv) == 2: + xlsx_file_path = sys.argv[1] + success_count = 0 + + try: + df_mentors = pd.read_excel(xlsx_file_path, sheet_name=SHEET_NAME) + df_mentors.columns = [col.strip() for col in df_mentors.columns] + except Exception as e: + logging.error(f"Failed to read Excel file {xlsx_file_path}: {e}") + return + + for _, row in df_mentors.iterrows(): + mentor_name = str(row["Mentor Name"]).strip() + url = str(row["Image Download URL"]).strip() + + if pd.isna(mentor_name) or pd.isna(url) or url == "": + logging.warning(f"Skipping download for row with missing data: {row} \n This needs to be fixed manually") + continue + + image_path = download_image(url, mentor_name) + if image_path: + success_count += 1 + + logging.info(f"Successfully downloaded {success_count} images.") + logging.info("Image download process completed.") else: - logging.info(f"Add parameters for download") + logging.info(f"Script needs 1 parameter (xlsx_file_path) to run") if __name__ == "__main__": diff --git a/tools/run_download_automation.sh b/tools/run_download_automation.sh index c04001a0..a1849e5d 100644 --- a/tools/run_download_automation.sh +++ b/tools/run_download_automation.sh @@ -7,5 +7,6 @@ source myenv/bin/activate # Install packages pip install -r requirements.txt -# Enter the parameters: IMAGE_URL MENTOR_NAME -python3 download_image.py "Mentor Name" "image_url_here" \ No newline at end of file +# Enter the parameters: XLSX_FILE_PATH +# Example: samples/mentors.xlsx (should contain two sheets: "WCC All Approved Mentors" and "Mentors Images") +python3 download_image.py samples/mentors.xlsx \ No newline at end of file diff --git a/tools/samples/mentors.xlsx b/tools/samples/mentors.xlsx index 02bc2ff3d74ea7eb8d166f312f79f7d7b13005d6..be49a536b25117217107a65dfed13c9b57786bab 100644 GIT binary patch delta 7906 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 delta 7111 zcmZvBbyO5yxAxFoGK9d;NOy-c(jC$b0!kwxF)+Z;IVecu5K@wZbPNqLG)RMlAgLf7 zm-oGEeZTL%_nyDb+Iycr_CC*9XYc3Par+}S7nUq^a_xwT&UeDZSiU>*URII9zq76aOul-_rV4#94zu(T_5t}Zb%i2DBQ&B zo{TRC3;iB*srPVig2WEA84xB!40Rh@(~9%=4<4{}Q9VufF*iFd1k%b2KDDt)a?Sx{ zd4KIS5K-Px(5Rwup`erv-^^PaG$C6XXd$csn}3!ZTIyNXF&eZJm9s{@ z>dWKLD$EB`UvqbbScbgo;z&+7)4OgJqj0g|waAx`V1i722k5;{Xr!zb@)!^8lcRu} zYmJ^D8CP!DHpuDv)@U7D^HWkCb*P!$dDcq?^Obca#knA1WkbWw65YCo4s;Y zm@1bKz;m*_*3)i9(&26<*3g*4^`SlK;Dd>6i^!wjANIgP_t*`Y7?K$H5waPXr;mki zMQ>Qd=0F2i8E9+v36ORW+{Xw69~keG;0`x(ENn^($jG zr}Oqhi_+3Lb^#=aVe<4Tp1KTC5MXk5hKc*KN97#%Py4O2b`a`y5B!>No32umzC!eQ z2-J@;W=NF*%$e@H{pn+y@$rVA;>`$W*U}%J(X(Uct>MAhwa2_49xwp^9{|CR2wYtW zoXA5504T5l0FuX$z&HE>o<6VbJw0FZ1-ic}HnQ?u6aa=6G(Ol~J%6jn^coJ0*Clez zn`mlEdGAeF=XLPSKfK}>cR7;iZl5R z#{;z7WsX05Ota5y{z1-lLz+!6eWq3Y8Qr+SEsPXYaHou zBFu@K2)|{HUzcj!I40mF!-uMBw*&nzJ$<`W4;Fa68wcUhg>=-Mn!89;`KZ2=WBhP+ z^ffL8bjR`A;o@HUa>@(GQEG2D{%L%F>d`9M?;XBQJH`{u3JW+%LXu0tK5PT0wl|(Beu1xynS}u%Ddf6pcN+fEe$=a$#hn$tanm%`c+$Di`xYo3oky6gf@aRr%3L ze`SU;R)2U0`)U|$S^$_@-MwpAAeg}?CP=Whp2qJnKa@WQbu56ptZ7Y9v4@#e6r9D4}J5Hk}o`2^wPk7%CSNfAW{OjC^ z5=9G(PvG)a;`aiXlrV43@_BcKhPHofOP*>Rabe>6(EO@&dFk&UNhLhB#%(;yA5dfv z*EZj3ech>XQB^!bE()$(*XDCn7ro^U=&WFae|*bDAcqerw=uA8Awn7u_mBpm49^*- zl!m!h!qrUlh;C=|=kX^;{BSMRxA%)W)m6+e`aV!u7Vv)F&)ECp`Vvq5D^_19zC*SY zJ6;#rEm`}(QCC~}Ryj~(YZ1e-YvWe-HoEJ?b&;tf1x%_%eFIMK@HXtG=W0zhkl3sJ zM4xDhCwADa)w=bkyP@w6)F>xj3*8|*BMG?}w5qAn5%cMIf@5_O?_LZiW&<9C4B~rh zEqDK&=kAjJ;H?)m3}G?LZ!SP?ublSL)vJRe9{>A7;xH4UOapOapJE#-mT+>6UFdd&zfAz^qcn zLMM?J0VU(5!QZwmO3xf}n$8Ltg@>y8U#Bw0P~y!|x=MYga&!*0a}Vupq0-s3bwj69 zWAsq4?bowU@pGk#MZYlPs%0MOV|6T)?t8Oh*RM8&8<3j#HU^PmCnZECaK(#THSc9w z$Xa;5%K%P^WjYXXdRIp=d+7t^;BaUZfY}m~7#V*b<)SehC8cm8{HDB{#2d3WP%3;~ z0d-I&vr|ZlkolB=C(x)=S5HPg&k-5UoGp7;Vpog3s;fsmu)Dc?P4|kp9TXo+!_@JD zGGUT}dF6KRy`uA`ogRPj{HUW?rw%5T1L3#nSP}3hA#|4E`c1LZVli?MN0B>`wEM`0kC0 zI%>da`m2rj{p0uW@bK^Nqbh5`V^NPf$_DES%`_x2GnNsA^Q8WGAN1+-o(ha>qA~Oa zyl9IZe4n;x)RFLP(?RBbM-B%&;pbI|WHw(}Z_mXvU}-t~56entE*|vfdM1`IOAQi|*u@ zxv&eE2x1_XY8XkY0ohGJ;PZY5W~$%)z=>78q9BL;*zDxc{atYo&K#LIhGs#i$GmV5#NtY9XdjDwO|y~dYF#RY2ug6Loto{Xbv zL{!F6Uaem11yXTO7MGyphU3u+do*-%*>%`6_3x_?DUHlmG8=ST8wnOig@TP=ysT`8 z$98;%!xK9=is7jppNruc9ULX_td7qmo4G22pr1V1dlIkowFe~=Jfu)&8NxquRis%^ zW;2hQ%CHxR02*(Uu|n`$Qp2!7qsE2>#R)YI4o2V^5&kbMEO!Xx&zlT7;|PeoyaG`n z;2piF|Z8W+FxCo%k(M^oc7>Qn72w>#s#=>6@M+X+#3Q%d3Nyx4f>bE=j zLSq}i5{elFhuC+s8%)10tfo-8qd$1|pXq15%dQ#ouDuEgrnL)hkKN5qtJOmcA{ED0 zsVMDlzB{04=GUZqiwkz@jk6)Eo-CmLLUuAPs zelcsd+b~&%uKohq_>Lnn2vT@t;+9TkPD9efS%VAP?Uo39Zrb&YcAr&VpUiwI)P8N) zHr^InD7Ir&jBM)E`PLS@F19ny(w!7Uh1L?Q5bkC|Sv=4_NMPi!y4mx~KfkYi5W^-! zQK?eA`Q3?mnEH%AG2|A+UYDv3ekczkTcmxrFJUkiOj|OPj zBM9>G2ugza9zhU|IDz`P@^W^BbC+&rN7GVzm^C|Wfb*kqDCx}t?R$cMhsbmhErpF& zv6$+#{G|A{?>cr`j%=27GR!Z8Y-X^321srP@!Q5ku z467QWZ%1r2B5nh#9ZRN~9qP`&Eeiz;ksbg5 z{&%D3>tg5Q*q%l2J6(aL2BDFIgES#4_^60l7cf#aJTvtL8<1aYQD+Y7CAw zh(4;9+gRO2Zx*M)D^Osw=j_LAquieoU_?e4!krGxOH(}@t3iL~MPp==t(-5tcLy>w zHkmT`n0o->a)rEYe_kDh2jm%xS+a3UFB2{@mg zQN##t@F^U9AJsvt3u(kp)v@=;Nj+lrpvcHHl!6&dBh`oJA{X$4l<)#r*b(heGnL zTkWYxC;gy->c9^Oly~Lz#Bjega1HgnH~4iu*Rnur*h=cLpbjHw=5OmoF2v{m!2)*{ zc9e-Qxxb8^6r^W2s`%8`>u^1u@NiDz?^E!j;KB0uc-WWAy8`a}J^5P(bM%ve?i4yf zQf6!^%;SMd0M9`bT@G3I(xpR|S`ovFzny4%5<7)SH~4}7p$!az>I6PW5kCKY|CYLS z^KM_@Y?v|yP#jHe+;9CB79^?a>kMwzb!-pN_J?eBysjtbKemG9O#~fh6Uuzxyx_J; zAT*+z*y~~5+7I(`_m43qQ{II%?-Rv>|oBqKaQu9$vdsaGv%lJR{`YO~*_Je@64!9dkj=eVYA zjfqtXHM}hH!@C>7v0e0Q5ei(^AxYhHjNj~vny`IQZ})U@2`H2p!vwz?c@-{Uz< z3jLr_iOu2``1yB?mykm&9?YVr&`AL_Mt(kSrZsw{-C2rUD8*Jkw=GIrQEairXm)Nj zpCMta;&_%wWPAQGBS@=kUQxW9ZkPu^I@jL}Qj>iz>+425=c3@_`?S#WN3s=D#y8-C zFcn(bP2~KI``tBEP8*Rl@-dfxE^g=x&j=|UX?FIo<AwMk^p^MrO-zYpXTw_%|lRT*VtNFWbE_Rb08m&vMi_ji|T|R zzVY*d1G%n-9e2SZ2e1`!tKt`h;lmVq*>$N`gcjd4jC<0qV*ECDQNp?H?=IIjBKa-d zc^p*8L0>IUl$itKwYXgGo3fLsU}i=obhN+M!>ed?EpuvcN*28>sC_Xa#FuTgwi4&L zJhM)!H5m2(Y`PCdEU5|mW%!R8%>0$A$ZL;G0FF&c^x|R`^Pq$aaq< zf%*jOH+2NzgZJ)*J4vB2cQ(y80xG+IU(x-9T{O=%d{^G<(y~RYG29cf_rJe~UXHtq z-q>n;XoIIL3|+QI1+7Fq;u!8OUNzG+T1@n~a9izN8={ix2BkhUd`@`V>#LXx*-yZxJK<_v&&ui zDTEzHR)vehhs9fDYpn09?+unMg#0O-!r^%0@B zBhB6C6hC!5w#%)Ys&{NQ+Hr+dnDV1a+=y;0rXqnaO#I4J-5MUs zTNQe_-~e+1Z$r+!CGofJARB#51IH?gENt!-bJlaCi9pCr%fyUJ#mT795q>BSC2Aup z_ZKsCYI|v|>@1pA4D#X0HRn-f;njp_dE#tSEQl%%j>ves0(bCN%v~r{PZyx&M%%N3 zz0zdjGZl;*!@UjPFauLdQz>}i@CPwSz0?W^UxFN)FC*I=)zP$&M@_^PKXS)3EgDYJ zCM_YMOGlvMswxa3NbCrNtT-wnj2I2+M@zXxNsB?&QjOaUtr)O|H@*1Y=>3$fGX7ZB zKb4e9-2J&2zl6=f3{t}I$7pg>+`_V_>h4QMI9lC?=x@i#Dlgy*eKk&RZWVQ3YPv(P zSPE1AQ#>~xLZ#&uZq^C*m2s5JXh&z^gfj+J{O)qgw>dVSNFl}h>Pq^Z3|JKZQ|2=H zQ#7%5_qMj0+dTZ^9LaR1W$maZ5>YbEd#lxSbV%UxY2>FvIr-=NGNm>OJA4Ws+}f{P zd?oMV`>DLFgRe_TpmoN}3?VVyYP@3LZdMNFbwHu<^GN&)ImR_<)k!%oGPHN#I$ zo!d#wYBpn>cD?F^rvMDwx>tn?$vf6vstsU-x%Nl=NC+*;M%c-j)AMNj`kmkF&i=SV z9_p_v6`(BiZTX*@xo7G9LqSAmyG_s7I^gq)%sdAu`V+832q$i7Wz_0PY-kisfw@^?2T)XxZ!`w{F>A$->G6|cu8nk!H zB0URuPPQJB`GjLwIpmnzfTw5xy#5aV+a2)gVx)+R-Y9&Wo&RWu$@cD6)B)v+p<)zs zTW`qd^V+;nr9d{eFgI(8_FNJbJv8w15*v65g13yH6k(Q2C@07LeDX25&Uitlq%O!@ zDpT;djLxg!*POFj7R@(j(%@sq8%d`kI@aF-^vVa@78%Ifzc2bdZSum6z%LLCubWMq z3jGA#A!n?5^p!6YvQx^dicGm|R zk+c#E-9!9%^i9@~?2NIH;0;E3hKL=s(~ZaziQ-U{$ZsSs_*(vL?|Zg#tUS32FC6j4 z@@iUa(V=JnS|pi-xQNz(c5)8-ku+5L;V?_iFot#m{^yyGwun$Y=fs zGLA3#1j#lxzPQSXG4pCK4WA$L)-pLiv;J^#*n1l4+Pa*uc!Ta<@xqw{UvVqKk*H?t znG%2hNS8u>oso~Z_!A*NK;(z3ZIuzAT@sXig=3-#eN!@BB&wXyz1kSlp|^?gGoGbV zYwerH!Z{H5FE;mx>>jok9n_bn+dzl6A2jijg$$IIo1})AeoL}Ws6>QbEGmJ|d^?RO zjJ`TmEYQmSRFAXmEcHugA(v?5`)ZCGPm?=sqk7H8Ez50FSjds;U+#s&c(f5i6z;UV zJNy)=OXA@zD(ZjeZ)wtfOnh~NIvAO1s}@0U%8uKCDqk{$cRy!W!v1UcCwo~A$el50 zCv)1{m-17^PsMqj)jGtl>)~w|j8--l-q+O^&0s}kr-)4Ln~VxXZ+<#XuY6DRf0g)| zX@gPyqpG3XfZ%6B1NZ!kj)NX!oD)M(uebb^1TpL5kt=g(1eA=f0XvRTlw6vSVw&On zFu(R<)S{s$>jT3KyFvPV8>*h(L1^`Th%C2+Qdy|`a?{pDP7PIoq~=pgqB&`vD|+%S zljF5v<1;h|u`FtYSNWDZ%8p5Siq}8YnN`|=hCzBLW1t#*qU|8E`tEL~X!J)t#}~{a zp;nsx1TVLt!Q=$lE`;mh-|kF$u^ahrjnydIB&gO`BTYD5w{!Rn-eU8C;b`Z9h&gAe zn0oH(8QsaP4zA*?QlIJ`dll8s*l!d$^9lYC+flFKYiVhm2Tj6Jvh|Ml699h68zMZM z+Vl%jqGl~{c%-`)aUBt->fh19!5QWqR;;H3KbUggmDODp@8Doy{TwLj!Bs>`{uppf z*n8Cg$+BU}*Nr0~WI2`_sIV8G6QZ#?dp`F@z4GsGw%>NRe&^sa-ku&x7QC|0f2;ss zU#>A@R=M0Vd=DslWk82@)!RJi#~^l3DMbI$%Q|D9Qk!|M5iuRFgB7GYo#O9efLL!b zWq8gXy|E{g_@Fda<8Sw$8<>p#`i13%u{e?J*Cbl%4??|+HvkX-6A_LQu?*G9R d0{|fX9|0}gFj-L=VtfETApG%k5#PVO{{?3)BnSWi From dd3d3a5822ef5f285792e4f00dc1b847c918396c Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Sun, 28 Sep 2025 10:09:56 +0100 Subject: [PATCH 6/9] add new workflow for adding new mentors --- .github/workflows/add_new_mentors.yml | 76 +++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .github/workflows/add_new_mentors.yml diff --git a/.github/workflows/add_new_mentors.yml b/.github/workflows/add_new_mentors.yml new file mode 100644 index 00000000..640ea23d --- /dev/null +++ b/.github/workflows/add_new_mentors.yml @@ -0,0 +1,76 @@ +name: Add Newly Accepted Mentors + +on: + workflow_dispatch: + inputs: + file_id: + description: "Google Drive file ID of the Excel sheet with the new mentors data" + required: true + current_period: + description: "Current period (specify \"long-term\" if during long-term mentorship registration; otherwise, default is used)" + required: false + default: 'default' + +jobs: + add-new-mentors: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('tools/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r tools/requirements.txt + + - name: Install and Configure rclone with Google Cloud service account + run: | + curl https://rclone.org/install.sh | sudo bash + echo '${{ secrets.GOOGLECLOUD_SERVICE_KEY_RETRIEVE_ADHOC_FILE_JSON }}' > service_account.json + rclone config create gdrive drive scope=drive service_account_file=service_account.json + + - name: Download spreadsheet from Google Drive + run: | + rclone backend copyid gdrive: ${{ github.event.inputs.file_id }} tools/samples/new_mentors.xlsx + + - name: Run scripts to append new mentors to mentors.yml and download their profile picture(s) + run: | + cd tools + python3 automation_mentors.py samples/new_mentors.xlsx ../_data/mentors.yml ${{ github.event.inputs.current_period }} a 0 + python3 download_image.py samples/new_mentors.xlsx + + - name: Cleanup files + if: always() + run: rm -f service_account.json tools/samples/new_mentors.xlsx + + - name: Create or Update Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GHA_ACTIONS_ALLOW_TOKEN }} + commit-message: "added new mentors" + branch: "automation/add-new-mentors" + team-reviewers: | + Women-Coding-Community/leaders + title: "[WCC Bot] Add New Mentors" + body: | + This PR was created automatically by a GitHub Action that handles adding new mentors. + `_data/mentors.yml` should be updated with the new data. Images for the new mentors should also have been downloaded and included in this PR. + + Please review the changes and ensure that the changes are as expected before merging. + labels: | + automation + new-mentors From f0645725ac3e4ba488a40051b918d5760eca37f3 Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Sun, 28 Sep 2025 10:42:16 +0100 Subject: [PATCH 7/9] fix: sheet names should match usage in script --- tools/samples/mentors.xlsx | Bin 13670 -> 13669 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/samples/mentors.xlsx b/tools/samples/mentors.xlsx index be49a536b25117217107a65dfed13c9b57786bab..bc84f1faf6a6f61a59f3eb65a995fe31fe41d21f 100644 GIT binary patch delta 3076 zcmY+GWmppm7sp3;*G4%6=@{MMFkpnzF+x&mFhN2<89Bm9IFKA52#PRzASg-*h(X9M zDGo=9gopw|U@zY1x%YYR`Es5UAJ6~%e=9-DK~1bIsD?`)f?H?-01HL{fC~Ts+(M{C zBg2Eek;q`>TOo)?4mMZkAl&igZB$Q+p$=^Byrk_#*D-kx`w%+u+;7kBISh>;9xIs~ z?c*kD7!Lcu<{PCdCr9)1{;NmccIIv5K~}t)C@uvUHV~mqJlh|QYDiYc)K|$rwpA$m zA`^<*8Cdw;u}jc;S2Srs4|se1*^LHsmgf3}a|D?#GONMO5cBmO4K{Cu{=iVS5qCM5 zD4IpC*80}noZ@WHHHsU=XtG|pGu)NC|6JsGl3- z1u$O`rrg)e)~mmux>(R9aDBBN4UZd!D8 z!N<(q`@sA_c*~_|30r^P&@mivw@;<&5*UA3K~8EL8_;do0puE4HTm%yAHjov>Iy$J zhhd}$Tk=9#s~{r=yGDvvMOtocotKi-t*R!j7jHaOR%>bKf>3f|+L?MrAKxYtqll_*+}OR=agpdyyiqaDNFSlhlU{pqtMly3TS{@wlj8 zE}i_yYw^xJ+`?lxS3H<%Ob;s>Wl9u9#DtPat8{C{Z36Q|5dAiG=c?HevMWjLeDm(S zGVZ`2T3kRq@aMs&GdOhjjoV_FhC|f6r^Xh#7m}&p8_3Jmh{lC}+Ai-t50Qoy)esb- z1op;2TPC{MZrTwOv6T?~rTB^+(XED_{q5q(eKOsi|4jEnaNJmu_V^0)iCd#rqI&w* zT0*RZ^S8lY;BY5joh|9K<}+@JtP3KMdhy)++cACz9OXL?Mm60Mk)OXyG+t%a^q1xi zj(sGIOJ*Ib&Rc7Fit*SHolh_)B+@lep2GBG4S&@Y!^A1TYonw)S<>g+dy3)<8JOnc z9Y2{pbT6|Ru3@B%^lSe{w^0*&jaz5gCRjPols~ClVgdjfB>?~+0IRAYj4E{uL6$(c zPmBVoG&|i1sxYkVBeFM74ZT;;SH`b$HkV{puFxMcHEXIlg=nSdqxh-Z`I% zAq{U>|9Gnb&J=o|a2%@=bT7b9i@w2konn2>uce;GTawl53MX;@En+9o2{xd`aBytS z`yi%~^`+{OtoY&zsnkBx5~kE44OnVwrr>|?-Vkr8zYzP43I^UsrDVQhF6j}MfB9ZY z?Q0WR9OJ>Pwb_GsMkIrO5UB!$as^<Tk0h{Mzy@8Vr{D--CzCW`9hRO6m@BFW6hH*m^*09ZIHPr*8k zFh=KTj(DGRchUr&p8`BZ=`c<1cw5B@;oaA^I@R|ZdcZm&H59lY=~C#PrxJhoNXLeC zVSKpY`v6fJ-m6^$rZGov211cyDK4g~m*Tq?^^y;hAoQqaf&`Y~B3GG*9HKnohi9YJ zr{Z053}Ah>6wy50ukBXyTPt)1dLdw}MX(V{ixT6-3^4}kISV;2M|dG3hZVsSQpIp4 zCgGemFr*zE#yh5LNoTWQ;LnOlS8JvLJ>fLcj|7hM>6sjNIixl3d+DihkFDW2ARgZR zqH;8yDAQx#6s|{$c}jy1>=!3sIo6H=Uee=0{Tzo!j~xu83+O?93>bQr!J2+YA3M+; z$6=uD>q2XV3b7p*CLsJ_;S4avq7a(MV};uzHaXLcJ~m@l_!%D&nPtf2n0EH8X~1YM z<#q%*U;vaLclpXsu$FjPzl#C9*29TMc5*LbKpBVQ44wkMmiE+DcYwpYdkH zOQgG-#z=Ztbjdvn=-OwSlU51gaW2lFDVdCeQ!Al6wUWP8CxBA>;~}M3tL#(hp||r7 z&nS{IdUFuTCXTQur+HV0UyB=s63)%41e}V)@wS*J*4~_J+`Le=eWeJrf}2?!4`^Xp z%@1KM#(0}ob_Vmy93pz9&1lbD(jgTq6~4hCP%tnqoYqs85C;ceE0#h z+rlV$^rl^DY{AM8$3tU0kETo}%Erl5fwC7_)J-%az)M@=XuSNnFT-zfiPG%cOmO=5 z*dF<_sIF|7w3M#iZJmanqBX{^GJNwQCg$am!}a(q8by6{wG%loQKaerxk z&m?bK$bqgoAF*1HSW4VH=eNTtSMnK-aRawsh^oZoNree23C_sFEh$pw6U+TlB?dz- zdq-&_{?&b)(GEOJ4p1T3OG~+u(b(f7>l@#xs12CR5P>kaMHc9PZT7ta8r27;{UGjG z5edyTIchA^1;MWX--Pjyc&Zmd|CXRyS>FXo3yFDeEJh{ z?3H(REzg{+_8g|8Xj=Ca)M@CAIhRLTm6SASP-*SK$?&KOCk6JE=`YGst#{EUU>bE#EVAxR*;X46nb=5i0xpkw{M%aHI)E zZ=p-zKa&`*&OOdDJd=Qk>RJbsdObOx)WT>AO+j@DwrQX|*6!QbvBm{_vXq%uEon6p zosE-3d(X8)OCp3vjQfz^hE_xEuRU3809F_*V;~&FNxiE(2MdBuHa=6KL)C!z=r^S3 z>rM|ok8XLSu&HI3-N&T+CzR}vp-ZGwtfErs0M-_C^!xxu0P|@r0gw&1M0L^t z0O73!6$Khp-)QjC^(qXwjz8L!jg3uevkdt|S1|vaM6LA9W715hoBti)#^%-u>Wc9^ zjC?pIJn5A_J9GBA+Y;zPom=(h%Qxat*Hn!B6{VX5fd0*IvVg6@loQ-E{i>?ey<8hM zk-PP<;YOY8r@eyYBwq{jO%t|^k4>u$4TL_|$7QalwhWcsqs&E#hxn$h?{@u&jc4m0 zsap8bbqaZLYmLP@Q)K&|W6s)xaJ<8f@xLGYd-*LBw-@;VoG z?GXY%#jngR$r-W-!O%|R`j^sw2T3ADGBt z&lVoe9MAhYI;5POOzLzsyEXeU#s(q6>^v^-{aEP=LzpQWYYoy?%X8luXMjvSi8Rc* zX6E6c^dno>u)xLY`_$-JDgc|JHqG)cHe>zNuW-z<{SD4HBVrJKH?cGt{8%||?$h2s zA%NXhmlpXimHadNlZ&trjY~AG*eDGd(f@wY|KIv5cS*bxl@kw2QWJUt%w(|61B g|2qI7?1_ey$iK%$2LN#YXI_jo)Rbh*Q2W#TA4cputJw&X`>xz(3eA1COj1)xMUGrEN~V~VTgGHW!rXGiYBq&P2$d^x z=E(V#t4%_E*{|>KkG`+(^Vjowp6B)a^?5$ed%=IvpC%|kOmLkdz5oIM7!Uve0RRBu zfjW5Hjeu)7T!3~sHn0SP#?9(NU)9!eTG=MIM1iM@;|1*pl&~6g6J$?s87s|P!+;a! zn5~u#L#Xfj(h1w7JXU)j&L=-F`8`%~ASXci+@qP951olw4&Fs>YCG#;vs-%bhYt^B zR?Z7V%@RRZg`0_uqeoulXfP}RPB}bF!!CM?@e54_iw>A3o<7UvXjk2>^la44oJYAg zFWHO!j3SGj%Lq?^u8`fIbXe-P|p=R2k;e^F?qi*H%;Dd8b#E8sv&1VB*WP zH>L&!lH!{A+NVmF-7H5Z3X+*p>vG6@5cFsb53z<)D%e^F_xI=n#K?c=M{&%esj?%2^@bKtIkkN$O{R&3LxVUu7X*330Um6qv~uz|{k z!nmr8c6(>fTDZsUhcoi-m0&aBP`!`03@YPza5GeH9k^lF?XuRp<*k?Z_z=UWlHs8HQXeW`XgQc$^0~UYva2oJ z;TTDzDg)8pUzGki?fi|B@^KEt!g-Nxp}=<{zj1qe7tmlFWOJM@)%pvu$D72l8gT+0 z31d!|p3Pe7_3RFnL7I|(6;d5-FYCw>!B(}>HUu1EJvXAwH(R(^H>YIalMqjFgx=XY z=5F&FVdGYjjLr62==!IJzs7@3Y-FHGTvgZFl^`Nug#vJ1xV5Sb6J56=2Q& zgzS9Rs+AaqpBqGpemlDD30~$`cL$uW*`j<7bd-Lr2e&L^>jo(Fd^B@>^`k7NQNS%f zV2Y+(`-Hk7FT$W@o2LCxTS=KMyE3|gom zc5u&7DD_2KHBH2(5mB7pgSe3wgA0TDark416sVRseOahkP@uX4jT++v0H_q2gfekl z7rJli$5CW&FZSF6DxK57Fi^joZsDltYp?x9uQQK&5AOf!b=3B#LZ~Wq$v)d)y+Y!< z*^3O#CRj~f8V03grXp7hf0XQ>m0o*wz1F9FFdk#1;ni{W#%#{#>Zz7Xa;0~MBYIQ# z_%j{5r?T&e@EA{Qru$tTZi>!)dXA{7|Ly!5@UlkljqB$mEM(#b3%rVyz;7(Ut!Wca zyLR$E2&>jQa2JKQ9@wefE*egB@v)jgmE}XWFlz6m6pj@^7w65B&if=MTvipI5QA<9 zWY9iDV7{e%v13W%IXx#!yE2Au1Vow(OHrre%^-_h?~P09S&-bxl%;6(LyLMX*lYgByr)@Ml&N*{M0wKWY*^&Mzn}Dl_ObEG3-rt3fEG)`=RV@w zj?@5muJ1q=soIS7^x|d_z?|5{|DF{7g-p{@mG&cPt~IPcx$Bvz{rSuj6qwA9Xnl#z zjUKQ)cLT_2ug$0_6&5g_;I;SWTW?+q9?aW4s@pU2d`J5Roex(SaKQ}}w! z%VUQpWPW@Dk1RI#Tng(?llorW5s;>EC4uL;O^z^=SHkF0+EXlIv)E765qpSRcIRv+~y~wLCvg`TYqw(1?skw4M(z*SD zQ&oXHYm7&7yzs)9WX7p%i+dty>W?AX1@69b`vXRJcTZz)O^sjj>s@p#ln6WNF$*BoI2Q%RLVln>^_AA2Fnvo5;;p{q#^Km;h`q*X3%0N`M{x*~BR^|3BAenVqRR&)AbjN%w5t~!0S zrU8#3kE9-o7MDIdVN~(85r0>$BIAm+Mu;wxvqANEOYbZm@PhPeOo$;4b!3<;V=Hpd z7A*uqlBv^dj4!GX%gt+YubjNOz2U>R!fXcd^9ZEq_{v&7)?f4n+wMHT7Pe--Ggbyh z@i%}spK_o1p+u=rm*FB&-l{7Ro5&~CRE&(945yaI%BU?NaFp>1R@~O!$Ld4<^69Y* zf!m6ci$s`OcXrIHuY%z=topbNl8$CnTq!OVtxa3Uzl!3Fj*ow zP+Y4lQnYlL?U9bopVN%kM=#NxJ>nXx6Jsh1l2xvjW%OJpa3aqKf8!8IC!s4k1r{K4 za%_5y$;fa}V@j=|xbncZv~f|I#hM4ND@?4SowI5J;tmVR?yH%jPn??Wr^;Luf@o9` zpTLKFllaPGQLCXlfe?8M?AN<=Plu+J+$N;Sy{ysalJ64nx9zJQB%Qu?4*#7t*B+8c zFlT#Zlp!4tri#7XY?a8Nk6qm>Xh&_KBIQBeKfjrAt;li!bhd^*7tj6N?PU5F zye-h_z3_McxK^1HpX27~;6cgsP$nm;g4sLJsy+8>k+o}@uDyM0fpG6w(St+xqoKDI zF1E#e_WG;z!ma?DRGL0m`5>*3Te9v$ZLM<|e*glxY8k5V$c zBKym({fymB%Pdk3gT}YuW4xR?mb>+(e@a?UY=Q|MKUx0eZ{@$4QIYGmTXD$s`&{qN z_VN#!V~aP%$dI5Aaf7h6FgL*&e8S&^>tWu@lY(gMeVv<~Uxy+Tg8RDDuI%L+HaV`# z-xq&3r<=d~rJcNFgHWYQi|UxBws3B7j*JkWoEGJX!lH7;JS=?#9`)L_>%Z;^XDP68 z|9lz&S>X)=lM4U{qCeBo;38V~1Jj`aaRoZ1N=gXaBM4HfRdnsKw1IxA0R9B8OrMD(>s-sgc30c_Gj z994?_Y_9SYXQD2&VJR8XSbW%BwIzI75}XuNF>K2RyPP>HRrjpBBZpw(8(5M(p%M~w z#*CMes!q9<|L$o#NXXa{({G(ITdIH)`N_h*j(y^lnW2AT4y~>%E#Kb)_vH$Th2ba=nX?|^$YSk(jD)jQ(`EKMzt01v|H65up;L-G}7z7qj54S% z1(b$T^q}Gt9t2eS4^1co0Fu99`QM;YbPzVc8aYazoCJl0fXe)_#ot{0-_iM_6kUWk wr3WD{{m=b5{1(pT-vBQ1@3P;SG-VH=BK=2Lzx@^ZpME|CX`l?c5C5n5Kkw{+5&!@I From d3d491c4afd8dec1e09b7725628710b55670d49d Mon Sep 17 00:00:00 2001 From: Airah Yusuff Date: Mon, 6 Oct 2025 19:11:52 +0100 Subject: [PATCH 8/9] cleanups + updates --- tools/README.md | 19 +++++++++++---- tools/automation_mentors.py | 46 +++++++++++++++++++----------------- tools/samples/mentors.xlsx | Bin 13669 -> 28208 bytes 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/tools/README.md b/tools/README.md index 25fd7e9e..5961bbf8 100644 --- a/tools/README.md +++ b/tools/README.md @@ -21,17 +21,26 @@ python 3.11 or above ```shell sh run_mentor_automation.sh ``` -**Note:** -- Ensure to update `mentors.xslx` sheetname `WCC All Approved Mentors` with new data containing the mentors to be added, **OR** +**Notes:** +If running locally: +- Ensure to update `mentors.xslx` sheetname: `WCC All Approved Mentors` with new data containing the mentors to be added, **OR** - If using another file source, adjust the `FILE_PATH_MENTORS_XLSX` parameter in [the script](run_mentor_automation.sh) to match the file path. - If running this script during long-term registration period, adjust the `CURRENT_PERIOD` parameter in [the script](run_mentor_automation.sh) to "long-term" -- After running the script, you **HAVE** to run the [run_download_automation script](run_download_automation.sh) to download images for the new mentors. Else, the image links will be broken as they do not exist yet. -- If using the script to update all mentors, update `run_mentor_automation.sh` to use WRITE mode +- After running the script, you **HAVE** to run the [run_download_automation script](run_download_automation.sh) to download images for the new mentors. Else, the image links will be broken as they do not exist yet. Read the instructions for the download script usage below. + +**If using GitHub Actions**, the GHA workflow is **ONLY** for adding new mentors. +It uses a Google Cloud service account setup to retrieve the Excel file from Google Drive. The service key has been configured for womencodingcommunity Google Drive account and the file to be used/updated has been shared with the service account email. + Hence, to run the GHA workflow, you only need to provide: + - the file ID for the excel sheet to use + - (Optional) the current period + +For more information on the GC service account configurations, you can read the [documentation](blog_automation/README.md) in the blog automation folder. + #### B) `download_image.py` -**Before running the script, make sure** to update `mentors.xslx` sheetname `Mentors Images` with the data for the new mentors that you want to download their images +**Before running the script, make sure** to update `mentors.xslx` sheetname: `Mentors Images` with the data for the new mentors that you want to download their images If you want to use another file source, adjust `XLSX_FILE_PATH` parameter in the [script](run_download_automation.sh) to match the file path. You can then run: diff --git a/tools/automation_mentors.py b/tools/automation_mentors.py index cc3bc6c1..b2345d2c 100644 --- a/tools/automation_mentors.py +++ b/tools/automation_mentors.py @@ -156,18 +156,19 @@ def sort_for_long_term_reg(num_mentee): return mentee_sort_map.get(num_mentee, 500) -def get_sort(mentorship_type, num_mentee, current_period): +def get_sort(mentorship_type, current_period, num_mentee): """ - Get mentor's sort value + Get sort value for a new mentor Rules: https://docs.google.com/document/d/1GwlleBNScHCQ3K8rgvYIB3upIr1BylgWjGR2jxwYWtI/edit?usp=sharing """ if current_period == LONG_TERM_REG_PERIOD and is_available_for_long_term(mentorship_type): - sort_for_long_term_reg(num_mentee) + return sort_for_long_term_reg(num_mentee) if current_period == DEFAULT_PERIOD and is_available_for_ad_hoc(mentorship_type): - return 100 - + return 500 + + # else the mentor is not available for any periods return 10 def get_mentorship_type(mentorship_type_str): @@ -258,16 +259,23 @@ def read_yml_file(file_path): return yml_dict -def get_num_mentee_from_row(mentor_row, default): +def get_num_mentee_from_row(mentor_row): """ - Extract num_mentee from mentor_row, or use default if invalid. + Gets the 'num_mentee' value for a new mentor from mentor_row, or use a default value if invalid. """ val = mentor_row.iloc[44] - return ( - int(val) if pd.notna(val) and isinstance(val, (int, np.integer)) - else default - ) + return int(val) if pd.notna(val) else 0 + +def get_mentor_position(mentor_row): + """ + Returns formatted value for mentor role and company + """ + if not pd.isna(mentor_row.iloc[9]): + return f"{mentor_row.iloc[8].strip()}, {mentor_row.iloc[9].strip()}" + else: + return mentor_row.iloc[8].strip() + def xlsx_to_yaml_parser(mentor_row, mentor_index, @@ -283,22 +291,16 @@ def xlsx_to_yaml_parser(mentor_row, focus = get_yaml_block_sequence(mentor_row, FOCUS_START_INDEX, FOCUS_END_INDEX) programming_languages = get_yaml_block_sequence(mentor_row, PROG_LANG_START_INDEX, PROG_LANG_END_INDEX) - # Left commented since the code might be used in the later versions - # to add default picture until the mentor's image is not available - # mentor_image = os.path.join(IMAGE_FILE_PATH, str(mentor_index) + IMAGE_SUFFIX) mentor_image = f"{IMAGE_FILE_PATH}/{mentor_row.iloc[2].strip().lower().replace(' ', '_')}{IMAGE_SUFFIX}" + # Format mentor role and company + mentor_position = get_mentor_position(mentor_row) mentor_type = get_mentorship_type(mentor_row.iloc[4]) + # If mentor is new i.e mentor_sort is 0 (from default input), get the correct num_mentees and sort values if mentor_sort == 0: - num_mentee = get_num_mentee_from_row(mentor_row, num_mentee) - - mentor_sort = get_sort(mentor_type, num_mentee, current_period) - - if not pd.isna(mentor_row.iloc[9]): - mentor_position = f"{mentor_row.iloc[8].strip()}, {mentor_row.iloc[9].strip()}" - else: - mentor_position = mentor_row.iloc[8].strip() + num_mentee = get_num_mentee_from_row(mentor_row) + mentor_sort = get_sort(mentor_type, current_period, num_mentee) mentor = { 'name': mentor_row.iloc[2].strip(), diff --git a/tools/samples/mentors.xlsx b/tools/samples/mentors.xlsx index bc84f1faf6a6f61a59f3eb65a995fe31fe41d21f..8fc504554c76050c890f5cde680c5719a8d67ffd 100644 GIT binary patch literal 28208 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 YjjoUG{?tzs(0lQ}zk(<~I;C&_14lAhb^rhX literal 13669 zcmeHuV{~TAw)Pu!Y}@JB>e#kAwr$%sI=1bO*-^)~ZFHd;&lK002S&62|(PArJt70R{jd10aAk1Z}JxjjSDYl-z8M9JFX% ztt<)hK!M3~0Kgyr|KIVyxCQzXC#-wvVFoS|?%7TIH`rDQO*nd%YsGpwm{g|Qy&+}w-?w`_?4kqz`q>cS{v=* z`sHV+!!ls;^h(jt7|B|^wUdVF${WJ3bkCQgP=Z=e3QJLbm3g-xc7X#kDZ;3b?#3QK zsGG@MdtA{?xgRME6A@&UkJDD_!?3s7D~^ePzd-+?7Y8T7o1O~QP@N3>HK!Ya->d?t zq*hoxLIkteVS_XF$jzG~el#wC*ou0y(8mXfdtb90 z;wg&Akdy<}+s)4}pt);7oaq%^WKyJT+(>j3=ALLgBmfE`_c0Qf?*_mSae> zl!Mi;5BGb22LZ_an{zfQ(-Z&tusEp?--G^eP91wAO9wjIKhFQ>l>du8@n5Q55ic#< zM-LNxA@&k7bU(Kiiy$EB!Y|fFsO0S{z6#$Ml~01b*7X?&K?y4WMAWCl`($<7I!lFU9?#I9niAJKX4cJ3}!RKktixg&bZ0co{${f8=`IRVA9%HW!2ww&XHiFBWZ3-q0^n zr_-sZLk{{TOI4mjmV~#DSjvi~U(9Osv+OyD+;j{ryKjWjyO3W!X=E~n6o{CS9vCM? z2T5~oebgJ6uYP8_^|L|tl@DDG`$yoHtbgRG|8x?G(jvX5j}{RH0RXT75J0Y$bpP-Z z7aMyEeH$B#KXTYVeFo?wk$q_S-+i>lkD2$=!vtOgbp}jz*u}rejc|BS1a&m6fYa9^ zg-BZ(l=8YgrzM`V))b^n=94hrFpL^MfBChIOYF2xL0*Rg+Pa)R-Uy|AFZ=bLAheOG z^&Sp2Qmm$umX38|(LzSnu#JzXlwCnLwJ#u1Ndt%3h$lxfWnhrs0n30YpbEZKSZ)6? zGqQ^%C(SH8Qy#%(AFJORX86&@YJ*uTDyGvLd-4hsdN>R^At#!q&fn}s8%+%u%q=Td zGhwT55JXLg#}4N!NwH)LsNxILs6Jz}MQ`jJ;u!Rx5)VfqlLj5BLp>!-jMwo~Efw<^ z@14EM`!V$2Sx%Mkm_^-3XqEf~0Kk8k#E0eltIZTB%ge6NBY0;wyz4%4vx~3r5i1C3 zOj5!sS%KiioqUf{9vrtUrV)6#&zva&d+H^SIL)AYds$mEIe5`mlxWx z`{77COVsD$Qx(7zS&>g!tU#5u_1XIB$L4eMO(W~i)Okrzz=-j8+bRjj+KNrm#?P(W zP+SgH635-l(E3z;X4cT-S`^|q!H^WCa;_1vX)(HokDBy6^A)r$_8JI%q)vPrXnA!s z>cc$1Ulr;r%6*UOfJ0Mbd%0P1Fp{VO#I*DuBp$HN)lzp8D&o0S>;VzIbos&rl_FFWBo_&$ z9o)?r@Z$#p*Uy!Xh?Qj;>Q55lktB`hl<3h1m^@&L)sK2PA#tVUdNd@i`8DwEL%MVa zr9dF&J`}iY;T$~EBYv~avt5+spFEUI5g49+ywCUAE^-nOLV&A}C~(v(9z!W%r|Q|8 z5b_8F<$_^4v^lmC!RI5YF^Oc%Pa{eGl(3i79*)Dac;^KbPn`hw!?AR;-q<(*IZSIn zU7N)Oy-2u{6??I1^=IU(y;-BpeBg4yLuE4i^{|Sc8Qfv(i5pqyz z1YaGTX}x-p-N8psCZ1ZDB5nSD8|2Pp zsbkZ^W73~(YM;MEvs%xODfFnc(VbBBWZ;&-{;MJTIax?8z9u!)CbkoYHv-Cqo6!So z_Equ(i>9B=`XymC1d9n7f`xklR%QUyWMSfAU0I~|70#NkM57-_&10E32RZj`d73!h zBZkhzhF3HhsaAKY_ct)`6>pVQv0SYz`Qf5ZkK=u8&%q7vem%S&#`~XvG2`V0A089{ zC_w-KVE4vub?Mh<@j#8Xubn{9R!ZymGufTVk7bO`8Bddf*L;<0EI^RHw9|~7~&;a zO1J^6VB^(@0AfaxF`|j~;WKfJ0c8f3-pGsvAG=DnOHjImwyyL-qI^fQD%|$buU8SV zpamGIN`FEbdDKXyP|7*V+Ud{k?9xfpMpZU|g#dod?T~lH51hJ%mKZiQu2`hD;$~SAJ00x(MIF#vdAmYqYfPj3>2&@aVn>E1 zZ31JM#ZYrZFB^a;6mx4>mH zyc6;T5ad@L^{BNF7R*;~O{G0>Fwt^s=ZZ6^@kOv}XYO9%o;!ROPiZB6jm+Fub@Rho zY#K{a=N%0ZHvfd=Vn6s3!et5Ju3iPff+7e@7NtiwwrbX!5G>}y>qnneDeY`BBro~z zt^`SyP>Rd4b?#L!0^m+7z@IjByn~xJzGKi~duc}U&bH4KJ}UOl+TYc4;z(IRUYo#_ zgP$WuX%Psinr;lWWi{CUpS7zdd)Q= zc7TYv_iNm@0=FQ$7nR))`5ozLvPa6oz?7{#G7cl>2K4Z$n5;qsqw<9wnm!Ed53P`!cGv!8HPs1 zhDD2BuFQBP=<_Ihq5c>yS=a$47yutU6W=qZ$TH4KyY5oAcm!*HL*wDQaE>uI!Tz>stvfo4>2L>qaSdy^<#yXTWO!t8>ofhY4^BC?2ZdO5407X=Aq zFnY%2vXtwZEX_0$(KNF*)sgact-JfTMKjVj*v<;Sf+jGvZmqp>?0tlzFdt}z1Y896Dm(yVMFn|8!BBp4^wvW>V ziy>0ShVX=OL~c@{NW!v!EHd*|$N(&9^bx{B9-GDY%qKp;1q>>QcOWp@m53vog!I6P z7)8Y*FBt>l>dnJ!W&rV?$30W>!AOG9rST8HfLdsLoxe2h3@b(TfPQY>|Gbf6gAqx& zFNJt(5<)x41}I9lgZ>2r2q6?RccYlDP@X?oQ}=cTGJMx6>ZsQ$S2=;}$ z4CAil0<;b|bY+VD0}j|a{SB>Ge{8XNQZ?xV9=aC5l%OxXNKBfMv7gY@4*Rnge=QHd z21(P^AVr|1p5xP-yh1!}D(Kr-|(3Pm>r~JT7jx%bnrAkk9bmH4Pb2 zZR}Cu*gBp!NBBBkf!;pXw-KV*&sTM!?|aWNK5s`%ya+_5<5M?uc<)cYu5RdfAJ0}q z@gADGUy0g9k%^|H?IYn_f$K1Te9uVeWZ#I^jx4PQ8RT0LbQk>rcexMBgkL4BxwnQG z%jMZ^vEu<(9a4)yb^PVgJ%hcQdt5C7x*E9Zq#g?EJZfgh=Q{?v9XJO5qbJq}UC5U(fHgPUcrycZ+UUUeDSNsf`r{5yfF*a$#yadx==+}fPPtkC0yj*cIJYftMHiw75 zxMyy+o)O0|V`6B$e8jITy;%{Wyzy)il0@^BYR*_2rSO|L_`Z5FFq%nt0NE%06A&n? z?!fA$z^PA6jFXg22KTeTPl;VWvDABwEE1!>6lpU!VZ^ZfN^~{;cs!DtB2Rl84axk0 zMQ^wt-6XF;xSSXf!4ele5maMf#sHxf9-ZDJ(xCt^7g}#j9~g)6Ce29SGAm7NjJQe_ zB%ylmZ8V8>5pm_ah_DRk;VPo8Ok9AxmlB)nVQgv`Enj`3X1Qt8>rw!()JA!q|EUuY zam?|(7kdYo`b<3;CWJ&uSOZ;U^fnl17c(IS6*1&$6XSMC6-T$G^G+$&gpX9yQpxf3 z2>g4{%rdL2HQYGyxI=c4Y#()mU6!(wr%c~suQbAhE4^&8MjzhL{@xnIy|FMw>(#py zik9SNQ7*?M8pIZos&2tfBc^SxK3pSVgxMmhEw8ZxxGVJPZm-29@%M06AFwaeK31b@ zSY#D?x=P^80{#Lt3bh1=_;vADonH~C4xE0*8-5|&kq2`&GG01QAntYN0AqE8gqMS< zvaS=)`UGP=^}c$*<^L3SZuC|P8x6Z(NNMtvtVW%spm6r4s1fZJSB@%So{MDpu#z>? zhP;-sXngJ&H2=NFeyenLLerG#JFUPIx)Lv?fHAMdq5bj>c&s|2XJJh{vF)*B(-9vB z@ABzlNY*f|y3TZgWqtg84f;BNhsudNPvbbK{~=w&H<`)Ib^R>a$`)GON;KSoe5KIw zAF8uflaBNZWb`_n;rPX_?|9!DK(c`bq{Ka5eekP*^vrAUkqAaAF~{aBdH*&C;b)iR z?ScaU)x;m*^k0)R2U8;>M+dq;FMlSY3>7Pzbb5q09=!OCB#41XxT_c!{~yT4nzB_69?d||^QP~y0~ADE4xpIypIkpi#VN3F0d zq)heeGDkmFw@cL(a|uSk!gXZjQV z(Dt33e)D(S4N%@=rX?oJn||mlOgIt5je5^@u}4cbZ~syVsS>px9W#os6}BFc6}&f< zYBzblAOr%`Oxr=c-A%I_Vg`n03tB%gzAaNeCVU zwK0HHn1!N&kse4O;*VAbvJ3tyF})Ve%|;^~vR)}Ryt@%`#%lvA?vfrQ$$z*m|MusM z^3PMnw-xJUK8!#euty+vS1W_Bpk}yYLyw;Af+#EN|C z0~;@G#x<^K6Dj#e_8d6voiCOh=b#-qjSoCt+9*C=$1VZ$Gj$JCQp>OGreogJ$#ffJ zH`O{S=95oz5k>W~**-D*5lb&Ew$3Yh^f;paP6g6~xlV@CgK=V!0^De5 z61PICfkC|;AAj5rs0&EktEiH%aq8tdUIYbA zdm((hl~*O#(n+e(u8rNk%?l>nJ5ffY(4{NGQ0VQX%r947m+#k}osu8WMwyl$(pH+5 zAJI;nmLJugowgg#`xfnhHs+X7UsAM_AFx;6{0|E;Y3@p&Ulb^pMCr4UNE-NZNpHfZ^hP(s_g%2L=85RWq3-%xYR3Ya} zhT;nWw#W};DCdiU0ssa3&Ig1e=L?JivoCOjG6 ztLBp2x=(T9MtD8;)bBdjif$;%jj431GvXo1pWKO$J?@5Wu}cBh1~P;6=5 z8Ft!Nw4W~KI?5JzyJ+?b2d}y=bK;^2=4_Y5H#cs4boHO@w(cQ?}_Mqjv zX`go^Nzd#NP|wEY0n)%GPaB=^$te=WmA^OouY6PL5G2M=zeMYb(%` z5vVUW!T`3#u(=BW$BSep_XUPR@Kwl`jp}H4*lp}eGCqU1Dcs}Oqbua|Zda*OFk7uv zed=1R)hu=!Y*c77FnM0N#Q)3lxgz>iBa-Y%nyPnwa^GMGA23$ntRq&Y5NRa7X6}^Dv&O^T zN`=yfIxn8TVR;7U-1KcSOuTS>-O?*Fu@IHZsRf}^u5W65oHqn4#XW+wXd2Jn<*rG! zaBm}tJ&f2VvI!18gNy4j1X&HDL@p6r(8ra&pyy$GyMg_*;K}ojYQ{-_s8a)NZ+9YnGDPg`HRDkVeH-6UC02VYs__+b2VLVO?WhjnG-FyQ#clPz8>*-~5F=rs@L)Df+{*VVO77H3 z*(>W1hTRk;ieI88+m0z5#gBYxisgxsNFXU`q4~7rtCgOrGdY$i0B$7VK3vtYr){Xf zcZa@JCa^hCi4uYLY$-f^g=Y5y0m?ESn$>TqK`Q45m~#^|L&;0s$>&`sBWqovlyr$g zOG4chT_zanJb(5FsrcOC!$uncoGDOK%9rq z+T+NKZFTHJQdz)O3ZYj`R@y2i64eMqJX}xfHI2XEY1jE&ycc`bBow1`-CO+VdTQJj z?NWKM7JV@x1-No=iiTrc0)f!@yX+|g(Ch`m#{ip7FNjk8lknD@Oi=4035!rYY2gkXbrJPX=r7lU3$#U+r)#8)VAc(V1fmy3rorQZrolT0 zq4N2C(fk}ilO=@UNI>W_!m(PeIHzGPJ^Pz_zVN}&9GZs=dnUTeNP^_d1c=cw56KhI zYLyioShKA77O3t^A(?4Vep$)#P4xXzd*;(&DCi97RR#=-w3|WJ7X5%+6(}Ye@@PJ=BNaJiI~t!&Yq>1tqj;lv zB~r0E5NOy_v=O(R9+sWCJa2%WFhgz>c)e_(m>@^TURn5_m_ER_hIT+&^t#kGEJ?9O z1SCEk3f_y@#S$vlw5U6)6ar!uzkR*(WP$a?tisArV%M`NQpj0PE_l;-Qt7@}!J+N6 zgvr|cQ*O7hAUB#+{%(dV?z4?&x0Zgxr`l? z<*?B{iF7yljx=TBGuAtjm~Z-0C;;-zIBlp|uFV=I=U-PGrkx&IHf|w@_~m{SsW% zwml$}(dP2Gds$*DW8KfqgN$CG{u}{)MyU##B%vi85+M##rVt)wYs;q+_PJ~0tkMk%v(W#2u(1ndE^z?@Q$(-WABZW<99=?T*&}PQACMCC2H(e zH%itd3>ObY%_a0TwP*!L^ekD0?d_{bFg`-h-KHSt)wGXN3P~uaMdfP^%Au7&T}Ec! zJf7zR?#nqMVp8?ZPYCh`zx;Zj`I*_OFr)9y`qOL<7k}H_axa7#rCB1e;WlC}qd$;_ zaDC7bh9s3PT>pqJjX9L*B6zs&>LO6k1&fw+^dTktZa!QYRFJ zRB;J{#-I{Tl!>#lI_BgmasncS3E)J(#3~x3G~z>op4W4SicGxh26V2SN(cPgPjNK&GC>TO&(nVg^jB{Bs*P%v9ov+66iZjtj_(qqy z{>$-oK-wkq{V={jHH(aLpO+LC)^n}8RH;ApoAng3>{aK^_I(40_BG*+rM1!5W`XU@ zYs`UwoOq?>pg0?Gq?zEq&+XymXhH7G3_aJPxXZK7UKpG}*vqA8K5d~Ta!_PmP=v{_-WJQLed11pRBgD6J#w3iQ5LQVL_Buku zk1u`+rsM9x2*jz!7dK%-o>qvpvwJWj_5xx|%byNU><3S*FxSD5V_@ZU0YjAZ&U7h+ z8}GjFvobuZV6T!cYvv*+`mIY`YD26Lz9mBKf{pylvft_z1Qu_5_d+0 z?(PHxyagS<^tE|wXAN==9p8=b<0Zc<&NPovn(bC_r(TX!E>heuW}B=0CfvE1q87k$ z=#3N{C;*Y1O-X2AK>5@CSx@Hs!8cx#aQXtz)p?g&Alf?=xkIk`fUsb`88Ex_TmE<` z1enItK*`8E(JldP6kkneb2N3#th#C)9_v;-VEbrJ>FIA+y*IX8Z*L1%u61m9COcO; zI}aCUkB`MSJ8f@=9UWO{8#eYVb}9STaj+7ZR>4Pp`7woFamI)npE6fS;21#?Z8%in*V;v@>N|2Y!%b1(g=5FOd`1q%>BPv(eQdludrc&s;d! z>K{0O-T;?7hIv!>iTGuxX>wEAC=(HgcP;pF-jCelb3SIw z4kVKRizC7AIbLujCF$1iNTwed3<9`1=;+2m*{w-h-2G;x?TQw*xP`hdS(=~P1F6QXwxWB&0*?R?Nt)wT#x&1B!AV4-tex2^=l1;6SPGIA zT{|g5;pXNJOedfBZ6wsiO|m>L%tl{{&Af!(?(|HL@7gf2h)V`J8l~l?C(WUT?Y#$? zbH*dj>qZLy?V$T9^dC!nf7(RiSnZG;ATp~_6lzXX&1Y1@QlqG3Mb*ahFX55Vl7qo zf3h9_EYkm{b4*^iy>Y1zTw3eHV-P<`Wrj8ea`ra14s-@K_C|lW$p`=P|F~oyJs23T zVG%%&5qtsu3?J_i71Cr8pzfUWl?rBmaf_BD+v;0bd_n!|y=0?PG@LW$23yR;eVk)U zO42>pa;UlyIh4SzpFRt^c|vZA{@z5K3AJ*DN~1pvZg-B6w^veKaE*FjLKXI;itiPU zIA(7ej8&x-#6YkWzXJ02V0%3^3-LZ!gmOBD{ERW75gktzaLM(vsPvtKW^`w zA3~~zV_!t6#2zNwS1Q|1&4pF+o26@7E~W$s5I?Mvg*rqWe>rqaY}vd~vP8w8K7vpS z2qS;6;9n*DwX@<2Cm&8*$)Pk1hIVU%waIAEMW7F_Vu%Y0%ZjLLgPlOg%2Pz((|U=5 z-H!tHxla|Rx5WkTMArTb201(19jpif(m0|E2WBMiF>K&3x@|wbT`xUqNoNC?{3);n zy&v-p>geO4pYPD4)|zVun^Um%g!9HVUk|_o|s(HbHMr+|fE>+S)YNF<-b- z)TA#LCWziYI_@8AH6UP`4+QV;x1#*Bd;fX;n~f=QlK-yY-|6!I6#V0w`QbzVLZ1I! z@ZTxK|0>w~F%>JdN{sXH0qXxgjw7+ZkeUSQ> zh9io Date: Mon, 6 Oct 2025 19:49:30 +0100 Subject: [PATCH 9/9] update test to reflect additional sample mentor added to sheet --- tools/tests/automation_functional_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/tests/automation_functional_test.py b/tools/tests/automation_functional_test.py index 321a3271..f81f5192 100644 --- a/tools/tests/automation_functional_test.py +++ b/tools/tests/automation_functional_test.py @@ -7,6 +7,7 @@ MENTOR_2 = "Mentor2 Name" MENTOR_3 = "Mentor3 Name" +MENTOR_4 = "Mentor4 Name" def test_write_mentors_skip_zero_rows(monkeypatch): @@ -19,9 +20,10 @@ def test_write_mentors_skip_zero_rows(monkeypatch): run_automation() result = read_yml_file(tmp_filename) - assert len(result) == 2, f"Expected to write 2 mentors but added {len(result)}" + assert len(result) == 3, f"Expected to write 3 mentors but added {len(result)}" assert MENTOR_2 == result[0]['name'], f"Expected content to be {MENTOR_2} but got '{result[0]['name']}'" - assert MENTOR_3 == result[1]['name'], f"Expected content to be {MENTOR_3} but got '{result[0]['name']}'" + assert MENTOR_3 == result[1]['name'], f"Expected content to be {MENTOR_3} but got '{result[1]['name']}'" + assert MENTOR_4 == result[2]['name'], f"Expected content to be {MENTOR_4} but got '{result[2]['name']}'" # Clean up the temporary file os.remove(tmp_filename)