deploy-release.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #!/usr/bin/env python3
  2. import argparse
  3. import json
  4. import os
  5. import re
  6. import shlex
  7. import stat
  8. import subprocess
  9. import sys
  10. from pathlib import Path
  11. from packaging import version as pv
  12. sys.path.append(str(Path(__file__).parent.parent))
  13. from tools.list_distros import generate_help
  14. from tools.reformat_readme import reformat_readme
  15. NEOFETCH_NEW_VERSION = ""
  16. def pre_check():
  17. """
  18. Check source code status before releasing.
  19. """
  20. assert os.path.isfile('./neofetch'), './neofetch doesn\'t exist, you are running this script in the wrong directory'
  21. assert os.stat('./neofetch').st_mode & stat.S_IEXEC, 'neofetch is not executable'
  22. assert os.path.islink('./hyfetch/scripts/neowofetch'), 'neowofetch is not a symbolic link'
  23. # subprocess.check_call(shlex.split('git diff-index --quiet HEAD --')) # 'Please commit all changes before release'
  24. subprocess.check_call(shlex.split('shellcheck neofetch'))
  25. def edit_versions(version: str):
  26. """
  27. Edit version numbers in hyfetch/constants.py, package.json, and README.md
  28. Also edits version number of neofetch, but the neofetch version number is separate.
  29. :param version: Version to release
  30. """
  31. # 1. package.json
  32. print('Editing package.json...')
  33. path = Path('package.json')
  34. content = json.loads(path.read_text())
  35. cur = pv.parse(content['version'])
  36. assert cur < pv.parse(version), 'Version did not increase'
  37. content['version'] = version
  38. path.write_text(json.dumps(content, ensure_ascii=False, indent=2))
  39. # 2. hyfetch/constants.py
  40. print('Editing hyfetch/constants.py...')
  41. path = Path('hyfetch/constants.py')
  42. content = [f"VERSION = '{version}'" if l.startswith('VERSION = ') else l for l in path.read_text().split('\n')]
  43. path.write_text('\n'.join(content))
  44. # 3. README.md
  45. print('Editing README.md...')
  46. path = Path('README.md')
  47. content = path.read_text()
  48. changelog_i = content.index('<!-- CHANGELOG STARTS HERE --->')
  49. version_i = content.index('###', changelog_i)
  50. version_end = content.index('\n', version_i)
  51. content = content[:version_i] + f'### {version}' + content[version_end:]
  52. path.write_text(content)
  53. # 4. neofetch script
  54. print('Editing neofetch...')
  55. path = Path('neofetch')
  56. lines = path.read_text().split('\n')
  57. version_i = next(i for i, l in enumerate(lines) if l.startswith('version='))
  58. nf = pv.parse(lines[version_i].replace('version=', ''))
  59. new = pv.parse(version)
  60. nf = f'{nf.major + new.major - cur.major}.{nf.minor + new.minor - cur.minor}.{nf.micro + new.micro - cur.micro}'
  61. lines[version_i] = f"version={nf}"
  62. path.write_text('\n'.join(lines))
  63. global NEOFETCH_NEW_VERSION
  64. NEOFETCH_NEW_VERSION = nf
  65. def finalize_neofetch():
  66. """
  67. Finalize current version
  68. """
  69. # 1. Update distro list
  70. print('Updating distro list in neofetch...')
  71. path = Path('neofetch')
  72. content = path.read_text()
  73. content = re.compile(r'(?<=# Flag: --ascii_distro\n#\n).*?(?=ascii_distro=)', re.DOTALL)\
  74. .sub(generate_help(100, '# ') + '\n', content)
  75. content = re.compile(r"""(?<=Which Distro's ascii art to print\n\n).*?{distro}_small to use them\.""", re.DOTALL)\
  76. .sub(generate_help(100, ' ' * 32), content)
  77. path.write_text(content)
  78. # 2. Regenerate man page
  79. print('Regenerating neofetch man page...')
  80. Path('neofetch.1').write_text(subprocess.check_output(['help2man', './neofetch']).decode())
  81. # 3. Reformat readme links
  82. print('Reformatting readme links...')
  83. reformat_readme()
  84. def post_check():
  85. """
  86. Check after changes are made
  87. """
  88. subprocess.check_call(shlex.split('shellcheck neofetch'))
  89. def create_release(v: str):
  90. """
  91. Create release commit and tag
  92. """
  93. print('Committing changes...')
  94. # 1. Add files
  95. subprocess.check_call(['git', 'add', 'hyfetch/constants.py', 'neofetch', 'neofetch.1', 'package.json', 'README.md'])
  96. # 2. Commit
  97. subprocess.check_call(['git', 'commit', '-m', f'[U] Release {v}'])
  98. # 3. Create tag
  99. subprocess.check_call(['git', 'tag', v])
  100. subprocess.check_call(['git', 'tag', f'neofetch-{NEOFETCH_NEW_VERSION}'])
  101. i = input('Please check the commit is correct. Press y to continue or any other key to cancel.')
  102. assert i == 'y'
  103. # 4. Push
  104. print('Pushing commits...')
  105. subprocess.check_call(['git', 'push'])
  106. subprocess.check_call(['git', 'push', 'origin', v])
  107. def deploy():
  108. """
  109. Deploy release to pip and npm
  110. """
  111. print('Deploying to pypi...')
  112. subprocess.check_call(['bash', 'tools/deploy.sh'])
  113. print('Done!')
  114. print('Deploying to npm...')
  115. otp = input('Please provide 2FA OTP for NPM: ')
  116. subprocess.check_call(['npm', 'publish', '--otp', otp])
  117. print('Done!')
  118. if __name__ == '__main__':
  119. parser = argparse.ArgumentParser(description='HyFetch Release Utility')
  120. parser.add_argument('version', help='Version to release')
  121. args = parser.parse_args()
  122. pre_check()
  123. edit_versions(args.version)
  124. finalize_neofetch()
  125. post_check()
  126. create_release(args.version)
  127. deploy()