|
| 1 | +import ast |
| 2 | +import os |
| 3 | +import shutil |
| 4 | +import subprocess |
| 5 | + |
| 6 | + |
| 7 | +def install_mkdocs_with_pipenv(): |
| 8 | + """ |
| 9 | + Builds a particular branch site. |
| 10 | + Having a varying set of requirements can be handled by having each branch |
| 11 | + build their dependencies and then running mkdocs build. |
| 12 | + """ |
| 13 | + folder = os.getcwd() |
| 14 | + subprocess.run(["pipenv", "install", "--site-packages"], cwd=folder) |
| 15 | + subprocess.run(["pipenv", "install", "-r", "requirements.txt"], cwd=folder) |
| 16 | + subprocess.run(["pipenv", "run", "mkdocs", "build"], cwd=folder) |
| 17 | + |
| 18 | +def copy_folder(source_dir, target_dir): |
| 19 | + """ |
| 20 | + Copies contents from source directory to target directory |
| 21 | + :param source_dir: Source directory from which contents are to be copied |
| 22 | + :param target_dir: Target Directory where the contents are copied to. |
| 23 | + """ |
| 24 | + os.makedirs(target_dir, exist_ok=True) |
| 25 | + |
| 26 | + for item in os.listdir(source_dir): |
| 27 | + source_path = os.path.join(source_dir, item) |
| 28 | + target_path = os.path.join(target_dir, item) |
| 29 | + |
| 30 | + if os.path.isdir(source_path): |
| 31 | + shutil.copytree(source_path, target_path, dirs_exist_ok=True) |
| 32 | + else: |
| 33 | + if os.path.exists(target_path): |
| 34 | + os.remove(target_path) |
| 35 | + shutil.copy2(source_path, target_path) |
| 36 | + |
| 37 | +def delete_folders(folder_paths): |
| 38 | + """ |
| 39 | + Cleans existing folders for app and branches before executing the builds |
| 40 | + :param folder_paths: List of folders to be deleted under the current working directory |
| 41 | + """ |
| 42 | + for folder_path in folder_paths: |
| 43 | + try: |
| 44 | + shutil.rmtree(folder_path) |
| 45 | + print(f"Folder {folder_path} deletion successful.") |
| 46 | + except OSError as e: |
| 47 | + print(f"Error deleting folder: {e}") |
| 48 | + |
| 49 | +def clone_data_to_branch_folder(branch_name, remote_url, parent_dir, pr_number=None): |
| 50 | + """ |
| 51 | + Clones data to branch folder in branch/<PR Number> or branch/dev folder |
| 52 | + :param branch_name: Branch to clone and build |
| 53 | + :param remote_url: Remote url for the git repository |
| 54 | + :param parent_dir: Parent directory to get context of where data is stored |
| 55 | + :param pr_number: PR number for the branch to host data into the folder |
| 56 | + """ |
| 57 | + common_dir = "branch" |
| 58 | + target_path = os.path.join(common_dir, pr_number) |
| 59 | + os.makedirs(target_path, exist_ok=True) |
| 60 | + os.chdir(target_path) |
| 61 | + subprocess.run(["git", "init"]) |
| 62 | + subprocess.run(["git", "remote", "add", "origin", remote_url]) |
| 63 | + print(f"Checking out branch {branch_name}") |
| 64 | + subprocess.run(["git", "fetch", "--depth", "1", "origin", branch_name]) |
| 65 | + subprocess.run([ |
| 66 | + "git", "checkout", "-b", branch_name, "--track", |
| 67 | + f"origin/{branch_name}" |
| 68 | + ]) |
| 69 | + install_mkdocs_with_pipenv() |
| 70 | + source_dir = os.path.join(os.getcwd(), "site") |
| 71 | + copy_folder(source_dir, os.path.join(parent_dir, "app", pr_number)) |
| 72 | + os.chdir(parent_dir) |
| 73 | + |
| 74 | + |
| 75 | +def process_branch_folders(): |
| 76 | + """ |
| 77 | + Clones the branch specific code to hosted/<branch-name> folder. |
| 78 | + It then executes the build command and copy the built site to apps folder |
| 79 | + under the same branch name |
| 80 | + :return: PR numbers in str list where the site data is copied to |
| 81 | + """ |
| 82 | + delete_folders(["branch", "app"]) |
| 83 | + |
| 84 | + command = ["gh", "pr", "list", "--json", "number,headRefName"] |
| 85 | + command_run_result = subprocess.run(command, capture_output=True, text=True).stdout.strip() |
| 86 | + branches_data = ast.literal_eval(command_run_result) |
| 87 | + remote_url = subprocess.run(["git", "remote", "get-url", "origin"], |
| 88 | + capture_output=True, |
| 89 | + text=True).stdout.strip() |
| 90 | + parent_dir = os.getcwd() |
| 91 | + clone_data_to_branch_folder("dev", remote_url, parent_dir, "dev") |
| 92 | + pr_numbers = [] |
| 93 | + for branch_data in branches_data: |
| 94 | + if not branch_data["headRefName"].startswith("hosted/"): |
| 95 | + continue |
| 96 | + pr_number = str(branch_data["number"]) |
| 97 | + clone_data_to_branch_folder(branch_data["headRefName"], remote_url, parent_dir, pr_number) |
| 98 | + pr_numbers.append(pr_number) |
| 99 | + |
| 100 | + return pr_numbers |
| 101 | + |
| 102 | +def update_nginx_config(pr_numbers): |
| 103 | + """ |
| 104 | + Updates nginx.conf file with branches built information to host multiple versions |
| 105 | + of software at the same time. |
| 106 | + :param pr_numbers: pr numbers a str list of open pr numbers to be hosted |
| 107 | + """ |
| 108 | + config_file = os.path.join(os.getcwd(), "nginx.conf") |
| 109 | + nginx_location_blocks = "" |
| 110 | + |
| 111 | + for pr_number in pr_numbers: |
| 112 | + location_block = f"""location /{pr_number} {{ |
| 113 | + alias /app/{pr_number}; |
| 114 | + try_files $uri $uri/ /index.html; |
| 115 | + error_page 404 /404.html; |
| 116 | + }} |
| 117 | + """ |
| 118 | + nginx_location_blocks += location_block |
| 119 | + |
| 120 | + with open(config_file, "r+") as f: |
| 121 | + content = f.read() |
| 122 | + content = content.replace("#REPLACE_APPS", nginx_location_blocks) |
| 123 | + f.seek(0) |
| 124 | + f.write(content) |
| 125 | + f.truncate() |
| 126 | + |
| 127 | + print("NGINX configuration updated successfully!") |
| 128 | + |
| 129 | +if __name__ == "__main__": |
| 130 | + current_dir = os.getcwd() |
| 131 | + pr_numbers = process_branch_folders() |
| 132 | + update_nginx_config(pr_numbers) |
0 commit comments