From 953230ccc1f0e520612bdccfe5eb70f93a711d46 Mon Sep 17 00:00:00 2001 From: Martin Leduc <31558169+DecimalTurn@users.noreply.github.com> Date: Mon, 17 Jun 2024 01:00:23 -0400 Subject: [PATCH] Add action --- README.md | 23 ++++++++++++++++ action.yml | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ enforce-crlf.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 action.yml create mode 100644 enforce-crlf.py diff --git a/README.md b/README.md index 61c59c2..edc3437 100644 --- a/README.md +++ b/README.md @@ -1 +1,24 @@ A simple GitHub Action to enforce CRLF on selected files in your repo. + +Example worflow: +```yml +name: Enforce-CRLF + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: write + +jobs: + enforce-crlf: + runs-on: ubuntu-latest + steps: + - name: Enforce CRLF action + uses: DecimalTurn/Enforce-CRLF@main + with: + extensions: .bas, .frm, .cls +``` diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..f5478d5 --- /dev/null +++ b/action.yml @@ -0,0 +1,69 @@ +name: Enforce-CRLF +description: 'Enforce CRLF.' +branding: + icon: "corner-down-left" + color: "blue" +inputs: + extensions: + description: 'List of extensions (including the dot) seperated by a comma.' + required: true + bot-name: + description: 'Name of the bot that will perform the commit.' + default: 'github-actions[bot]' + bot-email: + description: 'Email of the bot that will perform the commit.' + default: '41898282+github-actions[bot]@users.noreply.github.com' +runs: + using: "composite" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Get tofrodos package + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: tofrodos + version: 1.0 + - name: Run script + run: | + python '${{ github.action_path }}/enforce-crlf.py' "${{ inputs.extensions }}" + shell: bash + - name: Push content + uses: stefanzweifel/git-auto-commit-action@v5 + with: + # Optional. Commit message for the created commit. + # Defaults to "Apply automatic changes" + commit_message: "Enforce CRLF\n\nGitHub Action: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + # Optional commit user and author settings + commit_user_name: ${{ inputs.bot-name }} # defaults to "github-actions[bot]" + commit_user_email: ${{ inputs.bot-email }} # defaults to "41898282+github-actions[bot]@users.noreply.github.com" + + # Alternative approach to Push content using a bash script + # - name: Push content + # run: | + # git config user.name "${{ inputs.bot-name }}" + # git config user.email "${{ inputs.bot-email }}" + + # # Create an array of extensions + # IFS=',' read -r -a extensions <<< "${{ inputs.extensions }}" + + # # Add files with the specified extensions + # for ext in "${extensions[@]}"; do + # trimmed_ext=$(echo "$ext" | xargs) # Trim spaces + # echo "Adding files with extension: *$trimmed_ext" + # git add -v *"$trimmed_ext" || true + # done + + # git status + # if [ -n "$(git diff --cached --exit-code)" ]; then + # echo "Changes detected" + # commit_message=$(printf "Enforce CRLF\n\nGitHub Action: %s/%s/actions/runs/%s" "${{ github.server_url }}" "${{ github.repository }}" "${{ github.run_id }}") + # git commit -m "$commit_message" + # git push --set-upstream origin $branch_name + # else + # echo "No changes to commit" + # fi + # shell: bash diff --git a/enforce-crlf.py b/enforce-crlf.py new file mode 100644 index 0000000..92b5d6c --- /dev/null +++ b/enforce-crlf.py @@ -0,0 +1,70 @@ +import os +import argparse +import sys +import subprocess + +def needs_conversion_to_crlf(filepath): + file_info = subprocess.check_output(['file', filepath], universal_newlines=True) + if ", with no line terminators" in file_info or file_info.endswith("empty\n"): + return False + return ", with CRLF line terminators" not in file_info + +def convert_lf_to_crlf(filepath): + try: + # Use the subprocess module to run the todos (aka. unix2dos) command + print(f"🟡 {filepath} needs line endings replacement") + subprocess.run(["todos", filepath], check=True) + print(f" 🟢 {filepath} had there line endings replaced") + except subprocess.CalledProcessError as e: + print(f"🔴 {filepath} returned an error while converting: {e}") + sys.exit(1) + except FileNotFoundError: + print("⚠ Error: todos command not found. Make sure it's installed and in your PATH.") + sys.exit(1) + +def copy_file(source, destination): + try: + # Ensure the destination directory exists + destination_dir = os.path.dirname(destination) + if not os.path.exists(destination_dir): + os.makedirs(destination_dir) + + # Open the source file for reading + with open(source, 'rb') as source_file: + # Create the destination file and write the contents of the source file to it + with open(destination, 'wb') as destination_file: + destination_file.write(source_file.read()) + print(f"File '{source}' copied to '{destination}' successfully.") + except Exception as e: + print(f"An error occurred while copying the file: {e}") + +def main(extensions): + repo_dir = "/home/runner/work/" + # Split the extensions string into a list and strip whitespace + extensions_list = tuple(ext.strip() for ext in extensions.split(',')) + files = [] + for root, _, filenames in os.walk(repo_dir): + for filename in filenames: + if filename.endswith(extensions_list): + filepath = os.path.join(root, filename) + files.append(filepath) + + eol_result = needs_conversion_to_crlf(filepath) + if eol_result: + convert_lf_to_crlf(filepath) + else: + print(f"🟢 {filepath} has correct line endings") + + if not files: + print("No files with the specified extensions found in the repository.") + else: + print(f"Found {len(files)} file(s) with the specified extensions.") + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Process files with specified extensions in a directory.") + parser.add_argument('extensions', type=str, help='Comma-separated list of file extensions to process') + return parser.parse_args() + +if __name__ == "__main__": + args = parse_arguments() + main(args.extensions)