-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add zero-config self hosting on Render (#612)
* v1 of backend implementation for self hosting * Add docs * Add upgrades controller * Add global helpers for self hosting mode * Add self host settings controller * Conditionally show self hosting settings * Environment and config updates * Complete upgrade prompting flow * Update config for forked repo * Move configuration of github provider within class * Add upgrades cron * Update deploy button * Update guides * Fix render deployer * Typo * Enable auto upgrades * Fix cron * Make upgrade modes more clear and consistent * Trigger new available version * Fix logic for displaying upgrade prompts * Finish implementation * Fix regression * Trigger new version * Add i18n translations * trigger new version * reduce caching time for testing * Decrease cache for testing * trigger upgrade * trigger upgrade * Only trigger deploy once * trigger upgrade * If target is commit, always upgrade if any upgrade is available * trigger upgrade * trigger upgrade * Test release * Change back to maybe repo for defaults * Fix lint errors * Clearer naming * Fix relative link * Add abs path * Relative link * Update docs
- Loading branch information
Showing
53 changed files
with
1,356 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module Invitable | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
helper_method :invite_code_required? | ||
end | ||
|
||
private | ||
def invite_code_required? | ||
ENV["REQUIRE_INVITE_CODE"] == "true" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module SelfHostable | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
helper_method :self_hosted? | ||
end | ||
|
||
private | ||
def self_hosted? | ||
ENV["SELF_HOSTING_ENABLED"] == "true" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
class Settings::SelfHostingController < ApplicationController | ||
before_action :verify_self_hosting_enabled | ||
|
||
def edit | ||
end | ||
|
||
def update | ||
if all_updates_valid? | ||
self_hosting_params.keys.each do |key| | ||
Setting.send("#{key}=", self_hosting_params[key].strip) | ||
end | ||
|
||
redirect_to edit_settings_self_hosting_path, notice: t(".success") | ||
else | ||
flash.now[:error] = @errors.first.message | ||
render :edit, status: :unprocessable_entity | ||
end | ||
end | ||
|
||
private | ||
def all_updates_valid? | ||
@errors = ActiveModel::Errors.new(Setting) | ||
self_hosting_params.keys.each do |key| | ||
setting = Setting.new(var: key) | ||
setting.value = self_hosting_params[key].strip | ||
|
||
unless setting.valid? | ||
@errors.merge!(setting.errors) | ||
end | ||
end | ||
|
||
if self_hosting_params[:upgrades_mode] == "auto" && self_hosting_params[:render_deploy_hook].blank? | ||
@errors.add(:render_deploy_hook, t("settings.self_hosting.update.render_deploy_hook_error")) | ||
end | ||
|
||
@errors.empty? | ||
end | ||
|
||
def self_hosting_params | ||
params.require(:setting).permit(:render_deploy_hook, :upgrades_mode, :upgrades_target) | ||
end | ||
|
||
def verify_self_hosting_enabled | ||
head :not_found unless self_hosted? | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
class UpgradesController < ApplicationController | ||
before_action :verify_upgrades_enabled | ||
|
||
def acknowledge | ||
commit_sha = params[:id] | ||
upgrade = Upgrader.find_upgrade(commit_sha) | ||
|
||
if upgrade | ||
if upgrade.available? | ||
Current.user.acknowledge_upgrade_prompt(upgrade.commit_sha) | ||
flash[:notice] = t(".upgrade_dismissed") | ||
elsif upgrade.complete? | ||
Current.user.acknowledge_upgrade_alert(upgrade.commit_sha) | ||
flash[:notice] = t(".upgrade_complete_dismiss") | ||
else | ||
flash[:alert] = t(".upgrade_not_available") | ||
end | ||
else | ||
flash[:alert] = t(".upgrade_not_found") | ||
end | ||
|
||
redirect_back(fallback_location: root_path) | ||
end | ||
|
||
def deploy | ||
commit_sha = params[:id] | ||
upgrade = Upgrader.find_upgrade(commit_sha) | ||
|
||
unless upgrade | ||
flash[:alert] = t(".upgrade_not_found") | ||
return redirect_back(fallback_location: root_path) | ||
end | ||
|
||
prior_acknowledged_upgrade_commit_sha = Current.user.last_prompted_upgrade_commit_sha | ||
|
||
# Optimistically acknowledge the upgrade prompt | ||
Current.user.acknowledge_upgrade_prompt(upgrade.commit_sha) | ||
|
||
upgrade_result = Upgrader.upgrade_to(upgrade) | ||
|
||
if upgrade_result[:success] | ||
flash[:notice] = upgrade_result[:message] | ||
else | ||
# If the upgrade fails, revert to the prior acknowledged upgrade | ||
Current.user.acknowledge_upgrade_prompt(prior_acknowledged_upgrade_commit_sha) | ||
flash[:alert] = upgrade_result[:message] | ||
end | ||
|
||
redirect_back(fallback_location: root_path) | ||
end | ||
|
||
private | ||
def verify_upgrades_enabled | ||
head :not_found unless ENV["UPGRADES_ENABLED"] == "true" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
module Settings::SelfHostingHelper | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module UpgradesHelper | ||
def upgrade_notification | ||
return nil unless ENV["UPGRADES_ENABLED"] == "true" | ||
|
||
completed_upgrade = Upgrader.completed_upgrade | ||
return completed_upgrade if completed_upgrade && Current.user.last_alerted_upgrade_commit_sha != completed_upgrade.commit_sha | ||
|
||
available_upgrade = Upgrader.available_upgrade | ||
if available_upgrade && Setting.upgrades_mode == "manual" && Current.user.last_prompted_upgrade_commit_sha != available_upgrade.commit_sha | ||
available_upgrade | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
class AutoUpgradeJob < ApplicationJob | ||
queue_as :default | ||
|
||
def perform(*args) | ||
raise_if_disabled | ||
|
||
return Rails.logger.info "Skipping auto-upgrades because app is set to manual upgrades. Please set UPGRADES_MODE=auto to enable auto-upgrades" if Setting.upgrades_mode == "manual" | ||
|
||
Rails.logger.info "Searching for available auto-upgrades..." | ||
|
||
candidate = Upgrader.available_upgrade_by_type(Setting.upgrades_target) | ||
|
||
if candidate | ||
if Rails.cache.read("last_auto_upgrade_commit_sha") == candidate.commit_sha | ||
Rails.logger.info "Skipping auto upgrade: #{candidate.type} #{candidate.commit_sha} deploy in progress" | ||
return | ||
end | ||
|
||
Rails.logger.info "Auto upgrading to #{candidate.type} #{candidate.commit_sha}..." | ||
Upgrader.upgrade_to(candidate) | ||
Rails.cache.write("last_auto_upgrade_commit_sha", candidate.commit_sha, expires_in: 1.day) | ||
else | ||
Rails.logger.info "No auto upgrade available at this time" | ||
end | ||
end | ||
|
||
private | ||
def raise_if_disabled | ||
raise "Upgrades module is disabled. Please set UPGRADES_ENABLED=true to enable upgrade features" unless ENV["UPGRADES_ENABLED"] == "true" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
class Provider::Github | ||
attr_reader :name, :owner, :branch | ||
|
||
def initialize(config = {}) | ||
@name = config[:name] || ENV.fetch("GITHUB_REPO_NAME", "maybe") | ||
@owner = config[:owner] || ENV.fetch("GITHUB_REPO_OWNER", "maybe-finance") | ||
@branch = config[:branch] || ENV.fetch("GITHUB_REPO_BRANCH", "main") | ||
end | ||
|
||
def fetch_latest_upgrade_candidates | ||
Rails.cache.fetch("latest_github_upgrade_candidates", expires_in: 2.minutes) do | ||
Rails.logger.info "Fetching latest GitHub upgrade candidates from #{repo} on branch #{branch}..." | ||
begin | ||
latest_release = Octokit.releases(repo).first | ||
latest_version = latest_release ? Semver.from_release_tag(latest_release.tag_name) : Semver.new(Maybe.version) | ||
latest_commit = Octokit.branch(repo, branch) | ||
|
||
release_info = if latest_release | ||
{ | ||
version: latest_version, | ||
url: latest_release.html_url, | ||
commit_sha: Octokit.commit(repo, latest_release.tag_name).sha | ||
} | ||
end | ||
|
||
commit_info = { | ||
version: latest_version, | ||
commit_sha: latest_commit.commit.sha, | ||
url: latest_commit.commit.html_url | ||
} | ||
|
||
{ | ||
release: release_info, | ||
commit: commit_info | ||
} | ||
rescue => e | ||
Rails.logger.error "Failed to fetch latest GitHub commits: #{e.message}" | ||
nil | ||
end | ||
end | ||
end | ||
|
||
private | ||
def repo | ||
"#{owner}/#{name}" | ||
end | ||
end |
Oops, something went wrong.