heroku.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. """Handles heroku uploads"""
  2. # █ █ ▀ █▄▀ ▄▀█ █▀█ ▀
  3. # █▀█ █ █ █ █▀█ █▀▄ █
  4. # © Copyright 2022
  5. # https://t.me/hikariatama
  6. #
  7. # 🔒 Licensed under the GNU AGPLv3
  8. # 🌐 https://www.gnu.org/licenses/agpl-3.0.html
  9. from collections import namedtuple
  10. import logging
  11. import os
  12. try:
  13. import heroku3
  14. except ImportError:
  15. if "DYNO" in os.environ:
  16. raise
  17. from git import Repo
  18. from git.exc import InvalidGitRepositoryError
  19. from typing import Optional
  20. from . import utils
  21. def publish(
  22. key: Optional[str] = None,
  23. api_token: Optional[str] = None,
  24. create_new: Optional[bool] = True,
  25. ):
  26. """Push to heroku"""
  27. logging.debug("Configuring heroku...")
  28. if key is None:
  29. key = os.environ.get("heroku_api_token")
  30. app, config = get_app(key, api_token, create_new)
  31. config["heroku_api_token"] = key
  32. if api_token is not None:
  33. config["api_id"] = api_token.ID
  34. config["api_hash"] = api_token.HASH
  35. app.update_buildpacks(
  36. [
  37. "https://github.com/heroku/heroku-buildpack-python",
  38. "https://github.com/hikariatama/heroku-buildpack",
  39. "https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest",
  40. "https://github.com/jontewks/puppeteer-heroku-buildpack",
  41. "https://github.com/heroku/heroku-buildpack-apt",
  42. ]
  43. )
  44. if not any(
  45. addon.plan.name.startswith("heroku-postgresql") for addon in app.addons()
  46. ):
  47. app.install_addon("heroku-postgresql")
  48. repo = get_repo()
  49. url = app.git_url.replace("https://", f"https://api:{key}@")
  50. if "heroku" in repo.remotes:
  51. remote = repo.remote("heroku")
  52. remote.set_url(url)
  53. else:
  54. remote = repo.create_remote("heroku", url)
  55. remote.push(refspec="HEAD:refs/heads/master")
  56. return app
  57. def get_app(
  58. key: Optional[str] = None,
  59. api_token: Optional[namedtuple] = None,
  60. create_new: Optional[bool] = True,
  61. ):
  62. if key is None:
  63. key = os.environ.get("heroku_api_token")
  64. heroku = heroku3.from_key(key)
  65. for poss_app in heroku.apps():
  66. config = poss_app.config()
  67. if api_token is None or (
  68. config["api_id"] == api_token.ID and config["api_hash"] == api_token.HASH
  69. ):
  70. return poss_app, config
  71. if not create_new:
  72. logging.error("%r", {app: repr(app.config) for app in heroku.apps()})
  73. raise RuntimeError("Could not identify app!")
  74. app = heroku.create_app(
  75. name=f"hikka-{utils.rand(8)}",
  76. stack_id_or_name="heroku-20",
  77. region_id_or_name="eu",
  78. )
  79. config = app.config()
  80. return app, config
  81. def get_repo():
  82. """Helper to get the repo, making it if not found"""
  83. try:
  84. repo = Repo(os.path.dirname(utils.get_base_dir()))
  85. except InvalidGitRepositoryError:
  86. repo = Repo.init(os.path.dirname(utils.get_base_dir()))
  87. origin = repo.create_remote(
  88. "origin",
  89. "https://github.com/hikariatama/Hikka",
  90. )
  91. origin.fetch()
  92. repo.create_head("master", origin.refs.master)
  93. repo.heads.master.set_tracking_branch(origin.refs.master)
  94. repo.heads.master.checkout(True)
  95. return repo
  96. def init():
  97. """Will be run on every Heroku start"""
  98. # Create repo if not found
  99. get_repo()