brasa 0.2.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7fcda95aeadc11d59d3858cc26974447cde69ee79d5c43fcfb4dc8a7748371e
4
- data.tar.gz: 65bdf2bd120bd7fb33ba3875a12de42be1c9053f89680d730b3628312199a71a
3
+ metadata.gz: e07ee00f7ac9e995d27c4e920a9408358f9d8d026682cac95fb43cd89b63289b
4
+ data.tar.gz: 5ff8c1b1dfbacbdfecd63f4fb1a6bb06a6d438ad3a69b3bc7296d784a291b2b1
5
5
  SHA512:
6
- metadata.gz: 6b50ce6543904e84f0e324d090367dc7ee5ed4d7d51a35034dffb45b3dad51ed4e695b4cda104c9c0521979f81c0b5906f62c0348d4f5f56c703f744d5b20d98
7
- data.tar.gz: b7d240ea6ae2b0d7180f7401d9800285ddfb7a254e3d22c5bdbb99005a9b2fb92677259130adec78bbfe800eb485b5ee5aeaf0ad7799b4d0964e8dee2aefd7c8
6
+ metadata.gz: 6411273f8dc5913936a36e4df53d71c1e582338ae59a43fa3cd1a90e8e1aeb48d89e678a0108af9fcf6d019c6eabf1548a3dd75e4aee821bc1eda7972df49078
7
+ data.tar.gz: e9f02d023fc2a852d8ec826afa5801d89ebb133d278ccae56f59efc971e7a3c78ac9e8d449080e902a275543798d43c05259fa2be2e92fbf0e080f15f37edc20
@@ -1,4 +1,5 @@
1
1
  require "faraday"
2
+ require "faraday/multipart"
2
3
  require "json"
3
4
 
4
5
  module Brasa
@@ -43,8 +44,25 @@ module Brasa
43
44
  request(:delete, path)
44
45
  end
45
46
 
47
+ def upload(path, file_path:, params: {})
48
+ response = upload_connection.post(path) do |req|
49
+ req.body = params.merge(source: Faraday::Multipart::FilePart.new(file_path, "application/gzip"))
50
+ end
51
+ handle_response(response)
52
+ end
53
+
46
54
  private
47
55
 
56
+ def upload_connection
57
+ @upload_connection ||= Faraday.new(url: @api_url) do |conn|
58
+ conn.request :multipart
59
+ conn.request :url_encoded
60
+ conn.response :json
61
+ conn.headers["Authorization"] = "Bearer #{@token}" if @token
62
+ conn.adapter Faraday.default_adapter
63
+ end
64
+ end
65
+
48
66
  def request(method, path, body: nil, params: nil)
49
67
  response = connection.public_send(method, path) do |req|
50
68
  req.params = params if params && !params.empty?
@@ -1,26 +1,34 @@
1
1
  require "brasa/commands/base"
2
+ require "brasa/source_packer"
2
3
 
3
4
  module Brasa
4
5
  module Commands
5
6
  class Deploy < Base
6
- POLL_INTERVAL = 3
7
+ POLL_INTERVAL = 5
7
8
  MAX_POLLS = 120
8
9
 
9
10
  def execute(options = {})
10
11
  require_auth!
11
12
  slug = app_slug
12
13
 
13
- info("Iniciando deploy de #{slug}...")
14
+ info("Empacotando código...")
15
+ archive_path = SourcePacker.pack
14
16
 
15
- body = {}
16
- body[:branch] = options["branch"] if options["branch"]
17
+ size_kb = File.size(archive_path) / 1024
18
+ info("Enviando #{size_kb}KB para o servidor...")
17
19
 
18
- deploy = api.post("/api/v1/apps/#{slug}/deploys", body: body.empty? ? {} : body)
19
- info("Deploy ##{deploy["id"]} criado. Aguardando...")
20
+ deploy = api.upload(
21
+ "/api/v1/apps/#{slug}/deploys",
22
+ file_path: archive_path,
23
+ params: { branch: options["branch"] || "main" }
24
+ )
25
+ info("Deploy ##{deploy["id"]} criado. Aguardando build e deploy...")
20
26
 
21
27
  wait_for_deploy(slug, deploy["id"])
22
28
  rescue Api::Client::ApiError => e
23
29
  error("Erro: #{e.message}")
30
+ ensure
31
+ FileUtils.rm_f(archive_path) if archive_path
24
32
  end
25
33
 
26
34
  private
@@ -1,4 +1,5 @@
1
1
  require "brasa/commands/base"
2
+ require "brasa/source_packer"
2
3
 
3
4
  module Brasa
4
5
  module Commands
@@ -10,21 +11,24 @@ module Brasa
10
11
  require_auth!
11
12
  config = project_config
12
13
 
13
- info("Criando app #{config[:app]}...")
14
-
15
- app = create_app(config)
16
- info("App #{app["slug"]} criado. Provisionando infraestrutura...")
14
+ app = find_or_create_app(config)
15
+ slug = app["slug"]
17
16
 
18
- unless wait_for_provisioning(app["slug"])
19
- return
17
+ if app["status"] == "active"
18
+ info("Iniciando deploy...")
19
+ else
20
+ info("Provisionando infraestrutura...")
21
+ unless wait_for_provisioning(slug)
22
+ return
23
+ end
24
+ success("Infraestrutura provisionada!")
25
+ info("Iniciando primeiro deploy...")
20
26
  end
