koji_build.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #!/usr/bin/env python3
  2. import argparse
  3. import os
  4. import subprocess
  5. import re
  6. def check_dir(dirpath):
  7. if not os.path.isdir(dirpath):
  8. raise Exception("Directory %s doesn't exist" % dirpath)
  9. return dirpath
  10. def check_git_repo(dirpath):
  11. cwd = os.getcwd()
  12. os.chdir(dirpath)
  13. # check that the working copy is a working directory and is clean
  14. try:
  15. subprocess.check_call(['git', 'diff-index', '--quiet', 'HEAD', '--'])
  16. ret = True
  17. except:
  18. ret = False
  19. os.chdir(cwd)
  20. return ret
  21. def get_repo_and_commit_info(dirpath):
  22. cwd = os.getcwd()
  23. os.chdir(dirpath)
  24. remote = subprocess.check_output(['git', 'config', '--get', 'remote.origin.url']).decode().strip()
  25. # We want the exact hash for accurate build history
  26. hash = subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode().strip()
  27. os.chdir(cwd)
  28. return remote, hash
  29. def koji_url(remote, hash):
  30. if remote.startswith('git@'):
  31. remote = re.sub(r'git@(.+):', r'git+https://\1/', remote)
  32. elif remote.startswith('https://'):
  33. remote = 'git+' + remote
  34. else:
  35. raise Exception("Unrecognized remote URL")
  36. return remote + "?#" + hash
  37. def main():
  38. parser = argparse.ArgumentParser(description='Build a package or chain-build several from local git repos for RPM sources')
  39. parser.add_argument('target', help='Koji target for the build')
  40. parser.add_argument('git_repos', nargs='+',
  41. help='local path to one or more git repositories. If several are provided, '
  42. 'a chained build will be started in the order of the arguments')
  43. parser.add_argument('--scratch', action="store_true", help='Perform scratch build')
  44. parser.add_argument('--nowait', action="store_true", help='Do not wait for the build to end')
  45. args = parser.parse_args()
  46. target = args.target
  47. git_repos = [os.path.abspath(check_dir(d)) for d in args.git_repos]
  48. is_scratch = args.scratch
  49. is_nowait = args.nowait
  50. if len(git_repos) > 1 and is_scratch:
  51. parser.error("--scratch is not compatible with chained builds.")
  52. for d in git_repos:
  53. if not check_git_repo(d):
  54. parser.error("%s is not in a clean state (or is not a git repository)." % d)
  55. if len(git_repos) == 1:
  56. remote, hash = get_repo_and_commit_info(git_repos[0])
  57. url = koji_url(remote, hash)
  58. command = ['koji', 'build'] + (['--scratch'] if is_scratch else []) + [target, url] + (['--nowait'] if is_nowait else [])
  59. subprocess.check_call(['echo'] + command)
  60. subprocess.check_call(command)
  61. else:
  62. urls = []
  63. for d in git_repos:
  64. remote, hash = get_repo_and_commit_info(d)
  65. urls.append(koji_url(remote, hash))
  66. command = ['koji', 'chain-build', target] + (' : '.join(urls)).split(' ') + (['--nowait'] if is_nowait else [])
  67. subprocess.check_call(['echo'] + command)
  68. subprocess.check_call(command)
  69. if __name__ == "__main__":
  70. main()