GitLab CI Python black formatter says: would reformat, whereas running black does not reformat

Question:

When I run GitLab CI on this commit

with this gitlab-ci.yml:

stages:
    - format
    - test

black_formatting:
  image: python:3.6
  stage: format
  
  before_script:
    # Perform an update to make sure the system is up to date.
    - sudo apt-get update --fix-missing
    # Download miniconda.
    - wget -q https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; bash miniconda.sh -b -f -p $HOME/miniconda;
    # Ensure the (mini) conda environment can be activated.
    - export PATH="$HOME/miniconda/bin:$PATH"
    # (Re)create the environment.yml file for the repository.
    - conda env create -q -f environment.yml -n checkstyle-for-bash --force
    # Activate the environment of the repository.
    - source activate checkstyle-for-bash

  script:
    # Verify the Python code is black formatting compliant.
    - black . --check --exclude '.venv/|.local/|.cache/|.git/'
    # Verify the Python code is flake8 formatting compliant.
    - flake8 .
  allow_failure: false


test:pytest:36:
  stage: test
  image: python:3.6
  script:
    # Ensure the (mini) conda environment can be activated.
    - export PATH="$HOME/miniconda/bin:$PATH"
    # Activate the environment of the repository.
    - source activate checkstyle-for-bash
    # Run the python tests.
    - python -m pytest

it outputs:

Running with gitlab-runner 14.8.0 (565b6c0b)
  on trucolrunner DS42qHSq
Preparing the "shell" executor
00:00
Using Shell executor...
Preparing environment
00:00
Running on pcname...
Getting source from Git repository
00:02
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /home/gitlab-runner/builds/DS42qHSq/0/root/checkstyle-for-bash/.git/
Checking out 001577c3 as main...
Removing miniconda.sh
Skipping Git submodules setup
Executing "step_script" stage of the job script
02:55
$ sudo apt-get update --fix-missing
Hit:1 http://nl.archive.ubuntu.com/ubuntu impish InRelease
Get:2 http://security.ubuntu.com/ubuntu impish-security InRelease [110 kB]
Get:3 http://nl.archive.ubuntu.com/ubuntu impish-updates InRelease [115 kB]
Hit:4 https://repo.nordvpn.com/deb/nordvpn/debian stable InRelease
Get:5 http://nl.archive.ubuntu.com/ubuntu impish-backports InRelease [101 kB]
Hit:6 https://brave-browser-apt-release.s3.brave.com stable InRelease
Get:7 http://security.ubuntu.com/ubuntu impish-security/main amd64 DEP-11 Metadata [20,3 kB]
Get:8 http://security.ubuntu.com/ubuntu impish-security/universe amd64 DEP-11 Metadata [3.624 B]
Get:9 http://nl.archive.ubuntu.com/ubuntu impish-updates/main amd64 DEP-11 Metadata [25,8 kB]
Get:10 http://nl.archive.ubuntu.com/ubuntu impish-updates/universe amd64 DEP-11 Metadata [35,4 kB]
Get:11 http://nl.archive.ubuntu.com/ubuntu impish-updates/multiverse amd64 DEP-11 Metadata [940 B]
Get:12 http://nl.archive.ubuntu.com/ubuntu impish-backports/universe amd64 DEP-11 Metadata [16,4 kB]
Fetched 428 kB in 2s (235 kB/s)
Reading package lists...
$ wget -q https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; bash miniconda.sh -b -f -p $HOME/miniconda;
PREFIX=/home/gitlab-runner/miniconda
Unpacking payload ...
Collecting package metadata (current_repodata.json): ...working... done
Solving environment: ...working... done
# All requested packages already installed.
installation finished.
$ export PATH="$HOME/miniconda/bin:$PATH"
$ conda env create -q -f environment.yml -n checkstyle-for-bash --force
Collecting package metadata (repodata.json): ...working... done
Solving environment: ...working... done
Preparing transaction: ...working... done
Verifying transaction: ...working... done
Executing transaction: ...working... done
Installing pip dependencies: ...working... done
$ source activate checkstyle-for-bash
$ black . --check --exclude '.venv/|.local/|.cache/|.git/'
would reformat src/arg_parser.py
would reformat src/helper_text_parsing.py
Oh no!      
2 files would be reformatted, 10 files would be left unchanged.
ERROR: Job failed: exit status 1

