test_submodules.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. # SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Apache-2.0
  3. import os
  4. from subprocess import run
  5. from typing import Dict, List
  6. def run_cmd(cmd: List[str]) -> str:
  7. """Simple helper to run command and return it's stdout."""
  8. proc = run(cmd, capture_output=True, check=True, text=True)
  9. return proc.stdout.strip()
  10. def get_gitwdir() -> str:
  11. """Return absolute path to the current git working tree."""
  12. return run_cmd(['git', 'rev-parse', '--show-toplevel'])
  13. def get_submodules_config() -> Dict[str,Dict[str,str]]:
  14. """Return dictionary, where key is submodule name and value
  15. is a dictionary with variable:value pairs."""
  16. gitmodules_fn = os.path.join(get_gitwdir(), '.gitmodules')
  17. gitmodules_data = run_cmd(['git', 'config', '--list', '--file', gitmodules_fn])
  18. prefix = 'submodule.'
  19. config: Dict[str, Dict[str,str]] = {}
  20. for line in gitmodules_data.splitlines():
  21. if not line.startswith(prefix):
  22. continue
  23. splitted = line.split('=', maxsplit=1)
  24. if len(splitted) != 2:
  25. continue
  26. section, val = splitted
  27. # remove "submodule." prefix
  28. section = section[len(prefix):]
  29. # split section into module name and variable
  30. splitted = section.rsplit('.', maxsplit=1)
  31. if len(splitted) != 2:
  32. continue
  33. module_name, var = splitted
  34. if module_name not in config:
  35. config[module_name] = {}
  36. config[module_name][var] = val
  37. return config
  38. def test_sha() -> None:
  39. """ Check that submodule SHA in git-tree and .gitmodules match
  40. if sbom-hash variable is available in the .gitmodules file.
  41. """
  42. submodules = get_submodules_config()
  43. for name, variables in submodules.items():
  44. sbom_hash = variables.get('sbom-hash')
  45. if not sbom_hash:
  46. continue
  47. module_path = variables.get('path')
  48. if not module_path:
  49. continue
  50. output = run_cmd(['git', 'ls-tree', 'HEAD', module_path])
  51. if not output:
  52. continue
  53. module_hash = output.split()[2]
  54. msg = (f'Submodule \"{name}\" SHA \"{module_hash}\" in git '
  55. f'tree does not match SHA \"{sbom_hash}\" recorded in .gitmodules. '
  56. f'Please update \"sbom-hash\" in .gitmodules for \"{name}\" '
  57. f'and also please do not forget to update version and other submodule '
  58. f'information if necessary. It is important to keep this information '
  59. f'up-to-date for SBOM generation.')
  60. assert module_hash == sbom_hash, msg
  61. if __name__ == '__main__':
  62. test_sha()