FEATURE: add branch option to remote theme import

* FEATURE: add branch option to remote theme import

* FIX: Add missing variable in params

* FIX: Add missing param for import_theme method

* SPEC: Add test methods for branch support in git import

* FIX: Add missing space to scss style

* Do not assume default branch as master

* Change branch field placeholder

* FIX: add missing div start tag
This commit is contained in:
Erin Kosewic 2018-10-08 23:01:08 -07:00 committed by Sam
parent acba7d2a5d
commit 51aba32651
9 changed files with 99 additions and 18 deletions

View File

@ -44,7 +44,8 @@ export default Ember.Controller.extend(ModalFunctionality, {
options.data.append("theme", $("#file-input")[0].files[0]); options.data.append("theme", $("#file-input")[0].files[0]);
} else { } else {
options.data = { options.data = {
remote: this.get("uploadUrl") remote: this.get("uploadUrl"),
branch: this.get("branch")
}; };
if (this.get("privateChecked")) { if (this.get("privateChecked")) {

View File

@ -14,14 +14,21 @@
<label class="radio" for="remote">{{i18n 'upload_selector.from_the_web'}}</label> <label class="radio" for="remote">{{i18n 'upload_selector.from_the_web'}}</label>
{{#if remote}} {{#if remote}}
<div class="inputs"> <div class="inputs">
<div class='repo'>
{{input value=uploadUrl placeholder="https://github.com/discourse/sample_theme"}} {{input value=uploadUrl placeholder="https://github.com/discourse/sample_theme"}}
<span class="description">{{i18n 'admin.customize.theme.import_web_tip'}}</span> <span class="description">{{i18n 'admin.customize.theme.import_web_tip'}}</span>
</div>
<div class='branch'>
{{input value=branch placeholder="beta"}}
<span class="description">{{i18n 'admin.customize.theme.remote_branch'}}</span>
</div>
<div class='check-private'>
<label>
{{input type="checkbox" checked=privateChecked}}
{{i18n 'admin.customize.theme.is_private'}}
</label>
</div>
{{#if checkPrivate}} {{#if checkPrivate}}
<div class='check-private'>
<label>
{{input type="checkbox" checked=privateChecked}}
{{i18n 'admin.customize.theme.is_private'}}
</label>
{{#if privateChecked}} {{#if privateChecked}}
{{#if publicKey}} {{#if publicKey}}
<div class='public-key'> <div class='public-key'>
@ -30,10 +37,8 @@
</div> </div>
{{/if}} {{/if}}
{{/if}} {{/if}}
</div>
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/if}}
</div> </div>
{{/d-modal-body}} {{/d-modal-body}}

View File

@ -543,6 +543,10 @@
width: 27%; width: 27%;
} }
.modal-body .inputs .branch {
margin-top: 10px;
}
.modal-body .inputs .check-private { .modal-body .inputs .check-private {
margin-top: 10px; margin-top: 10px;
label { label {

View File

@ -76,7 +76,8 @@ class Admin::ThemesController < Admin::AdminController
end end
elsif params[:remote] elsif params[:remote]
begin begin
@theme = RemoteTheme.import_theme(params[:remote], current_user, private_key: params[:private_key]) branch = params[:branch] ? params[:branch] : nil
@theme = RemoteTheme.import_theme(params[:remote], current_user, private_key: params[:private_key], branch: branch)
render json: @theme, status: :created render json: @theme, status: :created
rescue RuntimeError => e rescue RuntimeError => e
Discourse.warn_exception(e, message: "Error importing theme") Discourse.warn_exception(e, message: "Error importing theme")

View File

@ -38,8 +38,8 @@ class RemoteTheme < ActiveRecord::Base
end end
end end
def self.import_theme(url, user = Discourse.system_user, private_key: nil) def self.import_theme(url, user = Discourse.system_user, private_key: nil, branch: nil)
importer = ThemeStore::GitImporter.new(url, private_key: private_key) importer = ThemeStore::GitImporter.new(url, private_key: private_key, branch: branch)
importer.import! importer.import!
theme_info = JSON.parse(importer["about.json"]) theme_info = JSON.parse(importer["about.json"])
@ -50,6 +50,7 @@ class RemoteTheme < ActiveRecord::Base
theme.remote_theme = remote_theme theme.remote_theme = remote_theme
remote_theme.private_key = private_key remote_theme.private_key = private_key
remote_theme.branch = branch
remote_theme.remote_url = importer.url remote_theme.remote_url = importer.url
remote_theme.update_from_remote(importer) remote_theme.update_from_remote(importer)
@ -73,7 +74,7 @@ class RemoteTheme < ActiveRecord::Base
end end
def update_remote_version def update_remote_version
importer = ThemeStore::GitImporter.new(remote_url, private_key: private_key) importer = ThemeStore::GitImporter.new(remote_url, private_key: private_key, branch: branch)
begin begin
importer.import! importer.import!
rescue ThemeStore::GitImporter::ImportFailed => err rescue ThemeStore::GitImporter::ImportFailed => err
@ -91,7 +92,7 @@ class RemoteTheme < ActiveRecord::Base
unless importer unless importer
cleanup = true cleanup = true
importer = ThemeStore::GitImporter.new(remote_url, private_key: private_key) importer = ThemeStore::GitImporter.new(remote_url, private_key: private_key, branch: branch)
begin begin
importer.import! importer.import!
rescue ThemeStore::GitImporter::ImportFailed => err rescue ThemeStore::GitImporter::ImportFailed => err
@ -235,6 +236,7 @@ end
# id :integer not null, primary key # id :integer not null, primary key
# remote_url :string not null # remote_url :string not null
# remote_version :string # remote_version :string
# branch :string
# local_version :string # local_version :string
# about_url :string # about_url :string
# license_url :string # license_url :string

View File

@ -3270,6 +3270,7 @@ en:
import_web_tip: "Repository containing theme" import_web_tip: "Repository containing theme"
import_file_tip: ".dcstyle.json file containing theme" import_file_tip: ".dcstyle.json file containing theme"
is_private: "Theme is in a private git repository" is_private: "Theme is in a private git repository"
remote_branch: "Branch"
public_key: "Grant the following public key access to the repo:" public_key: "Grant the following public key access to the repo:"
about_theme: "About Theme" about_theme: "About Theme"
license: "License" license: "License"

View File

@ -0,0 +1,5 @@
class AddBranchToRemoteTheme < ActiveRecord::Migration[5.2]
def change
add_column :remote_themes, :branch, :string
end
end

View File

@ -5,13 +5,14 @@ class ThemeStore::GitImporter
class ImportFailed < StandardError; end class ImportFailed < StandardError; end
attr_reader :url attr_reader :url
def initialize(url, private_key: nil) def initialize(url, private_key: nil, branch: nil)
@url = url @url = url
if @url.start_with?("https://github.com") && !@url.end_with?(".git") if @url.start_with?("https://github.com") && !@url.end_with?(".git")
@url += ".git" @url += ".git"
end end
@temp_folder = "#{Pathname.new(Dir.tmpdir).realpath}/discourse_theme_#{SecureRandom.hex}" @temp_folder = "#{Pathname.new(Dir.tmpdir).realpath}/discourse_theme_#{SecureRandom.hex}"
@private_key = private_key @private_key = private_key
@branch = branch
end end
def import! def import!
@ -67,7 +68,11 @@ class ThemeStore::GitImporter
def import_public! def import_public!
begin begin
Discourse::Utils.execute_command("git", "clone", @url, @temp_folder) if @branch.present?
Discourse::Utils.execute_command("git", "clone", "--single-branch", "-b", @branch, @url, @temp_folder)
else
Discourse::Utils.execute_command("git", "clone", @url, @temp_folder)
end
rescue => err rescue => err
raise ImportFailed.new(err.message) raise ImportFailed.new(err.message)
end end
@ -83,9 +88,12 @@ class ThemeStore::GitImporter
end end
begin begin
Discourse::Utils.execute_command({ git_ssh_command = { 'GIT_SSH_COMMAND' => "ssh -i #{ssh_folder}/id_rsa -o StrictHostKeyChecking=no" }
'GIT_SSH_COMMAND' => "ssh -i #{ssh_folder}/id_rsa -o StrictHostKeyChecking=no" if @branch.present?
}, "git", "clone", @url, @temp_folder) Discourse::Utils.execute_command(git_ssh_command, "git", "clone", "--single-branch", "-b", @branch, @url, @temp_folder)
else
Discourse::Utils.execute_command(git_ssh_command, "git", "clone", @url, @temp_folder)
end
rescue => err rescue => err
raise ImportFailed.new(err.message) raise ImportFailed.new(err.message)
end end

View File

@ -0,0 +1,54 @@
# encoding: utf-8
require 'rails_helper'
require 'theme_store/git_importer'
describe ThemeStore::GitImporter do
context "#import" do
let(:url) { "https://github.com/example/example.git" }
let(:ssh_url) { "git@github.com:example/example.git" }
let(:branch) { "dev" }
before do
hex = "xxx"
SecureRandom.stubs(:hex).returns(hex)
@temp_folder = "#{Pathname.new(Dir.tmpdir).realpath}/discourse_theme_#{hex}"
@ssh_folder = "#{Pathname.new(Dir.tmpdir).realpath}/discourse_theme_ssh_#{hex}"
end
it "should import from http url" do
Discourse::Utils.expects(:execute_command).with("git", "clone", url, @temp_folder)
importer = ThemeStore::GitImporter.new(url)
importer.import!
end
it "should import from ssh url" do
Discourse::Utils.expects(:execute_command).with({
'GIT_SSH_COMMAND' => "ssh -i #{@ssh_folder}/id_rsa -o StrictHostKeyChecking=no"
}, "git", "clone", ssh_url, @temp_folder)
importer = ThemeStore::GitImporter.new(ssh_url, private_key: "private_key")
importer.import!
end
it "should import branch from http url" do
Discourse::Utils.expects(:execute_command).with("git", "clone", "--single-branch", "-b", branch, url, @temp_folder)
importer = ThemeStore::GitImporter.new(url, branch: branch)
importer.import!
end
it "should import branch from ssh url" do
Discourse::Utils.expects(:execute_command).with({
'GIT_SSH_COMMAND' => "ssh -i #{@ssh_folder}/id_rsa -o StrictHostKeyChecking=no"
}, "git", "clone", "--single-branch", "-b", branch, ssh_url, @temp_folder)
importer = ThemeStore::GitImporter.new(ssh_url, private_key: "private_key", branch: branch)
importer.import!
end
end
end