However, if I run black src/** on the GitHub repository, black returns:

~/git/checkstyle-for-bash$ git pull
Already up to date.
(base) some@name:~/git/checkstyle-for-bash$ black src/**
All done! ✨   ✨
8 files left unchanged.

Just in case I did not clone the right repository, I also manually copy-pasted the content of the src/arg_parser.py file from GitLab into ~/git/checkstyle-for-bash/src/arg_parser.py and ran black again. However, the output is the same, it does not change anything.

For completeness, this is the content of the src/arg_parser.py file:

# This is the main code of this project nr, and it manages running the code and
# outputting the results to LaTex.
import argparse


def parse_cli_args():
    # Instantiate the parser
    parser = argparse.ArgumentParser(description="Optional app description")

    # Include argument parsing for default code.
    # Allow user to load a graph from file.
    parser.add_argument(
        "--ggl",
        dest="google_style_guide",
        action="store_true",
        help=(
            "boolean flag, determines whether the Google Style Guide for "
            "Bash rules are followed."
        ),
    )

    # Allow user to specify an infile.
    parser.add_argument("infile", nargs="?", type=argparse.FileType("r"))

    # Specify default argument values for the parser.
    parser.set_defaults(google_style_guide=True,)

    # Load the arguments that are given.
    args = parser.parse_args()
    return args

Question

What could be causing the GitLab CI to say the files would be reformatted by black (even though the files are not reformatted when running black on them (on the same device (in a different conda environment)))?

Setup

I run my own GitLab CI on the same device on which I test the conda black commands. The GitLab CI copies the GitHub commits of a repository, one at a time, runs its CI on it, and then reports the results back to GitHub.

I am currently not able to expose my GitLab server on clearnet as I am behind a gateway that I currently do not control.

Doubts

I am fairly certain it is a "silly" mistake from my side, however I have not yet been able to figure out what it is. Especially since I manually copy pasted the GitLab file content of the src/arg_parser.py file twice, and ran black twice to verify black indeed does not change "that" file. Also, to be sure it was not a trailing newline or anything, I used the copy button with the mouse, instead of manual selection:
enter image description here

Additionally, the file is flake8 compliant. My current guess is that somehow the CI is not ran on the most recent commit of that repository. However, to verify that I clicked on the GitLab of the failed commit, which indeed redirects to the "05e85fd54f93ccfc427023b21f9cdb0c0cd6db2e" commit (copy) in GitLab:
enter image description here It is from this commit that I copy-pasted the src/arg_parser.py file twice.

Another guess would be that the gitlab-ci.yml loads a miniconda environment whereas my local version of black uses a full conda environment. Perhaps they have a different newline character that would lead to a formatting difference. (Even though I doubt that would be the case).

Issue

I ran the CI again whilst include the black . --diff command in the gitlab-ci.yml script, and the difference is between a:

''' Return

and:

'''Return

as is displayed in the accompanying output:

$ black . --diff --exclude '.venv/|.local/|.cache/|.git/'
--- src/arg_parser.py   2022-04-03 10:13:10.751289 +0000
+++ src/arg_parser.py   2022-04-03 11:11:26.297995 +0000
@@ -24,10 +24,12 @@
 
     # Allow user to specify an infile.
     parser.add_argument("infile", nargs="?", type=argparse.FileType("r"))
 
     # Specify default argument values for the parser.
-    parser.set_defaults(google_style_guide=True,)
+    parser.set_defaults(
+        google_style_guide=True,
+    )
 
     # Load the arguments that are given.
     args = parser.parse_args()
     return args
would reformat src/arg_parser.py
--- src/helper_text_parsing.py  2022-04-02 19:35:45.142619 +0000
+++ src/helper_text_parsing.py  2022-04-03 11:11:26.342908 +0000
@@ -5,11 +5,11 @@
 def add_two(x):
     return x + 2
 
 
 def get_function_line_nrs(filecontent, rules):
-    """ Returns two lists containing the starting and ending line numbers of
+    """Returns two lists containing the starting and ending line numbers of
     the functions respectively.
 
     :param filecontent: The content of the bash file that is being analysed.
     :param rules: The Bash formatting rules that are chosen by the user.
     """
would reformat src/helper_text_parsing.py
All done! ✨   ✨
2 files would be reformatted, 10 files would be left unchanged.

I am not quite sure exactly why this happens, as I thought python black would always converge to the exact same formatting for a given valid python file. I assume it is because two different black versions are used between the miniconda environment and the anaconda environment on the same device.

To test this hypothesis I am including a black --version command in the gitlab-ci.yml.

Asked By: a.t.

||

Answers:

The miniconda environment in the GitLab CI used python black version:

black, 22.3.0 (compiled: yes)

Whereas the local environment used python black version:

black, version 19.10b0

Updating the local black version, pushing the formatted code according to the latest python black version, and running the GitLab CI on that GitHub commit resulted in a successful GitLab CI run.

Answered By: a.t.

another way to ensure you have the version you want you can do e.g pip install black==22.1.0 in before_script.

Answered By: Jehona Kryeziu