go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/scripts/check_go_mod_tidy.py (about)

     1  #!/usr/bin/env python3
     2  # Copyright 2021 The LUCI Authors.
     3  #
     4  # Licensed under the Apache License, Version 2.0 (the "License");
     5  # you may not use this file except in compliance with the License.
     6  # You may obtain a copy of the License at
     7  #
     8  #      http://www.apache.org/licenses/LICENSE-2.0
     9  #
    10  # Unless required by applicable law or agreed to in writing, software
    11  # distributed under the License is distributed on an "AS IS" BASIS,
    12  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  # See the License for the specific language governing permissions and
    14  # limitations under the License.
    15  
    16  from __future__ import absolute_import
    17  from __future__ import print_function
    18  
    19  import os
    20  import shutil
    21  import subprocess
    22  import sys
    23  
    24  
    25  # A list of (original file, what to rename it to prior to a check).
    26  MOD_FILES = [
    27      ('go.mod', '.go.mod.current'),
    28      ('go.sum', '.go.sum.current'),
    29  ]
    30  
    31  
    32  def main(args):
    33    if len(args) != 1:
    34      print('Want 1 argument: a path to a directory with go.mod')
    35      return 1
    36    os.chdir(args[0])
    37  
    38    # Backup existing go.mod and go.sum since we possibly will modify them.
    39    for old, new in MOD_FILES:
    40      shutil.copyfile(old, new)
    41  
    42    try:
    43      # This command modifies go.mod and/or go.sum if they are untidy. There's
    44      # currently no way to ask it to check their tidiness without overriding
    45      # them. See https://github.com/golang/go/issues/27005.
    46      subprocess.check_call(['go', 'mod', 'tidy'])
    47  
    48      # Check the diff, it should be empty.
    49      for old, new in MOD_FILES:
    50        mod_diff = diff(new, old)
    51        if mod_diff:
    52          print('%s file is stale:' % old)
    53          print(mod_diff)
    54          print()
    55          print('Run "go mod tidy" to update it.')
    56          return 1
    57  
    58    except subprocess.CalledProcessError as exc:
    59      print(
    60          'Failed to call %s, return code %d:\n%s' %
    61          (exc.cmd, exc.returncode, exc.output))
    62      return 2
    63  
    64    finally:
    65      for old, new in MOD_FILES:
    66        shutil.move(new, old)
    67  
    68  
    69  def diff(a, b):
    70    cmd = ['git', 'diff', '--no-index', a, b]
    71    proc = subprocess.Popen(
    72        args=cmd,
    73        stdout=subprocess.PIPE,
    74        stderr=subprocess.PIPE,
    75        universal_newlines=True)
    76    out, err = proc.communicate()
    77    if proc.returncode and err:
    78      raise subprocess.CalledProcessError(
    79          returncode=proc.returncode, cmd=cmd, output=err)
    80    return out.strip()
    81  
    82  
    83  if __name__ == '__main__':
    84    sys.exit(main(sys.argv[1:]))