bard 1.1.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 588cdbfd25f55995fcc7a63da8cca7d8ca0f85aa0493e707e42b0684a09814d4
4
- data.tar.gz: 3936e7c7ff76faec65b7865641ad271c78b5f1e1d1f0e76cab72d2c59c83ff42
3
+ metadata.gz: 50507cf111440a4f0d9f6cd1ee580f6749f81534c1c2f507fb32adcf7d49cbe7
4
+ data.tar.gz: e0386582b40d92ca6d5d003f1b83f03c34ad19968338b23e468f08778bdec968
5
5
  SHA512:
6
- metadata.gz: a30e2048f3c2d8c64c5f2d83babce66b0c008145cab3bfa2e1fa7685edb710b75ca204258bb946f8361d99a43af8f52c468eae24af41222f5d69479e5b6f667b
7
- data.tar.gz: 642c7e6c47280b94f3b21439534b7b932debea8ecb72704f3a34ca241cbace3094c5f59ed521f3b412d818a5929e0d331eba44a36c816f5f85b00e1611d066c1
6
+ metadata.gz: e3790197e55287ec52f6f4ee62b4e7df4cb02d148182520a913ac2ca235344cd7bb62f3b3a4ed53bb50e549cb08594d39de72c8a52de00fa441d65c52ecd696c
7
+ data.tar.gz: 8a6525ca5efc614ed59f51c811d39733bec7d5c5e9c1966510006d221d0d5654402098cb9f492e7ce3289cda3d43748b9af1b726a25a22e9b98718f461ec5c90
@@ -0,0 +1,19 @@
1
+ require "delegate"
2
+
3
+ class Bard::CLI::Command < SimpleDelegator
4
+ def self.desc command, description
5
+ @command = command
6
+ @method = command.split(" ").first.to_sym
7
+ @description = description
8
+ end
9
+
10
+ def self.setup cli
11
+ cli.desc @command, @description
12
+
13
+ method = @method # put in local variable so next block can capture it
14
+ cli.define_method method do |*args|
15
+ command = Bard::CLI::New.new(self)
16
+ command.send method, *args
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,6 @@
1
1
  require "bard/git"
2
2
  require "bard/command"
3
+ require "bard/github_pages"
3
4
 
4
5
  module Bard::CLI::Deploy
5
6
  def self.included mod
@@ -7,6 +8,7 @@ module Bard::CLI::Deploy
7
8
 
8
9
  option :"skip-ci", type: :boolean
9
10
  option :"local-ci", type: :boolean
11
+ option :clone, type: :boolean
10
12
  desc "deploy [TO=production]", "checks that current branch is a ff with master, checks with ci, merges into master, deploys to target, and then deletes branch."
11
13
  def deploy to=:production
12
14
  branch = Bard::Git.current_branch
@@ -37,7 +39,17 @@ module Bard::CLI::Deploy
37
39
  run! "git push github"
38
40
  end
39
41
 
40
- config[to].run! "git pull origin master && bin/setup"
42
+ if options[:clone]
43
+ config[to].run! "git clone git@github.com:botandrosedesign/#{project_name}", home: true
44
+ invoke :master_key, nil, from: "local", to: to
45
+ config[to].run! "bin/setup && bard setup"
46
+ else
47
+ if config[to].github_pages
48
+ Bard::GithubPages.new(self).deploy(config[to])
49
+ else
50
+ config[to].run! "git pull origin master && bin/setup"
51
+ end
52
+ end
41
53
 
42
54
  puts green("Deploy Succeeded")
43
55
 
@@ -0,0 +1,68 @@
1
+ require "bard/cli/command"
2
+ require "bard/github"
3
+
4
+ class Bard::CLI::New < Bard::CLI::Command
5
+ desc "new <project-name>", "creates new bard app named <project-name>"
6
+ def new project_name
7
+ @project_name = project_name
8
+ validate
9
+ create_project
10
+ push_to_github
11
+ stage
12
+ puts green("Project #{project_name} created!")
13
+ puts "Please cd ../#{project_name}"
14
+ end
15
+
16
+ attr_accessor :project_name
17
+
18
+ private
19
+
20
+ def validate
21
+ if project_name !~ /^[a-z][a-z0-9]*\Z/
22
+ puts red("!!! ") + "Invalid project name: #{yellow(project_name)}."
23
+ puts "The first character must be a lowercase letter, and all following characters must be a lowercase letter or number."
24
+ exit 1
25
+ end
26
+ end
27
+
28
+ def create_project
29
+ run! <<~BASH
30
+ env -i bash -lc '
31
+ export HOME=~
32
+ cd ..
33
+ source ~/.rvm/scripts/rvm
34
+ rvm use --create #{ruby_version}@#{project_name}
35
+
36
+ gem list rails -i && gem install rails --no-document
37
+ rails new #{project_name} --skip-kamal -m #{template_path}
38
+ '
39
+ BASH
40
+ end
41
+
42
+ def push_to_github
43
+ Bard::Github.new(project_name).create_repo
44
+ run! <<~BASH
45
+ cd ../#{project_name}
46
+ git add -A
47
+ git commit -m"initial commit."
48
+ git remote add origin git@github.com:botandrosedesign/#{project_name}
49
+ git push -u origin master
50
+ BASH
51
+ end
52
+
53
+ def stage
54
+ run! <<~BASH
55
+ cd ../#{project_name}
56
+ bard deploy --provision
57
+ BASH
58
+ end
59
+
60
+ def ruby_version
61
+ File.read(".ruby-version").chomp
62
+ end
63
+
64
+ def template_path
65
+ File.expand_path("new_rails_template.rb", __dir__)
66
+ end
67
+ end
68
+
@@ -0,0 +1,88 @@
1
+ ruby_version, project_name = (`rvm current name`.chomp).split("@")
2
+
3
+ file ".ruby-version", ruby_version
4
+ file ".ruby-gemset", project_name
5
+
6
+ file "Gemfile", <<~RUBY
7
+ source "https://rubygems.org"
8
+
9
+ gem "bootsnap", require: false
10
+ gem "rails", "~>8.0.0"
11
+ gem "bard-rails"
12
+ gem "sqlite3"
13
+
14
+ gem "sprockets-rails"
15
+ gem "dartsass-sprockets"
16
+ gem "bard-sass"
17
+
18
+ gem "importmap-rails"
19
+ gem "turbo-rails"
20
+ gem "stimulus-rails"
21
+
22
+ gem "solid_cache"
23
+ gem "solid_queue"
24
+ gem "solid_cable"
25
+
26
+ gem "image_processing"
27
+
28
+ group :development do
29
+ gem "web-console"
30
+ end
31
+
32
+ group :development, :test do
33
+ gem "debug", require: "debug/prelude"
34
+ gem "brakeman", require: false
35
+ gem "rubocop-rails-omakase", require: false
36
+ end
37
+
38
+ group :test do
39
+ gem "cucumber-rails", require: false
40
+ gem "cuprite-downloads"
41
+ gem "capybara-screenshot"
42
+ gem "database_cleaner"
43
+ gem "puma"
44
+ gem "chop"
45
+ gem "email_spec"
46
+ gem "timecop"
47
+ gem "rspec-rails"
48
+ end
49
+
50
+ group :production do
51
+ gem "foreman-export-systemd_user"
52
+ gem "puma"
53
+ end
54
+ RUBY
55
+
56
+ file "app/assets/config/manifest.js", <<~RUBY
57
+ //= link_tree ../images
58
+ //= link_directory ../stylesheets .css
59
+ //= link_tree ../../javascript .js
60
+ RUBY
61
+
62
+ run "rm -f app/assets/stylesheets/application.css"
63
+
64
+ file "app/assets/stylesheets/application.sass", <<~SASS
65
+ body
66
+ border: 10px solid red
67
+ SASS
68
+
69
+ gsub_file "app/views/layouts/application.html.erb", " <%# Includes all stylesheet files in app/assets/stylesheets %>\n", ''
70
+ gsub_file "app/views/layouts/application.html.erb", 'stylesheet_link_tag :app,', 'stylesheet_link_tag :application,'
71
+
72
+ file "app/views/static/index.html.slim", <<~SLIM
73
+ h1 #{project_name}
74
+ SLIM
75
+
76
+ insert_into_file "config/database.yml", <<~YAML, after: "database: storage/test.sqlite3"
77
+
78
+ staging:
79
+ <<: *default
80
+ database: storage/staging.sqlite3
81
+ YAML
82
+
83
+ after_bundle do
84
+ run "bard install"
85
+ run "bin/setup"
86
+ run "bard setup"
87
+ end
88
+
data/lib/bard/cli.rb CHANGED
@@ -31,8 +31,24 @@ module Bard
31
31
  include const_get(klass)
32
32
  end
33
33
 
34
+ {
35
+ new: "New",
36
+ }.each do |command, klass|
37
+ require "bard/cli/#{command}"
38
+ const_get(klass).setup(self)
39
+ end
40
+
34
41
  def self.exit_on_failure? = true
35
42
 
43
+ no_commands do
44
+ def run!(...)
45
+ Bard::Command.run!(...)
46
+ rescue Bard::Command::Error => e
47
+ puts red("!!! ") + "Running command failed: #{yellow(e.message)}"
48
+ exit 1
49
+ end
50
+ end
51
+
36
52
  private
37
53
 
38
54
  def config
@@ -42,13 +58,6 @@ module Bard
42
58
  def project_name
43
59
  @project_name ||= File.expand_path(".").split("/").last
44
60
  end
45
-
46
- def run!(...)
47
- Bard::Command.run!(...)
48
- rescue Bard::Command::Error => e
49
- puts red("!!! ") + "Running command failed: #{yellow(e.message)}"
50
- exit 1
51
- end
52
61
  end
53
62
  end
54
63
 
data/lib/bard/command.rb CHANGED
@@ -23,6 +23,9 @@ module Bard
23
23
  end
24
24
 
25
25
  def run verbose: false, quiet: false
26
+ # no-op if server doesn't really exist
27
+ return true if on.respond_to?(:ssh) && on.ssh == false
28
+
26
29
  if verbose
27
30
  system full_command(quiet: quiet)
28
31
  else
data/lib/bard/config.rb CHANGED
@@ -75,5 +75,17 @@ module Bard
75
75
  raise ArgumentError
76
76
  end
77
77
  end
78
+
79
+ # short-hand for michael
80
+
81
+ def github_pages url=nil
82
+ server :production do
83
+ github_pages true
84
+ ssh false
85
+ ping url
86
+ end
87
+
88
+ backup false
89
+ end
78
90
  end
79
91
  end
data/lib/bard/github.rb CHANGED
@@ -19,6 +19,14 @@ module Bard
19
19
  end
20
20
  end
21
21
 
22
+ def delete path, params={}
23
+ request(path) do |uri|
24
+ Net::HTTP::Delete.new(uri).tap do |r|
25
+ r.body = JSON.dump(params)
26
+ end
27
+ end
28
+ end
29
+
22
30
  def read_file path, branch: "master"
23
31
  metadata = get("contents/#{path}", ref: branch)
24
32
  Base64.decode64(metadata["content"])
@@ -28,6 +36,17 @@ module Bard
28
36
  post("keys", title:, key:)
29
37
  end
30
38
 
39
+ def create_repo
40
+ post("https://api.github.com/orgs/botandrosedesign/repos", {
41
+ name: project_name,
42
+ private: true,
43
+ })
44
+ end
45
+
46
+ def delete_repo
47
+ delete("https://api.github.com/repos/botandrosedesign/#{project_name}")
48
+ end
49
+
31
50
  private
