Automate Local Environment Setup for Your Monorepo with a Python Script

TL;DR: This guide shows you how to automate the setup of .env.example and .json.example files in a monorepo using a Python script. The script copies template files, prompts for user input to fill in placeholders, and skips files that are already set up.

Thank me by sharing on Twitter 🙏

Introduction

Managing environment variables is crucial for any development project. These variables allow us to configure our applications for different environments without changing the code. However, setting up these variables manually for multiple projects in a monorepo can be tedious. In this post, I’ll share a solution I developed to automate this process using Python. We’ll create a script that copies template files, prompts for user input to fill in placeholder values, and skips files that are already set up.

Why Automate Environment Setup?

In a monorepo, where multiple projects share the same repository, keeping track of environment variables can become complicated. Each project might have its own set of configuration files, often with placeholders for sensitive information like database passwords or API keys. Manually updating these files can lead to inconsistencies and potential security risks if not handled properly. Automating this process ensures that all required variables are set up correctly and uniformly across all projects.

Setting Up the Python Script

Let’s break down the process into manageable steps. We’ll cover:

  1. Defining the root folders and file types to search for.
  2. Prompting the user for values to replace placeholders in the configuration files.
  3. Copying template files and replacing placeholders with the user-provided values.
  4. Skipping files that are already set up to avoid unnecessary prompts and overwrites.

1. Defining Root Folders and File Types

First, we need to specify the root folders where our configuration files are located and the types of files we want to process. In my case, these were .env.example and .json.example files. Here’s how I defined them in Python:

Python
import os
import re
import shutil

ROOT_FOLDERS = ['project1', 'project2', 'project3']
FILE_SUFFIXES = ['.env.example', '.json.example']

2. Prompting for Values

Next, we need a way to prompt the user for values to replace placeholders in our configuration files. To ensure consistency, we’ll store these values in a dictionary and reuse them when the same placeholder appears in different files.

Python
# Dictionary to store values for placeholders
values = {}

def prompt_for_value(value_name):
    if value_name in values:
        return values[value_name]
    value = input(f"Please enter the value for {value_name}: ")
    values[value_name] = value
    return value

3. Copying and Processing Files

With our folders and file types defined, and a function to prompt for values, we can now copy the template files to their respective locations and replace placeholders. We’ll also handle file skipping to avoid overwriting existing files.

Python
def process_file(file_path):
    with open(file_path, 'r') as file:
        content = file.read()

    placeholders = re.findall(r'\${([^}]+)}', content)
    unique_placeholders = set(placeholders)

    for placeholder in unique_placeholders:
        value = prompt_for_value(placeholder)
        content = content.replace(f"${{{placeholder}}}", value)

    with open(file_path, 'w') as file:
        file.write(content)

def setup_environment():
    for folder in ROOT_FOLDERS:
        if not os.path.isdir(folder):
            print(f"Folder {folder} does not exist.")
            continue

        matching_files_found = False
        for file in os.listdir(folder):
            if any(file.endswith(suffix) for suffix in FILE_SUFFIXES):
                matching_files_found = True
                example_path = os.path.join(folder, file)
                output_path = os.path.join(folder, file.replace('.example', ''))

                if os.path.exists(output_path):
                    print(f"Skipping {output_path} as it already exists.")
                    continue

                shutil.copy(example_path, output_path)
                print(f"Processing {output_path}")
                process_file(output_path)
                print(f"{output_path} file created with entered values.")

        if not matching_files_found:
            print(f"No matching example files found in {folder}")

if __name__ == '__main__':
    setup_environment()

4. Running the Script

To run the setup, navigate to the root directory of your monorepo and execute the following command:

ShellScript
python setup_env.py

This script will copy the .env.example and .json.example files to their respective non-example versions in each specified root folder, find all placeholders, prompt the user to enter the values for each placeholder (reusing values when appropriate), and replace the placeholders with the entered values. It will skip any output files that already exist and print a message indicating that they were skipped.

Conclusion

Automating the setup of environment variables in a monorepo can significantly streamline your development process. By creating a Python script to handle this task, you ensure consistency and reduce the potential for errors. The script I’ve shared can be easily adapted to suit the specific needs of your projects, making it a versatile tool in your development toolkit.

Implementing this automation has saved me a lot of time and hassle, and I hope it does the same for you. Happy developing!

Share this:

Leave a Reply