21
- success("Infraestrutura provisionada!")
22
27
 
23
- info("Iniciando primeiro deploy...")
24
- deploy = trigger_deploy(app["slug"])
28
+ deploy = trigger_deploy(slug)
25
29
 
26
- if wait_for_deploy(app["slug"], deploy["id"])
27
- success("Deploy concluído! App disponível em https://#{app["slug"]}.usebrasa.com.br")
30
+ if wait_for_deploy(slug, deploy["id"])
31
+ success("Deploy concluído! App disponível em https://#{slug}.usebrasa.com.br")
28
32
  end
29
33
  rescue Api::Client::ValidationError => e
30
34
  error("Erro ao criar app: #{e.message}")
@@ -34,18 +38,55 @@ module Brasa
34
38
 
35
39
  private
36
40
 
41
+ def find_or_create_app(config)
42
+ existing = api.get("/api/v1/apps/#{config[:app]}")
43
+ info("App #{existing["slug"]} encontrado (#{existing["status"]}).")
44
+ ensure_repo_url(existing["slug"])
45
+ existing
46
+ rescue Api::Client::NotFoundError
47
+ info("Criando app #{config[:app]}...")
48
+ create_app(config)
49
+ end
50
+
51
+ def ensure_repo_url(slug)
52
+ repo = detect_git_remote
53
+ return unless repo
54
+
55
+ api.patch("/api/v1/apps/#{slug}", body: { app: { repo_url: repo } })
56
+ rescue Api::Client::ApiError
57
+ # Não bloquear o fluxo se falhar ao atualizar repo
58
+ end
59
+
37
60
  def create_app(config)
38
61
  api.post("/api/v1/apps", body: {
39
62
  name: config[:app],
40
63
  stack: config[:stack],
41
64
  preset: config[:preset],
42
65
  region: config[:region],
66
+ repo_url: detect_git_remote,
43
67
  repo_branch: config[:branch]
44
68
  })
45
69
  end
46
70
 
47
71
  def trigger_deploy(slug)
48
- api.post("/api/v1/apps/#{slug}/deploys")
72
+ info("Empacotando código...")
73
+ archive_path = SourcePacker.pack
74
+ size_kb = File.size(archive_path) / 1024
75
+ info("Enviando #{size_kb}KB para o servidor...")
76
+
77
+ deploy = api.upload(
78
+ "/api/v1/apps/#{slug}/deploys",
79
+ file_path: archive_path,
80
+ params: { branch: project_config[:branch] || "main" }
81
+ )
82
+ deploy
83
+ ensure
84
+ FileUtils.rm_f(archive_path) if archive_path
85
+ end
86
+
87
+ def detect_git_remote
88
+ remote = `git remote get-url origin 2>/dev/null`.strip
89
+ remote.empty? ? nil : remote
49
90
  end
50
91
 
51
92
  def wait_for_provisioning(slug)
@@ -0,0 +1,48 @@
1
+ require "tmpdir"
2
+ require "open3"
3
+
4
+ module Brasa
5
+ class SourcePacker
6
+ IGNORE_PATTERNS = %w[
7
+ .git node_modules tmp log .bundle vendor/bundle
8
+ .brasa.yml .env .env.* *.log coverage
9
+ ].freeze
10
+
11
+ def self.pack(directory = Dir.pwd)
12
+ new(directory).pack
13
+ end
14
+
15
+ def initialize(directory)
16
+ @directory = directory
17
+ end
18
+
19
+ def pack
20
+ archive_path = File.join(Dir.tmpdir, "brasa-source-#{Time.now.to_i}.tar.gz")
21
+
22
+ excludes = build_excludes
23
+ cmd = [ "tar", "czf", archive_path ] + excludes + [ "-C", @directory, "." ]
24
+
25
+ _out, err, status = Open3.capture3(*cmd)
26
+ raise "Falha ao empacotar código: #{err}" unless status.success?
27
+
28
+ archive_path
29
+ end
30
+
31
+ private
32
+
33
+ def build_excludes
34
+ patterns = IGNORE_PATTERNS.dup
35
+
36
+ dockerignore = File.join(@directory, ".dockerignore")
37
+ if File.exist?(dockerignore)
38
+ File.readlines(dockerignore).each do |line|
39
+ line = line.strip
40
+ next if line.empty? || line.start_with?("#")
41
+ patterns << line
42
+ end
43
+ end
44
+
45
+ patterns.flat_map { |p| [ "--exclude", p ] }
46
+ end
47
+ end
48
+ end
data/lib/brasa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Brasa
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brasa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brasa
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: faraday-multipart
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: tty-prompt
42
56
  requirement: !ruby/object:Gem::Requirement
@@ -152,6 +166,7 @@ files:
152
166
  - lib/brasa/commands/status.rb
153
167
  - lib/brasa/commands/up.rb
154
168
  - lib/brasa/config.rb
169
+ - lib/brasa/source_packer.rb
155
170
  - lib/brasa/version.rb
156
171
  homepage: https://usebrasa.com.br
157
172
  licenses: