Add "fourier bundle" command (#2953)
This commit is contained in:
parent
6e58ef29d6
commit
8c83c86529
|
@ -0,0 +1,45 @@
|
|||
name: Release dry-run
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- Gemfile*
|
||||
- Package.swift
|
||||
- Package.resolved
|
||||
- Sources/**
|
||||
- Project.swift
|
||||
|
||||
env:
|
||||
RUBY_VERSION: '3.0.1'
|
||||
TUIST_STATS_OPT_OUT: true
|
||||
|
||||
jobs:
|
||||
bundle-all:
|
||||
name: Bundle tuist and tuistenv with Xcode ${{ matrix.xcode }}
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
xcode: ['12']
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Select Xcode
|
||||
run: sudo xcode-select -switch /Applications/Xcode_${{ matrix.xcode }}.app
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ env.RUBY_VERSION }}
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: vendor/bundle
|
||||
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gems-
|
||||
- name: Bundle install
|
||||
run: |
|
||||
bundle config path vendor/bundle
|
||||
bundle install --jobs 4 --retry 3
|
||||
- name: Build
|
||||
run: |
|
||||
./fourier bundle all
|
|
@ -3,7 +3,6 @@ inherit_gem:
|
|||
rubocop-rails_config:
|
||||
- config/rails.yml
|
||||
require:
|
||||
- rubocop-rake
|
||||
- rubocop-minitest
|
||||
|
||||
Style/ClassAndModuleChildren:
|
||||
|
@ -20,7 +19,6 @@ AllCops:
|
|||
DisplayStyleGuide: true
|
||||
Include:
|
||||
- Gemfile
|
||||
- Rakefile
|
||||
- projects/fourier/**/*.rb
|
||||
|
||||
Exclude:
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -7,7 +7,6 @@ ruby "3.0.1"
|
|||
gem "cucumber", "~> 6.0"
|
||||
gem "rake", "~> 13.0"
|
||||
gem "simctl", "~> 1.6"
|
||||
gem "encrypted-environment", "~> 0.2.0"
|
||||
gem "google-cloud-storage", "~> 1.31"
|
||||
gem "colorize", "~> 0.8.1"
|
||||
gem "cocoapods", "~> 1.10"
|
||||
|
@ -22,6 +21,7 @@ gem "zeitwerk", "~> 2.4"
|
|||
gem "cli-kit", "~> 3.3"
|
||||
gem "semantic", "~> 1.6"
|
||||
gem "down", "~> 5.2"
|
||||
gem "ejson", "~> 1.2"
|
||||
|
||||
group :test do
|
||||
gem "mocha", "~> 1.12"
|
||||
|
|
40
Gemfile.lock
40
Gemfile.lock
|
@ -75,20 +75,20 @@ GEM
|
|||
colorize (0.8.1)
|
||||
concurrent-ruby (1.1.8)
|
||||
crass (1.0.6)
|
||||
cucumber (6.0.0)
|
||||
cucumber (6.1.0)
|
||||
builder (~> 3.2, >= 3.2.4)
|
||||
cucumber-core (~> 9.0, >= 9.0.0)
|
||||
cucumber-core (~> 9.0, >= 9.0.1)
|
||||
cucumber-create-meta (~> 4.0, >= 4.0.0)
|
||||
cucumber-cucumber-expressions (~> 12.1, >= 12.1.1)
|
||||
cucumber-gherkin (~> 18.1, >= 18.1.0)
|
||||
cucumber-html-formatter (~> 13.0, >= 13.0.0)
|
||||
cucumber-messages (~> 15.0, >= 15.0.0)
|
||||
cucumber-wire (~> 5.0, >= 5.0.0)
|
||||
cucumber-wire (~> 5.0, >= 5.0.1)
|
||||
diff-lcs (~> 1.4, >= 1.4.4)
|
||||
mime-types (~> 3.3, >= 3.3.1)
|
||||
multi_test (~> 0.1, >= 0.1.2)
|
||||
sys-uname (~> 1.2, >= 1.2.2)
|
||||
cucumber-core (9.0.0)
|
||||
cucumber-core (9.0.1)
|
||||
cucumber-gherkin (~> 18.1, >= 18.1.0)
|
||||
cucumber-messages (~> 15.0, >= 15.0.0)
|
||||
cucumber-tag-expressions (~> 3.0, >= 3.0.1)
|
||||
|
@ -103,24 +103,21 @@ GEM
|
|||
cucumber-messages (15.0.0)
|
||||
protobuf-cucumber (~> 3.10, >= 3.10.8)
|
||||
cucumber-tag-expressions (3.0.1)
|
||||
cucumber-wire (5.0.0)
|
||||
cucumber-core (~> 9.0, >= 9.0.0)
|
||||
cucumber-wire (5.0.1)
|
||||
cucumber-core (~> 9.0, >= 9.0.1)
|
||||
cucumber-cucumber-expressions (~> 12.1, >= 12.1.1)
|
||||
cucumber-messages (~> 15.0, >= 15.0.0)
|
||||
declarative (0.0.20)
|
||||
declarative-option (0.1.0)
|
||||
diff-lcs (1.4.4)
|
||||
digest-crc (0.6.3)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
down (5.2.1)
|
||||
addressable (~> 2.5)
|
||||
ejson (1.2.1)
|
||||
encrypted-environment (0.2.0)
|
||||
ejson (~> 1.2)
|
||||
erubi (1.10.0)
|
||||
escape (0.0.4)
|
||||
ethon (0.12.0)
|
||||
ffi (>= 1.3.0)
|
||||
ethon (0.14.0)
|
||||
ffi (>= 1.15.0)
|
||||
faraday (1.4.1)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-net_http (~> 1.0)
|
||||
|
@ -144,7 +141,7 @@ GEM
|
|||
rexml
|
||||
signet (~> 0.14)
|
||||
webrick
|
||||
google-apis-iamcredentials_v1 (0.2.0)
|
||||
google-apis-iamcredentials_v1 (0.3.0)
|
||||
google-apis-core (~> 0.1)
|
||||
google-apis-storage_v1 (0.3.0)
|
||||
google-apis-core (~> 0.1)
|
||||
|
@ -162,7 +159,7 @@ GEM
|
|||
google-cloud-core (~> 1.2)
|
||||
googleauth (~> 0.9)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (0.16.0)
|
||||
googleauth (0.16.2)
|
||||
faraday (>= 0.17.3, < 2.0)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
|
@ -174,7 +171,7 @@ GEM
|
|||
i18n (1.8.10)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.5.1)
|
||||
jwt (2.2.2)
|
||||
jwt (2.2.3)
|
||||
loofah (2.9.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
|
@ -184,8 +181,7 @@ GEM
|
|||
mime-types (3.3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2021.0225)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.5.1)
|
||||
mini_mime (1.1.0)
|
||||
minitest (5.14.4)
|
||||
minitest-reporters (1.4.3)
|
||||
ansi
|
||||
|
@ -201,8 +197,7 @@ GEM
|
|||
nap (1.1.0)
|
||||
naturally (2.2.1)
|
||||
netrc (0.11.0)
|
||||
nokogiri (1.11.4)
|
||||
mini_portile2 (~> 2.5.0)
|
||||
nokogiri (1.11.4-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
octokit (4.21.0)
|
||||
faraday (>= 0.9)
|
||||
|
@ -235,9 +230,9 @@ GEM
|
|||
rainbow (3.0.0)
|
||||
rake (13.0.3)
|
||||
regexp_parser (2.1.1)
|
||||
representable (3.0.4)
|
||||
representable (3.1.1)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.2.5)
|
||||
|
@ -294,6 +289,7 @@ GEM
|
|||
ffi (~> 1.1)
|
||||
thor (1.1.0)
|
||||
thread_safe (0.3.6)
|
||||
trailblazer-option (0.1.1)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (1.2.9)
|
||||
|
@ -310,7 +306,7 @@ GEM
|
|||
zeitwerk (2.4.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86_64-darwin-20
|
||||
|
||||
DEPENDENCIES
|
||||
byebug (~> 11.1)
|
||||
|
@ -320,7 +316,7 @@ DEPENDENCIES
|
|||
colorize (~> 0.8.1)
|
||||
cucumber (~> 6.0)
|
||||
down (~> 5.2)
|
||||
encrypted-environment (~> 0.2.0)
|
||||
ejson (~> 1.2)
|
||||
google-cloud-storage (~> 1.31)
|
||||
highline (~> 2.0)
|
||||
minitest
|
||||
|
|
171
Rakefile
171
Rakefile
|
@ -1,171 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "rake/testtask"
|
||||
require "rubygems"
|
||||
require "cucumber"
|
||||
require "cucumber/rake/task"
|
||||
require "mkmf"
|
||||
require "fileutils"
|
||||
require "google/cloud/storage"
|
||||
require "encrypted/environment"
|
||||
require "colorize"
|
||||
require "highline"
|
||||
require "tmpdir"
|
||||
require "json"
|
||||
require "zip"
|
||||
require "macho"
|
||||
|
||||
desc("Install git hooks")
|
||||
task :install_git_hooks do
|
||||
system("cp hooks/pre-commit .git/hooks/pre-commit")
|
||||
system("chmod u+x .git/hooks/pre-commit")
|
||||
puts("pre-commit hook installed on .git/hooks/")
|
||||
end
|
||||
|
||||
desc("Builds and archive a release version of tuist and tuistenv for local testing.")
|
||||
task :local_package do
|
||||
package
|
||||
end
|
||||
|
||||
desc("Builds, archives, and publishes tuist and tuistenv for release")
|
||||
task :release, [:version] do |_task, options|
|
||||
decrypt_secrets
|
||||
release(options[:version])
|
||||
end
|
||||
|
||||
desc("Publishes the installation scripts")
|
||||
task :release_scripts do
|
||||
decrypt_secrets
|
||||
release_scripts
|
||||
end
|
||||
|
||||
desc("Encrypt secret keys")
|
||||
task :encrypt_secrets do
|
||||
Encrypted::Environment.encrypt_ejson("secrets.ejson", private_key: ENV["SECRET_KEY"])
|
||||
end
|
||||
|
||||
def decrypt_secrets
|
||||
Encrypted::Environment.load_from_ejson("secrets.ejson", private_key: ENV["SECRET_KEY"])
|
||||
end
|
||||
|
||||
def release_scripts
|
||||
bucket = storage.bucket("tuist-releases")
|
||||
print_section("Uploading installation scripts to the tuist-releases bucket on GCS")
|
||||
bucket.create_file("script/install", "scripts/install").acl.public!
|
||||
bucket.create_file("script/uninstall", "scripts/uninstall").acl.public!
|
||||
end
|
||||
|
||||
def package
|
||||
print_section("Building tuist")
|
||||
FileUtils.mkdir_p("build")
|
||||
system("swift", "build", "--product", "tuist", "--configuration", "release")
|
||||
system(
|
||||
"swift", "build",
|
||||
"--product", "ProjectDescription",
|
||||
"--configuration", "release",
|
||||
"-Xswiftc", "-enable-library-evolution",
|
||||
"-Xswiftc", "-emit-module-interface",
|
||||
"-Xswiftc", "-emit-module-interface-path",
|
||||
"-Xswiftc", ".build/release/ProjectDescription.swiftinterface"
|
||||
)
|
||||
system(
|
||||
"swift", "build",
|
||||
"--product", "ProjectAutomation",
|
||||
"--configuration", "release",
|
||||
"-Xswiftc", "-enable-library-evolution",
|
||||
"-Xswiftc", "-emit-module-interface",
|
||||
"-Xswiftc", "-emit-module-interface-path",
|
||||
"-Xswiftc", ".build/release/ProjectAutomation.swiftinterface"
|
||||
)
|
||||
system("swift", "build", "--product", "tuistenv", "--configuration", "release")
|
||||
|
||||
build_templates_path = File.join(__dir__, ".build/release/Templates")
|
||||
script_path = File.join(__dir__, ".build/release/script")
|
||||
vendor_path = File.join(__dir__, ".build/release/vendor")
|
||||
|
||||
FileUtils.rm_rf(build_templates_path) if File.exist?(build_templates_path)
|
||||
FileUtils.cp_r(File.expand_path("Templates", __dir__), build_templates_path)
|
||||
FileUtils.rm_rf(script_path) if File.exist?(script_path)
|
||||
FileUtils.cp_r(File.expand_path("script", __dir__), script_path)
|
||||
FileUtils.cp_r(File.expand_path("projects/tuist/vendor", __dir__), vendor_path)
|
||||
|
||||
File.delete("tuist.zip") if File.exist?("tuist.zip")
|
||||
File.delete("tuistenv.zip") if File.exist?("tuistenv.zip")
|
||||
|
||||
Dir.chdir(".build/release") do
|
||||
system(
|
||||
"zip", "-q", "-r", "--symlinks",
|
||||
"tuist.zip", "tuist",
|
||||
"ProjectDescription.swiftmodule",
|
||||
"ProjectDescription.swiftdoc",
|
||||
"libProjectDescription.dylib",
|
||||
"ProjectDescription.swiftinterface",
|
||||
"ProjectAutomation.swiftmodule",
|
||||
"ProjectAutomation.swiftdoc",
|
||||
"libProjectAutomation.dylib",
|
||||
"ProjectAutomation.swiftinterface",
|
||||
"Templates",
|
||||
"vendor",
|
||||
"script"
|
||||
)
|
||||
system("zip", "-q", "-r", "--symlinks", "tuistenv.zip", "tuistenv")
|
||||
end
|
||||
|
||||
FileUtils.cp(".build/release/tuist.zip", "build/tuist.zip")
|
||||
FileUtils.cp(".build/release/tuistenv.zip", "build/tuistenv.zip")
|
||||
end
|
||||
|
||||
def release(version)
|
||||
if version.nil?
|
||||
version = cli.ask("Introduce the released version:")
|
||||
end
|
||||
|
||||
puts "Releasing #{version} 🚀"
|
||||
|
||||
package
|
||||
|
||||
bucket = storage.bucket("tuist-releases")
|
||||
|
||||
print_section("Uploading to the tuist-releases bucket on GCS")
|
||||
|
||||
bucket.create_file("build/tuist.zip", "#{version}/tuist.zip").acl.public!
|
||||
bucket.create_file("build/tuistenv.zip", "#{version}/tuistenv.zip").acl.public!
|
||||
|
||||
bucket.create_file("build/tuist.zip", "latest/tuist.zip").acl.public!
|
||||
bucket.create_file("build/tuistenv.zip", "latest/tuistenv.zip").acl.public!
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
version_path = File.join(tmp_dir, "version")
|
||||
File.write(version_path, version)
|
||||
bucket.create_file(version_path, "latest/version").acl.public!
|
||||
end
|
||||
end
|
||||
|
||||
def system(*args)
|
||||
Kernel.system(*args) || abort
|
||||
end
|
||||
|
||||
def cli
|
||||
@cli ||= HighLine.new
|
||||
end
|
||||
|
||||
def storage
|
||||
@storage ||= Google::Cloud::Storage.new(
|
||||
project_id: ENV["GCS_PROJECT_ID"],
|
||||
credentials: {
|
||||
type: ENV["GCS_TYPE"],
|
||||
project_id: ENV["GCS_PROJECT_ID"],
|
||||
private_key_id: ENV["GCS_PRIVATE_KEY_ID"],
|
||||
private_key: ENV["GCS_PRIVATE_KEY"],
|
||||
client_email: ENV["GCS_CLIENT_EMAIL"],
|
||||
client_id: ENV["GCS_CLIENT_ID"],
|
||||
auth_uri: ENV["GCS_AUTH_URI"],
|
||||
token_uri: ENV["GCS_TOKEN_URI"],
|
||||
auth_provider_x509_cert_url: ENV["GCS_AUTH_PROVIDER_X509_CERT_URL"],
|
||||
client_x509_cert_url: ENV["GCS_CLIENT_X509_CERT_URL"],
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def print_section(text)
|
||||
puts(text.bold.green)
|
||||
end
|
|
@ -10,10 +10,9 @@ let config = TapestryConfig(
|
|||
.pre(tool: "sudo", arguments: ["xcode-select", "-s", "/Applications/Xcode_12.app"]),
|
||||
.pre(.dependenciesCompatibility([.spm(.all)])),
|
||||
.pre(tool: "swift", arguments: ["test"]),
|
||||
// .pre(tool: "bundle", arguments: ["exec", "rake", "features"]),
|
||||
.pre(.docsUpdate),
|
||||
.post(tool: "bundle", arguments: ["exec", "rake", "release[\(Argument.version)]"]),
|
||||
.post(tool: "bundle", arguments: ["exec", "rake", "release_scripts"]),
|
||||
.post(tool: "./fourier", arguments: ["release", "tuist", "\(Argument.version)"]),
|
||||
.post(tool: "./fourier", arguments: ["release", "scripts"]),
|
||||
.post(
|
||||
.githubRelease(
|
||||
owner: "tuist",
|
||||
|
|
|
@ -43,7 +43,7 @@ To start working on the project, we can follow the steps below:
|
|||
- Ensure you have the NodeJS version specified in the `.nvmrc`
|
||||
- Ensure you have the Ruby version specified in the `.ruby-version`
|
||||
- Run `bundle install` to automatically install the required dependencies
|
||||
- Run `rake install_git_hooks` to automatically format the code following Tuist's conventions
|
||||
- Run `./fourier up` to automatically format the code following Tuist's conventions
|
||||
- Open `Package.swift` using Xcode
|
||||
|
||||
:::note Xcode
|
||||
|
|
|
@ -41,6 +41,12 @@ module Fourier
|
|||
desc "update", "Update project's components"
|
||||
subcommand "update", Commands::Update
|
||||
|
||||
desc "bundle", "Bundle tuist and tuistenv"
|
||||
subcommand "bundle", Commands::Bundle
|
||||
|
||||
desc "encrypt", "Encrypt content in the repository"
|
||||
subcommand "encrypt", Commands::Encrypt
|
||||
|
||||
desc "focus TARGET", "Edit Tuist's project focusing on the target TARGET"
|
||||
def focus(target)
|
||||
Services::Focus.call(target: target)
|
||||
|
@ -106,6 +112,9 @@ module Fourier
|
|||
Services::Check.call
|
||||
end
|
||||
|
||||
desc "release", "Release the Tuist"
|
||||
subcommand "release", Commands::Release
|
||||
|
||||
def self.exit_on_failure?
|
||||
true
|
||||
end
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
require "tmpdir"
|
||||
|
||||
module Fourier
|
||||
module Commands
|
||||
class Bundle < Base
|
||||
desc "tuist", "Bundle tuist"
|
||||
option(
|
||||
:output,
|
||||
desc: "The directory in which the vendored tuist will be generated",
|
||||
type: :string,
|
||||
required: false,
|
||||
aliases: :p,
|
||||
)
|
||||
def tuist
|
||||
output_directory = options[:output]
|
||||
output_directory ||= File.expand_path("build", Constants::ROOT_DIRECTORY)
|
||||
Services::Bundle::Tuist.call(output_directory: output_directory)
|
||||
end
|
||||
|
||||
desc "tuistenv", "Bundle tuistenv"
|
||||
option(
|
||||
:output,
|
||||
desc: "The directory in which the vendored tuistenv will be generated",
|
||||
type: :string,
|
||||
required: false,
|
||||
aliases: :p,
|
||||
)
|
||||
def tuistenv
|
||||
output_directory = options[:output]
|
||||
output_directory ||= File.expand_path("build", Constants::ROOT_DIRECTORY)
|
||||
Services::Bundle::Tuistenv.call(output_directory: output_directory)
|
||||
end
|
||||
|
||||
desc "all", "Bundle tuistenv and tuist"
|
||||
option(
|
||||
:output,
|
||||
desc: "The directory in which the vendored tuist and tuistenv will be generated",
|
||||
type: :string,
|
||||
required: false,
|
||||
aliases: :p,
|
||||
)
|
||||
def all
|
||||
output_directory = options[:output]
|
||||
output_directory ||= File.expand_path("build", Constants::ROOT_DIRECTORY)
|
||||
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
Services::Bundle::Tuist.call(
|
||||
output_directory: output_directory,
|
||||
build_directory: tmp_dir
|
||||
)
|
||||
Services::Bundle::Tuistenv.call(
|
||||
output_directory: output_directory,
|
||||
build_directory: tmp_dir
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
module Fourier
|
||||
module Commands
|
||||
class Encrypt < Base
|
||||
desc "secrets", "Encrypt the secrets in this repository"
|
||||
def secrets
|
||||
Services::Encrypt::Secrets.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,6 +4,7 @@ module Fourier
|
|||
class GitHub < Base
|
||||
desc "cancel-workflows SUBCOMMAND ...ARGS", "Cancels all the running workflows"
|
||||
def cancel_workflows
|
||||
Utilities::Secrets.decrypt
|
||||
Services::GitHub::CancelWorkflows.call
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
module Fourier
|
||||
module Commands
|
||||
class Release < Base
|
||||
desc "tuist VERSION", "Bundles and uploads Tuist to GCS"
|
||||
def tuist(version)
|
||||
Utilities::Secrets.decrypt
|
||||
|
||||
output_directory ||= File.expand_path("build", Constants::ROOT_DIRECTORY)
|
||||
Services::Bundle::Tuist.call(output_directory: output_directory)
|
||||
Services::Bundle::Tuistenv.call(output_directory: output_directory)
|
||||
Utilities::Output.section("Uploading tuist and tuistenv scripts to GCS...")
|
||||
Services::Release::Tuist.call(
|
||||
version: version,
|
||||
tuistenv_zip_path: File.join(output_directory, "tuist.zip"),
|
||||
tuist_zip_path: File.join(output_directory, "tuistenv.zip"),
|
||||
)
|
||||
Utilities::Output.success("tuist and tuistenv uploaded to GCS")
|
||||
end
|
||||
|
||||
desc "scripts", "Bundles and uploads the installation scripts to GCS"
|
||||
def scripts
|
||||
Utilities::Secrets.decrypt
|
||||
Utilities::Output.section("Uploading installation scripts to GCS...")
|
||||
Services::Release::Scripts.call
|
||||
Utilities::Output.success("Scripts successfully uploaded")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
module Fourier
|
||||
module Constants
|
||||
module GoogleCloud
|
||||
RELEASES_BUCKET = "tuist-releases"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,124 @@
|
|||
# frozen_string_literal: true
|
||||
require "fileutils"
|
||||
require "tmpdir"
|
||||
|
||||
module Fourier
|
||||
module Services
|
||||
module Bundle
|
||||
class Tuist < Base
|
||||
attr_reader :output_directory
|
||||
attr_reader :build_directory
|
||||
|
||||
def initialize(output_directory:, build_directory: nil)
|
||||
@output_directory = output_directory
|
||||
@build_directory = build_directory
|
||||
end
|
||||
|
||||
def call
|
||||
output_directory = File.expand_path("build", Constants::ROOT_DIRECTORY) if output_directory.nil?
|
||||
FileUtils.mkdir_p(output_directory) unless Dir.exist?(output_directory)
|
||||
|
||||
in_build_directory do |build_directory|
|
||||
Utilities::Output.section("Building Tuist...")
|
||||
build_tuist(build_directory: build_directory)
|
||||
|
||||
Utilities::Output.section("Building ProjectAutomation...")
|
||||
build_project_automation(build_directory: build_directory)
|
||||
|
||||
Utilities::Output.section("Building ProjectDescription...")
|
||||
build_project_description(build_directory: build_directory)
|
||||
|
||||
Dir.mktmpdir do |vendor_directory|
|
||||
FileUtils.cp_r(
|
||||
File.expand_path("projects/tuist/vendor", Constants::ROOT_DIRECTORY),
|
||||
File.expand_path("vendor", vendor_directory)
|
||||
)
|
||||
FileUtils.cp_r(
|
||||
File.expand_path("Templates", Constants::ROOT_DIRECTORY),
|
||||
File.expand_path("Templates", vendor_directory)
|
||||
)
|
||||
[
|
||||
"tuist", "ProjectDescription.swiftmodule", "ProjectDescription.swiftdoc",
|
||||
"libProjectDescription.dylib", "ProjectDescription.swiftinterface",
|
||||
"ProjectAutomation.swiftmodule", "ProjectAutomation.swiftdoc", "ProjectAutomation.swiftinterface"
|
||||
].each do |file|
|
||||
FileUtils.cp(
|
||||
File.expand_path("release/#{file}", build_directory),
|
||||
File.expand_path(file, vendor_directory)
|
||||
)
|
||||
end
|
||||
|
||||
Dir.chdir(vendor_directory) do
|
||||
output_zip_path = File.expand_path("tuist.zip", output_directory)
|
||||
Utilities::Output.section("Generating #{output_zip_path}...")
|
||||
Utilities::System.system(
|
||||
"zip", "-q", "-r", "--symlinks",
|
||||
output_zip_path,
|
||||
"tuist",
|
||||
"ProjectDescription.swiftmodule",
|
||||
"ProjectDescription.swiftdoc",
|
||||
"libProjectDescription.dylib",
|
||||
"ProjectDescription.swiftinterface",
|
||||
"ProjectAutomation.swiftmodule",
|
||||
"ProjectAutomation.swiftdoc",
|
||||
"ProjectAutomation.swiftinterface",
|
||||
"Templates",
|
||||
"vendor"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def in_build_directory
|
||||
unless build_directory.nil?
|
||||
yield(build_directory)
|
||||
else
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
yield(tmp_dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def build_tuist(build_directory:)
|
||||
Utilities::System.system(
|
||||
"swift", "build",
|
||||
"--product", "tuist",
|
||||
"--configuration", "release",
|
||||
"--build-path", build_directory,
|
||||
"--package-path", Constants::ROOT_DIRECTORY
|
||||
)
|
||||
end
|
||||
|
||||
def build_project_description(build_directory:)
|
||||
Utilities::System.system(
|
||||
"swift", "build",
|
||||
"--product", "ProjectDescription",
|
||||
"--configuration", "release",
|
||||
"-Xswiftc", "-enable-library-evolution",
|
||||
"-Xswiftc", "-emit-module-interface",
|
||||
"-Xswiftc", "-emit-module-interface-path",
|
||||
"-Xswiftc", File.expand_path("release/ProjectDescription.swiftinterface", build_directory),
|
||||
"--build-path", build_directory,
|
||||
"--package-path", Constants::ROOT_DIRECTORY
|
||||
)
|
||||
end
|
||||
|
||||
def build_project_automation(build_directory:)
|
||||
Utilities::System.system(
|
||||
"swift", "build",
|
||||
"--product", "ProjectAutomation",
|
||||
"--configuration", "release",
|
||||
"-Xswiftc", "-enable-library-evolution",
|
||||
"-Xswiftc", "-emit-module-interface",
|
||||
"-Xswiftc", "-emit-module-interface-path",
|
||||
"-Xswiftc", File.expand_path("release/ProjectAutomation.swiftinterface", build_directory),
|
||||
"--build-path", build_directory,
|
||||
"--package-path", Constants::ROOT_DIRECTORY
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
# frozen_string_literal: true
|
||||
require "fileutils"
|
||||
require "tmpdir"
|
||||
|
||||
module Fourier
|
||||
module Services
|
||||
module Bundle
|
||||
class Tuistenv < Base
|
||||
attr_reader :output_directory
|
||||
attr_reader :build_directory
|
||||
|
||||
def initialize(output_directory:, build_directory: nil)
|
||||
@output_directory = output_directory
|
||||
@build_directory = build_directory
|
||||
end
|
||||
|
||||
def call
|
||||
output_directory = File.expand_path("build", Constants::ROOT_DIRECTORY) if output_directory.nil?
|
||||
FileUtils.mkdir_p(output_directory) unless Dir.exist?(output_directory)
|
||||
|
||||
in_build_directory do |build_directory|
|
||||
Utilities::Output.section("Building Tuistenv...")
|
||||
build_tuistenv(build_directory: build_directory)
|
||||
|
||||
Dir.mktmpdir do |vendor_directory|
|
||||
FileUtils.cp(
|
||||
File.expand_path("release/tuistenv", build_directory),
|
||||
File.expand_path("tuistenv", vendor_directory)
|
||||
)
|
||||
|
||||
Dir.chdir(vendor_directory) do
|
||||
output_zip_path = File.expand_path("tuistenv.zip", output_directory)
|
||||
Utilities::Output.section("Generating #{output_zip_path}...")
|
||||
Utilities::System.system(
|
||||
"zip", "-q", "-r", "--symlinks",
|
||||
output_zip_path,
|
||||
"tuistenv"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def in_build_directory
|
||||
unless build_directory.nil?
|
||||
yield(build_directory)
|
||||
else
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
yield(tmp_dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def build_tuistenv(build_directory:)
|
||||
Utilities::System.system(
|
||||
"swift", "build",
|
||||
"--product", "tuistenv",
|
||||
"--configuration", "release",
|
||||
"--build-path", build_directory,
|
||||
"--package-path", Constants::ROOT_DIRECTORY
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5,13 +5,12 @@ module Fourier
|
|||
class CancelWorkflows < Base
|
||||
attr_reader :github_client
|
||||
|
||||
def initialize(github_client: Utilities::GitHubClient)
|
||||
def initialize(github_client: Utilities::GitHubClient.new)
|
||||
@github_client = github_client
|
||||
end
|
||||
|
||||
def call
|
||||
Utilities::Secrets.decrypt
|
||||
runs = github_client.repository_workflow_runs(Constants::REPOSITORY, status: "queued")
|
||||
runs = github_client.repository_workflow_runs(Constants::REPOSITORY, { status: "queued" })
|
||||
runs[:workflow_runs].each do |run|
|
||||
puts "Cancelling workflow run with id: #{run[:id]}"
|
||||
github_client.cancel_workflow_run(Constants::REPOSITORY, run[:id])
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
module Fourier
|
||||
module Services
|
||||
module Release
|
||||
class Scripts < Base
|
||||
attr_reader :storage
|
||||
|
||||
def initialize(
|
||||
storage: Fourier::Utilities::GoogleCloudStorage.new
|
||||
)
|
||||
@storage = storage
|
||||
end
|
||||
|
||||
|
||||
def call
|
||||
bucket = storage.bucket(Constants::GoogleCloud::RELEASES_BUCKET)
|
||||
install_path = File.expand_path("script/install", Constants::ROOT_DIRECTORY)
|
||||
uninstall_path = File.expand_path("script/uninstall", Constants::ROOT_DIRECTORY)
|
||||
|
||||
bucket.create_file(install_path, "scripts/install").acl.public!
|
||||
bucket.create_file(uninstall_path, "scripts/uninstall").acl.public!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
module Fourier
|
||||
module Services
|
||||
module Release
|
||||
class Tuist < Base
|
||||
attr_reader :tuistenv_zip_path, :tuist_zip_path, :storage, :version
|
||||
|
||||
def initialize(
|
||||
version:,
|
||||
tuistenv_zip_path:,
|
||||
tuist_zip_path:,
|
||||
storage: Utilities::GoogleCloudStorage.new()
|
||||
)
|
||||
@version = version
|
||||
@tuistenv_zip_path = tuistenv_zip_path
|
||||
@tuist_zip_path = tuist_zip_path
|
||||
@storage = storage
|
||||
end
|
||||
|
||||
def call
|
||||
bucket = storage.bucket(Constants::GoogleCloud::RELEASES_BUCKET)
|
||||
|
||||
bucket.create_file(tuist_zip_path, "#{version}/tuist.zip").acl.public!
|
||||
bucket.create_file(tuistenv_zip_path, "#{version}/tuistenv.zip").acl.public!
|
||||
|
||||
bucket.create_file(tuist_zip_path, "latest/tuist.zip").acl.public!
|
||||
bucket.create_file(tuistenv_zip_path, "latest/tuistenv.zip").acl.public!
|
||||
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
version_path = File.join(tmp_dir, "version")
|
||||
File.write(version_path, version)
|
||||
bucket.create_file(version_path, "latest/version").acl.public!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,8 +4,18 @@ module Fourier
|
|||
module Services
|
||||
class Up < Base
|
||||
def call
|
||||
puts "Not implemented yet"
|
||||
install_git_hooks
|
||||
end
|
||||
|
||||
private
|
||||
def install_git_hooks
|
||||
Utilities::Output.section("Installing Git pre-commit hooks")
|
||||
src_path = File.join(Constants::ROOT_DIRECTORY, "hooks/pre-commit")
|
||||
dst_path = File.join(Constants::ROOT_DIRECTORY, ".git/hooks/pre-commit")
|
||||
|
||||
FileUtils.cp(src_path, dst_path)
|
||||
Utilities::System.system("chmod", "u+x", dst_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
require "json"
|
||||
require "tmpdir"
|
||||
require "fileutils"
|
||||
|
||||
module Fourier
|
||||
module Utilities
|
||||
module EncryptedEnvironment
|
||||
EnvironmentError = Class.new(StandardError)
|
||||
MissingEjson = Class.new(EnvironmentError)
|
||||
|
||||
def self.load_from_ejson(ejson_path, private_key: nil)
|
||||
decrypt_environment(
|
||||
ejson_path: ejson_path,
|
||||
private_key: private_key
|
||||
).each do |key, value|
|
||||
ENV[key] = value if key != "_public_key"
|
||||
end
|
||||
end
|
||||
|
||||
def self.encrypt_ejson(ejson_path, private_key: nil)
|
||||
with_secrets(ejson_path: ejson_path, private_key: private_key) do |path|
|
||||
%x(EJSON_KEYDIR=#{path} #{binary_path} encrypt #{ejson_path})
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
private
|
||||
def binary_path
|
||||
File.expand_path("../vendor/ejson", __dir__)
|
||||
end
|
||||
|
||||
def decrypt_environment(ejson_path:, private_key: nil)
|
||||
with_secrets(ejson_path: ejson_path, private_key: private_key) do |path|
|
||||
output = %x(EJSON_KEYDIR=#{path} #{binary_path} decrypt #{ejson_path})
|
||||
JSON.parse(output)
|
||||
end
|
||||
end
|
||||
|
||||
def with_secrets(ejson_path:, private_key: nil)
|
||||
raise MissingEjson unless File.exist?(ejson_path)
|
||||
|
||||
content = File.read(ejson_path)
|
||||
ejson = JSON.parse(content)
|
||||
public_key = ejson["_public_key"]
|
||||
should_delete = false
|
||||
|
||||
if !private_key.nil?
|
||||
secrets_path = Dir.mktmpdir
|
||||
should_delete = true
|
||||
File.write(File.join(secrets_path, public_key), private_key)
|
||||
yield(secrets_path)
|
||||
else
|
||||
yield("/opt/ejson/keys/")
|
||||
end
|
||||
ensure
|
||||
FileUtils.remove_dir(secrets_path, true) if should_delete
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
require "google/cloud/storage"
|
||||
|
||||
module Fourier
|
||||
module Utilities
|
||||
class GoogleCloudStorage
|
||||
def self.new(environment: ENV)
|
||||
Google::Cloud::Storage.new(
|
||||
project_id: ENV["GCS_PROJECT_ID"],
|
||||
credentials: {
|
||||
type: ENV["GCS_TYPE"],
|
||||
project_id: ENV["GCS_PROJECT_ID"],
|
||||
private_key_id: ENV["GCS_PRIVATE_KEY_ID"],
|
||||
private_key: ENV["GCS_PRIVATE_KEY"],
|
||||
client_email: ENV["GCS_CLIENT_EMAIL"],
|
||||
client_id: ENV["GCS_CLIENT_ID"],
|
||||
auth_uri: ENV["GCS_AUTH_URI"],
|
||||
token_uri: ENV["GCS_TOKEN_URI"],
|
||||
auth_provider_x509_cert_url: ENV["GCS_AUTH_PROVIDER_X509_CERT_URL"],
|
||||
client_x509_cert_url: ENV["GCS_CLIENT_X509_CERT_URL"],
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
require "colorize"
|
||||
|
||||
module Fourier
|
||||
module Utilities
|
||||
class Output
|
||||
def self.section(message)
|
||||
STDERR.puts(message.cyan.bold)
|
||||
end
|
||||
|
||||
def self.subsection(message)
|
||||
STDERR.puts(message.cyan)
|
||||
end
|
||||
|
||||
def self.error(message)
|
||||
STDERR.puts(message.red.bold)
|
||||
end
|
||||
|
||||
def self.warning(message)
|
||||
STDOUT.puts(message.yellow.bold)
|
||||
end
|
||||
|
||||
def self.success(message)
|
||||
STDOUT.puts(message.green.bold)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
require "encrypted/environment"
|
||||
|
||||
module Fourier
|
||||
module Utilities
|
||||
module Secrets
|
||||
def self.decrypt
|
||||
Encrypted::Environment.load_from_ejson(secrets_ejson_path, private_key: ENV["SECRET_KEY"])
|
||||
EncryptedEnvironment.load_from_ejson(secrets_ejson_path, private_key: ENV["SECRET_KEY"])
|
||||
end
|
||||
|
||||
def self.encrypt
|
||||
Encrypted::Environment.load_from_ejson(secrets_ejson_path, private_key: ENV["SECRET_KEY"])
|
||||
EncryptedEnvironment.load_from_ejson(secrets_ejson_path, private_key: ENV["SECRET_KEY"])
|
||||
end
|
||||
|
||||
def self.secrets_ejson_path
|
||||
|
|
Binary file not shown.
|
@ -7,7 +7,6 @@ module Fourier
|
|||
class CancelWorkflowsTest < TestCase
|
||||
def test_cancels_workflows
|
||||
# Given
|
||||
Utilities::Secrets.expects(:decrypt)
|
||||
github_client = mock("github_client")
|
||||
.responds_like_instance_of(Utilities::GitHubClient)
|
||||
queued_jobs = {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
require "test_helper"
|
||||
|
||||
module Fourier
|
||||
module Services
|
||||
class UpTest < TestCase
|
||||
include TestHelpers::SupressOutput
|
||||
|
||||
def test_call_installs_git_hooks
|
||||
# Given
|
||||
src_path = File.join(Constants::ROOT_DIRECTORY, "hooks/pre-commit")
|
||||
dst_path = File.join(Constants::ROOT_DIRECTORY, ".git/hooks/pre-commit")
|
||||
FileUtils
|
||||
.expects(:cp)
|
||||
.with(src_path, dst_path)
|
||||
Utilities::System
|
||||
.expects(:system)
|
||||
.with("chmod", "u+x", dst_path)
|
||||
|
||||
# When/Then
|
||||
supressing_output do
|
||||
Up.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue