heroku.py 3.3 KB

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