@@ -58,36 +58,61 @@ def run(self, args: argparse.Namespace) -> int:
5858
5959 logger .info (f"Running black against { package_name } " )
6060
61- if in_ci ():
61+ check_only = in_ci () != 0
62+
63+ if check_only :
6264 if not is_check_enabled (package_dir , "black" , default = False ):
6365 logger .info (f"Package { package_name } opts-out of black check." )
6466 continue
6567
66- result = self .format_directory (executable , package_dir )
68+ result = self .format_directory (executable , package_dir , check_only = check_only )
6769 if result is None :
68- # install or formatting failed, already logged
6970 results .append (1 )
7071 continue
7172
72- if result .stderr and "reformatted" in result .stderr .decode ("utf-8" ):
73- if in_ci ():
73+ stderr_text = result .stderr .decode ("utf-8" ) if result .stderr else ""
74+ stdout_text = result .stdout .decode ("utf-8" ) if result .stdout else ""
75+
76+ has_issues = result .returncode != 0 if check_only else "reformatted" in stderr_text
77+
78+ if has_issues :
79+ if check_only and result .returncode > 1 :
80+ logger .error (f"Black failed for { package_name } (exit code { result .returncode } )." )
81+ if stderr_text .strip ():
82+ logger .error (f"Black stderr:\n { stderr_text } " )
83+ results .append (result .returncode )
84+ elif check_only :
7485 logger .info (
75- f"The package { package_name } needs reformat. Run `azpysdk black .` locally from the package root to reformat."
86+ f"The package { package_name } has black formatting issues. "
87+ f"Run `azpysdk black .` locally from the package root to reformat."
7688 )
89+ if stdout_text .strip ():
90+ logger .info (f"Black diff output:\n { stdout_text } " )
91+ if stderr_text .strip ():
92+ logger .info (f"Black summary:\n { stderr_text } " )
7793 results .append (1 )
7894 else :
7995 logger .info (f"The package { package_name } was reformatted." )
96+ if stdout_text .strip ():
97+ logger .info (f"Black diff output:\n { stdout_text } " )
98+ if stderr_text .strip ():
99+ logger .info (f"Black summary:\n { stderr_text } " )
80100 else :
81101 logger .info (f"The package { package_name } is properly formatted, no files changed." )
82102
83103 return max (results ) if results else 0
84104
85105 @staticmethod
86- def format_directory (executable : str , target_dir : str ) -> Optional [subprocess .CompletedProcess ]:
106+ def format_directory (
107+ executable : str , target_dir : str , check_only : bool = False
108+ ) -> Optional [subprocess .CompletedProcess ]:
87109 """Run black on *target_dir* using the repo-wide config.
88110
89111 Installs the pinned black version into the environment of *executable*,
90112 then formats all Python files under *target_dir*.
113+
114+ When *check_only* is True, runs with ``--check --diff`` to report
115+ issues without modifying files.
91116 """
92117 try :
93118 install_into_venv (executable , [f"black=={ BLACK_VERSION } " ], target_dir )
@@ -96,12 +121,18 @@ def format_directory(executable: str, target_dir: str) -> Optional[subprocess.Co
96121 return None
97122
98123 config_file_location = os .path .join (REPO_ROOT , "eng/black-pyproject.toml" )
124+ cmd = [executable , "-m" , "black" , f"--config={ config_file_location } " ]
125+ if check_only :
126+ cmd .append ("--check" )
127+ cmd .append ("--diff" )
128+ cmd .append (target_dir )
129+
99130 try :
100131 return subprocess .run (
101- [ executable , "-m" , "black" , f"--config= { config_file_location } " , target_dir ] ,
132+ cmd ,
102133 stdout = subprocess .PIPE ,
103134 stderr = subprocess .PIPE ,
104- check = True ,
135+ check = not check_only ,
105136 )
106137 except subprocess .CalledProcessError as e :
107138 logger .error (f"Black formatting failed for { target_dir } : { e } " )
0 commit comments