skip to Main Content

I am trying to write a job that would lint only the changed files, on a push or pull request.
I succeeded in writing a job that retrieves the changed files but when I am passing the list of files to the lint step, it is being skipped.
I on purpose changing a bunch of files.
The code looks like this:

name: Lint Changed Files

on: [push, pull_request]

jobs:
  changed_files:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Get list of added and modified files
        id: changed-files
        uses: tj-actions/changed-files@v39

      - name: Echo changed files
        run: |
          echo "Changed Files: ${{ steps.changed-files.outputs.all_changed_files }}" 

  lint:
    needs: [changed_files]
    runs-on: ubuntu-latest
    steps:
    - name: Lint Python scripts
      if: endsWith(needs.changed_files.outputs.all_changed_files, '.py')
      run: |
        pip install flake8
        echo "${{ needs.changed_files.outputs.all_changed_files }}" | tr ' ' 'n' | grep \.py$ | xargs flake8

    - name: Lint shell scripts
      if: endsWith(needs.changed_files.outputs.all_changed_files, '.sh')
      run: |
        sudo apt-get install shellcheck
        echo "${{ needs.changed_files.outputs.all_changed_files }}" | tr ' ' 'n' | grep \.sh$ | xargs shellcheck

    - name: Lint YAML files
      if: endsWith(needs.changed_files.outputs.all_changed_files, 'yaml')
      run: |
        pip install yamllint
        echo "${{ needs.changed_files.outputs.all_changed_files }}" | tr ' ' 'n' | grep \.y[a]?ml$ | xargs yamllint

Can the ‘startsWith’ handle a list of strings (in this case, filenames)?
And if not, what is the best way of doing so?
Thank you!

2

Answers


  1. The startsWith function in GitHub Actions does not handle a list of strings.
    It is designed to check if a single string starts with another specified string.

    You are using the endsWith function, but it operates under a similar principle as startsWith, checking if a single string ends with a specified substring.

    The current approach of using endsWith to check if any of the changed files end with a specific extension (e.g., .py, .sh, yaml) will not work as intended since needs.changed_files.outputs.all_changed_files is a single string containing a space-separated list of all changed files, and endsWith will only check the end of this entire string.


    A better approach would be to use a shell command to process the list of changed files and determine if any of the files have the desired extension:

    name: Lint Changed Files
    
    on: [push, pull_request]
    
    jobs:
      changed_files:
        runs-on: ubuntu-latest
    
        steps:
          - name: Checkout code
            uses: actions/checkout@v2
            with:
              fetch-depth: 0
    
          - name: Get list of added and modified files
            id: changed-files
            uses: tj-actions/changed-files@v39
    
          - name: Echo changed files
            run: |
              echo "Changed Files: ${{ steps.changed-files.outputs.all_changed_files }}" 
    
      lint:
        needs: [changed_files]
        runs-on: ubuntu-latest
        steps:
        - name: Check for Python files
          id: check-python
          run: |
            echo "::set-output name=python::$(echo "${{ needs.changed_files.outputs.all_changed_files }}" | grep -q \.py && echo true || echo false)"
        
        - name: Lint Python scripts
          if: steps.check-python.outputs.python == 'true'
          run: |
            pip install flake8
            echo "${{ needs.changed_files.outputs.all_changed_files }}" | tr ' ' 'n' | grep \.py$ | xargs flake8
    
        - name: Check for Shell files
          id: check-shell
          run: |
            echo "::set-output name=shell::$(echo "${{ needs.changed_files.outputs.all_changed_files }}" | grep -q \.sh && echo true || echo false)"
        
        - name: Lint shell scripts
          if: steps.check-shell.outputs.shell == 'true'
          run: |
            sudo apt-get install shellcheck
            echo "${{ needs.changed_files.outputs.all_changed_files }}" | tr ' ' 'n' | grep \.sh$ | xargs shellcheck
        
        - name: Check for YAML files
          id: check-yaml
          run: |
            echo "::set-output name=yaml::$(echo "${{ needs.changed_files.outputs.all_changed_files }}" | grep -q \.y[a]?ml && echo true || echo false)"
    
        - name: Lint YAML files
          if: steps.check-yaml.outputs.yaml == 'true'
          run: |
            pip install yamllint
            echo "${{ needs.changed_files.outputs.all_changed_files }}" | tr ' ' 'n' | grep \.y[a]?ml$ | xargs yamllint
    

    You would now have separate steps added, to check for the presence of files with each of the desired extensions.
    These steps use the grep command to search for the extensions in the list of changed files, and set an output variable to true if any files with the extension are found.
    The if conditions for the linting steps have been updated to check these output variables, so the linting steps will only run if there are files with the corresponding extensions among the changed files.

    Login or Signup to reply.
  2. tj-actions/changed-files already provides a files input parameter that you can use for this filtering.

    Example:

    name: changed_files_test
    
    on: workflow_dispatch
    
    jobs:
      changed-files:
        runs-on: ubuntu-latest
    
        outputs:
          py: ${{ steps.changed-files-py.outputs.all_changed_files }}
          sh: ${{ steps.changed-files-sh.outputs.all_changed_files }}
          yaml: ${{ steps.changed-files-yaml.outputs.all_changed_files }}
    
        steps:
          - name: Checkout
            uses: actions/checkout@v4
            with:
              fetch-depth: 0
    
          - name: Changed files (c)
            id: changed-files-py
            uses: tj-actions/changed-files@v39
            with:
              files: '**.py'
    
          - name: Changed files (js)
            id: changed-files-sh
            uses: tj-actions/changed-files@v39
            with:
              files: '**.sh'
    
          - name: Changed files (sh)
            id: changed-files-yaml
            uses: tj-actions/changed-files@v39
            with:
              files: |
                **.yml
                **.yaml
    
      lint:
        runs-on: ubuntu-latest
        needs: [changed-files]
    
        steps:
          - name: Lint (py)
            if: ${{ needs.changed-files.outputs.py }}
            run: flake8 ${{ needs.changed-files.outputs.py }}
    
          - name: Lint (sh)
            if: ${{ needs.changed-files.outputs.sh }}
            run: shellcheck ${{ needs.changed-files.outputs.sh }}
    
          - name: Lint (yaml)
            if: ${{ needs.changed-files.outputs.yaml }}
            run: yamllint ${{ needs.changed-files.outputs.yaml }}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search