32
51
 
33
52
  def github_apikey
@@ -63,7 +82,7 @@ module Bard
63
82
  response.body
64
83
  end
65
84
  else
66
- raise [req.method, req.uri, req.to_hash, response].inspect
85
+ raise [req.method, req.uri, req.to_hash, response, response.body].inspect
67
86
  end
68
87
  end
69
88
  end
@@ -0,0 +1,112 @@
1
+ require 'delegate'
2
+ require 'fileutils'
3
+ require 'bard/git'
4
+
5
+ module Bard
6
+ class GithubPages < SimpleDelegator
7
+ def deploy server
8
+ @sha = Git.sha_of(Git.current_branch)
9
+ @build_dir = "tmp/github-build-#{@sha}"
10
+ @branch = "gh-pages"
11
+ @domain = server.ping.first
12
+
13
+ puts "Starting deployment to GitHub Pages..."
14
+
15
+ build_site
16
+ tree_sha = create_tree_from_build
17
+ new_commit = create_commit(tree_sha)
18
+ commit_and_push new_commit
19
+ end
20
+
21
+ private
22
+
23
+ def build_site
24
+ FileUtils.rm_rf "tmp/github-build-".sub(@sha, "*")
25
+ run! <<~BASH
26
+ bundle exec rake assets:clean assets:precompile
27
+ RAILS_ENV=production bundle exec rails s -p 3000 -d --pid tmp/pids/server.pid
28
+
29
+ # Create the output directory and enter it
30
+ BUILD=#{@build_dir}
31
+ rm -rf $BUILD
32
+ mkdir -p $BUILD
33
+ cp -R public/assets $BUILD/
34
+ cd $BUILD
35
+
36
+ # wait until server responds
37
+ curl --retry 5 --retry-delay 2 -s -o /dev/null "http://0.0.0.0:3000"
38
+
39
+ # Mirror the site to the build folder, ignoring links with query params
40
+ wget --reject-regex "(.*)\\?(.*)" -FEmnH http://0.0.0.0:3000/
41
+ echo #{@domain} > CNAME
42
+
43
+ # Kill the server
44
+ cd -
45
+ cat tmp/pids/server.pid | xargs -I {} kill {}
46
+
47
+ # Clean up the assets
48
+ rm -rf public/assets
49
+ BASH
50
+ end
51
+
52
+ def create_tree_from_build
53
+ # Create temporary index
54
+ git_index_file = ".git/tmp-index"
55
+ git = "GIT_INDEX_FILE=#{git_index_file} git"
56
+ run! "#{git} read-tree --empty"
57
+
58
+ # Add build files to temporary index
59
+ Dir.chdir(@build_dir) do
60
+ Dir.glob('**/*', File::FNM_DOTMATCH).each do |file|
61
+ next if file == '.' || file == '..'
62
+ if File.file?(file)
63
+ run! "#{git} update-index --add --cacheinfo 100644 $(#{git} hash-object -w #{file}) #{file}"
64
+ end
65
+ end
66
+ end
67
+
68
+ # Create tree object from index
69
+ tree_sha = `#{git} write-tree`.chomp
70
+
71
+ # Clean up temporary index
72
+ FileUtils.rm_f(git_index_file)
73
+
74
+ tree_sha
75
+ end
76
+
77
+ def create_commit tree_sha
78
+ # Get parent commit if branch exists
79
+ parent = get_parent_commit
80
+
81
+ # Create commit object
82
+ message = "'Deploying to #{@branch} from @ #{@sha} 🚀'"
83
+ args = ['commit-tree', tree_sha]
84
+ args += ['-p', parent] if parent
85
+ args += ['-m', message]
86
+
87
+ commit_sha = `git #{args.join(' ')}`.chomp
88
+
89
+ commit_sha
90
+ end
91
+
92
+ def get_parent_commit
93
+ sha = Git.sha_of("#{@branch}^{commit}")
94
+ return sha if $?.success?
95
+ nil # Branch doesn't exist yet
96
+ end
97
+
98
+ def commit_and_push commit_sha
99
+ if branch_exists?
100
+ run! "git update-ref refs/heads/#{@branch} #{commit_sha}"
101
+ else
102
+ run! "git branch #{@branch} #{commit_sha}"
103
+ end
104
+ run! "git push -f origin #{@branch}:refs/heads/#{@branch}"
105
+ end
106
+
107
+ def branch_exists?
108
+ system("git show-ref --verify --quiet refs/heads/#{@branch}")
109
+ end
110
+ end
111
+ end
112
+
@@ -0,0 +1,25 @@
1
+ # install public keys if missing
2
+
3
+ class Bard::Provision::AuthorizedKeys < Bard::Provision
4
+ def call
5
+ print "Authorized Keys:"
6
+
7
+ KEYS.each do |search_text, full_key|
8
+ provision_server.run! <<~BASH #, quiet: true
9
+ file=~/.ssh/authorized_keys
10
+ if ! grep -F -q "#{search_text}" $file; then
11
+ echo "#{full_key}" >> $file
12
+ fi
13
+ BASH
14
+ end
15
+
16
+ puts " ✓"
17
+ end
18
+
19
+ KEYS = {
20
+ "micah@haku" => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAH235mtpxPQucd0bIgdufo1bR3By2+a+NPHiZS1P7SpI73evN9+hY7ri+gLscPLRWeoy1ig/TbyfN1AqJmfqIaskZdYOdcEQdOum4AwDMY5L6OAq2o5NER047RqDxE6Pjm2nfRVVw2Dz38eeco+ouchCI+sY5pJL/wEZItrCpPjKvwo56uln1rL6Smd4Kh98ZBKTGL8xKs95rNmFdBCCq4eUE28JDgkJAiLDZ/4u2LNrgEr7/brkUieZjaZ4BacBi8EQvyvMWmZ0g2MoG+Ptxn/3K2nd1QqdhfINqHBVCi8UbkP08B0Msif/7Dycuxd7DU9cVZ3RgnhLtbIsQ8HaYVj5yCKB6CuX3lv3H4YKBghBC/TnJD5Nq5xcSYTW0BKKrusCb/OoOk5AUV+BGM1+R70fno8reVEBUlZDkWapHxmqgNnf1byL7Aol/L5SWgyfSLT6b5FjI6g/U+dhaecYY9T9g/GWo+JiwZktc094O0ujlQHoibMY2M0csVfvO9Oc= micah@haku",
21
+ "gubs@Theia.local" => "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEApJh0E8ZlaLbMUWGvryAhEBRnnI519ZKz586vdQTuIPlDb9xhe5m3Ys8Fk9LKqJUQNxBV6qCGOXNgNdWySkk2ChmmgDnPfr7/31ZuOAASFbUY0PtaDXUsMVvs1Uu2VhtRU9gSduGonEHG7iBpAuBI23CxU4yPS6o3pv7L9xwnmULes5F9S4/nDvPig15h9byInyHOLDV0XjHFS+2OlSWO/xC8uqH5CdlxXFAmPQ0R69qmILl0rcTPyNMLJGcJGUzb/LMRJX/RDyTpZeJPjH4V+zksQ/4YQ3LWvLrlZL6QLuM285ve4mQa3vBY4WMqNlp4Ig3ZCFOpMKmpvTn7pFUmKw== gubs@Theia.local",
22
+ }
23
+ end
24
+
25
+
@@ -0,0 +1,30 @@
1
+ # install log rotation if missing
2
+
3
+ class Bard::Provision::LogRotation < Bard::Provision
4
+ def call
5
+ print "Log Rotation:"
6
+
7
+ provision_server.run! <<~BASH, quiet: true
8
+ file=/etc/logrotate.d/#{server.project_name}
9
+ if [ ! -f $file ]; then
10
+ sudo tee $file > /dev/null <<EOF
11
+ $(pwd)/log/*.log {
12
+ weekly
13
+ size 100M
14
+ missingok
15
+ rotate 52
16
+ delaycompress
17
+ notifempty
18
+ copytruncate
19
+ create 664 www www
20
+ }
21
+ EOF
22
+ fi
23
+ BASH
24
+
25
+ puts " ✓"
26
+ end
27
+ end
28
+
29
+
30
+
@@ -3,7 +3,7 @@ module Bard
3
3
  def self.call(...) = new(...).call
4
4
 
5
5
  def call
6
- %w[SSH User Apt MySQL Repo MasterKey RVM App Passenger Data HTTP].each do |step|
6
+ %w[SSH User AuthorizedKeys Apt MySQL Repo MasterKey RVM App Passenger Data HTTP LogRotation].each do |step|
7
7
  require "bard/provision/#{step.downcase}"
8
8
  self.class.const_get(step).call(*values)
9
9
  end
data/lib/bard/server.rb CHANGED
@@ -3,7 +3,7 @@ require "bard/command"
3
3
  require "bard/copy"
4
4
 
5
5
  module Bard
6
- class Server < Struct.new(:project_name, :key, :ssh, :path, :ping, :gateway, :ssh_key, :env)
6
+ class Server < Struct.new(:project_name, :key, :ssh, :path, :ping, :gateway, :ssh_key, :env, :github_pages)
7
7
  def self.define project_name, key, &block
8
8
  new(project_name, key).tap do |server|
9
9
  server.instance_eval &block
@@ -24,7 +24,7 @@ module Bard
24
24
  end
25
25
  end
26
26
 
27
- setting :ssh, :path, :ping, :gateway, :ssh_key, :env
27
+ setting :ssh, :path, :ping, :gateway, :ssh_key, :env, :github_pages
28
28
 
29
29
  def ping(*args)
30
30
  if args.length == 0
data/lib/bard/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Bard
2
- VERSION = "1.1.2"
2
+ VERSION = "1.3.0"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Geisel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-13 00:00:00.000000000 Z
11
+ date: 2024-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -139,11 +139,14 @@ files:
139
139
  - lib/bard/ci/local.rb
140
140
  - lib/bard/cli.rb
141
141
  - lib/bard/cli/ci.rb
142
+ - lib/bard/cli/command.rb
142
143
  - lib/bard/cli/data.rb
143
144
  - lib/bard/cli/deploy.rb
144
145
  - lib/bard/cli/hurt.rb
145
146
  - lib/bard/cli/install.rb
146
147
  - lib/bard/cli/master_key.rb
148
+ - lib/bard/cli/new.rb
149
+ - lib/bard/cli/new_rails_template.rb
147
150
  - lib/bard/cli/open.rb
148
151
  - lib/bard/cli/ping.rb
149
152
  - lib/bard/cli/provision.rb
@@ -157,12 +160,15 @@ files:
157
160
  - lib/bard/copy.rb
158
161
  - lib/bard/git.rb
159
162
  - lib/bard/github.rb
163
+ - lib/bard/github_pages.rb
160
164
  - lib/bard/ping.rb
161
165
  - lib/bard/provision.rb
162
166
  - lib/bard/provision/app.rb
163
167
  - lib/bard/provision/apt.rb
168
+ - lib/bard/provision/authorizedkeys.rb
164
169
  - lib/bard/provision/data.rb
165
170
  - lib/bard/provision/http.rb
171
+ - lib/bard/provision/logrotation.rb
166
172
  - lib/bard/provision/masterkey.rb
167
173
  - lib/bard/provision/mysql.rb
168
174
  - lib/bard/provision/passenger.rb