strata-cli 0.1.8 → 0.1.9

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/lib/strata/cli/ai/services/table_generator.rb +35 -20
  4. data/lib/strata/cli/api/client.rb +23 -63
  5. data/lib/strata/cli/api/response_error_handler.rb +115 -0
  6. data/lib/strata/cli/error_reporter.rb +4 -1
  7. data/lib/strata/cli/generators/datasource.rb +4 -3
  8. data/lib/strata/cli/generators/group.rb +37 -0
  9. data/lib/strata/cli/generators/migration.rb +2 -1
  10. data/lib/strata/cli/generators/project.rb +18 -11
  11. data/lib/strata/cli/generators/relation.rb +2 -1
  12. data/lib/strata/cli/generators/table.rb +5 -8
  13. data/lib/strata/cli/generators/templates/table.table_name.yml +1 -1
  14. data/lib/strata/cli/generators/test.rb +2 -1
  15. data/lib/strata/cli/guard.rb +4 -1
  16. data/lib/strata/cli/helpers/command_context.rb +8 -9
  17. data/lib/strata/cli/helpers/datasource_helper.rb +1 -1
  18. data/lib/strata/cli/helpers/description_helper.rb +2 -1
  19. data/lib/strata/cli/main.rb +15 -3
  20. data/lib/strata/cli/output.rb +103 -0
  21. data/lib/strata/cli/sub_commands/audit.rb +4 -3
  22. data/lib/strata/cli/sub_commands/branch.rb +163 -0
  23. data/lib/strata/cli/sub_commands/create.rb +1 -2
  24. data/lib/strata/cli/sub_commands/datasource.rb +2 -0
  25. data/lib/strata/cli/sub_commands/deploy.rb +14 -13
  26. data/lib/strata/cli/sub_commands/project.rb +4 -3
  27. data/lib/strata/cli/sub_commands/table.rb +9 -8
  28. data/lib/strata/cli/terminal.rb +7 -4
  29. data/lib/strata/cli/ui/field_editor.rb +21 -27
  30. data/lib/strata/cli/utils/deployment_monitor.rb +15 -34
  31. data/lib/strata/cli/utils/git.rb +78 -0
  32. data/lib/strata/cli/utils/import_manager.rb +4 -1
  33. data/lib/strata/cli/utils/test_reporter.rb +4 -32
  34. data/lib/strata/cli/utils/version_checker.rb +4 -8
  35. data/lib/strata/cli/utils.rb +3 -1
  36. data/lib/strata/cli/version.rb +1 -1
  37. data/lib/strata/cli.rb +4 -3
  38. metadata +4 -2
  39. data/lib/strata/cli/helpers/color_helper.rb +0 -103
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "group"
4
4
  require "yaml"
5
+ require_relative "../output"
5
6
 
6
7
  module Strata
7
8
  module CLI
@@ -23,7 +24,7 @@ module Strata
23
24
  # Write the updated template
24
25
  create_file output_path, updated_content
25
26
 
26
- say_status :created, output_path, :green
27
+ Output.print_status(:created, output_path, type: :success, context: self)
27
28
  end
28
29
 
29
30
  private
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "utils"
4
+ require_relative "output"
5
+
4
6
  module Strata
5
7
  module CLI
6
8
  module Guard
@@ -10,13 +12,14 @@ module Strata
10
12
  adapters
11
13
  version
12
14
  deploy
15
+ branch
13
16
  ].freeze
14
17
 
15
18
  def invoke_command(command, *args)
16
19
  Utils.exit_error_if_not_strata! unless ALLOWED_COMMANDS.include?(command.name)
17
20
  super
18
21
  rescue Strata::CommandError => e
19
- shell.say_error "ERROR: #{e.message}", :red
22
+ Output.print_error("ERROR: #{e.message}", context: self)
20
23
  exit 1
21
24
  end
22
25
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "tty-prompt"
4
4
  require_relative "datasource_helper"
5
- require_relative "color_helper"
5
+ require_relative "../output"
6
6
  require_relative "prompts"
7
7
  require_relative "../error_reporter"
8
8
 
@@ -10,6 +10,7 @@ module Strata
10
10
  module CLI
11
11
  module Helpers
12
12
  module CommandContext
13
+ include Output
13
14
  include DatasourceHelper
14
15
 
15
16
  def adapter
@@ -28,8 +29,7 @@ module Strata
28
29
  @table_fetch_result ||= begin
29
30
  tables = with_spinner("Fetching tables from #{datasource_key}...") { adapter.tables }
30
31
  if tables.empty?
31
- # Assuming Prompts and ColorHelper are available in the class or via module
32
- say Prompts::MSG_NO_TABLES_FOUND % datasource_key, ColorHelper.warning
32
+ say(Output.format(:warning, Prompts::MSG_NO_TABLES_FOUND % datasource_key), nil) if respond_to?(:say)
33
33
  {tables: [], failed: false}
34
34
  else
35
35
  {tables: tables, failed: false}
@@ -38,15 +38,14 @@ module Strata
38
38
  ErrorReporter.log_error(e, context: "create table: failed fetching tables for '#{datasource_key}'")
39
39
 
40
40
  if ErrorReporter.connection_error?(e)
41
- say "Could not connect to datasource '#{datasource_key}'.", ColorHelper.warning
41
+ say(Output.format(:warning, "Could not connect to datasource '#{datasource_key}'."), nil) if respond_to?(:say)
42
42
  else
43
- say "Could not fetch tables from datasource '#{datasource_key}'.", ColorHelper.warning
44
- say "Reason: #{ErrorReporter.user_message_for(e)}", ColorHelper.warning
43
+ say(Output.format(:warning, "Could not fetch tables from datasource '#{datasource_key}'."), nil) if respond_to?(:say)
44
+ say(Output.format(:warning, "Reason: #{ErrorReporter.user_message_for(e)}"), nil) if respond_to?(:say)
45
45
  end
46
46
 
47
- say "Hint: verify credentials/settings and run 'strata datasource test #{datasource_key}'.",
48
- ColorHelper.info
49
- say "Details logged to '#{ErrorReporter.log_relative_path}'.", ColorHelper.info
47
+ say(Output.format(:dim, "Hint: verify credentials/settings and run 'strata datasource test #{datasource_key}'."), nil) if respond_to?(:say)
48
+ say(Output.format(:info, "Details logged to '#{ErrorReporter.log_relative_path}'."), nil) if respond_to?(:say)
50
49
  {tables: [], failed: true}
51
50
  end
52
51
  end
@@ -8,7 +8,7 @@ module Strata
8
8
  redshift: %w[pg],
9
9
  mysql: %w[mysql2],
10
10
  sqlserver: %w[tiny_tds],
11
- athena: %w[aws-sdk-athena aws-sdk-s3],
11
+ athena: %w[aws-sdk-athena aws-sdk-s3 rexml],
12
12
  trino: %w[trino-client],
13
13
  sqlite: %w[sqlite3],
14
14
  duckdb: %w[duckdb]
@@ -11,7 +11,8 @@ module Strata
11
11
  if File.exist?(file_path)
12
12
  long_desc File.read(file_path)
13
13
  else
14
- warn "Warning: Description file not found at #{file_path}"
14
+ require_relative "../output"
15
+ Output.print_warning("Warning: Description file not found at #{file_path}")
15
16
  end
16
17
  end
17
18
  end
@@ -3,16 +3,19 @@
3
3
  require_relative "generators/project"
4
4
  require_relative "sub_commands/datasource"
5
5
  require_relative "sub_commands/deploy"
6
+ require_relative "sub_commands/branch"
6
7
  require_relative "sub_commands/project"
7
8
  require_relative "sub_commands/table"
8
9
  require_relative "sub_commands/create"
9
10
  require_relative "sub_commands/audit"
10
11
  require_relative "helpers/description_helper"
12
+ require_relative "output"
11
13
 
12
14
  module Strata
13
15
  module CLI
14
16
  class Main < Thor
15
17
  include Guard
18
+ include Output
16
19
  extend Helpers::DescriptionHelper
17
20
 
18
21
  def self.exit_on_failure?
@@ -30,21 +33,22 @@ module Strata
30
33
  repeatable: true
31
34
  option :source, aliases: ["s"], type: :string, desc: "URL of existing project"
32
35
  option :api_key, aliases: ["a"], type: :string, desc: "Api Key. Required if initializing existing project."
36
+ option :verbose, aliases: ["v"], type: :boolean, default: false,
37
+ desc: "Show detailed init output (file-by-file actions)."
33
38
 
34
39
  def init(project_name = nil)
35
40
  unless project_name || options[:source]
36
41
  raise Strata::CommandError, "PROJECT_NAME is required when not using --source option."
37
42
  end
38
43
 
39
- say_status :started, "Creating #{project_name || "project from source"} - #{options[:datasource]}",
40
- ColorHelper.info
44
+ print_status(:created, (project_name || "project from source").to_s, type: :info)
41
45
  invoke Generators::Project, [project_name], options
42
46
  end
43
47
 
44
48
  desc "adapters", "Lists supported data warehouse adapters"
45
49
  def adapters
46
50
  out = " SUPPORTED ADAPTERS: \n\t#{DWH.adapters.keys.join("\n\t")}"
47
- say out, ColorHelper.info
51
+ print_info(out)
48
52
  end
49
53
 
50
54
  desc "datasource", "Manage project datasources"
@@ -56,12 +60,20 @@ module Strata
56
60
  desc "table", "Manage semantic tables"
57
61
  subcommand "table", SubCommands::Table
58
62
 
63
+ desc "tables", "List all semantic models in the project"
64
+ def tables
65
+ SubCommands::Table.start(["list"])
66
+ end
67
+
59
68
  desc "audit", "Audit project configuration and models"
60
69
  subcommand "audit", SubCommands::Audit
61
70
 
62
71
  desc "deploy", "Deploy project to Strata server"
63
72
  subcommand "deploy", SubCommands::Deploy
64
73
 
74
+ desc "branch", "Manage Strata server branches"
75
+ subcommand "branch", SubCommands::Branch
76
+
65
77
  desc "project", "Manage project configuration"
66
78
  subcommand "project", SubCommands::Project
67
79
 
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "pastel"
5
+
6
+ module Strata
7
+ module CLI
8
+ module Output
9
+ THEME = {
10
+ success: :green,
11
+ error: %i[red bold],
12
+ warning: :yellow,
13
+ info: :cyan,
14
+ title: %i[cyan bold],
15
+ highlight: %i[cyan bold],
16
+ dim: :bright_black,
17
+ primary: :blue,
18
+ secondary: :magenta,
19
+ border: %i[cyan dim],
20
+ selected: %i[green bold],
21
+ disabled: :bright_black
22
+ }.freeze
23
+
24
+ class << self
25
+ def pastel
26
+ @pastel ||= Pastel.new(enabled: $stdout.tty?)
27
+ end
28
+
29
+ def shell_for(context = nil)
30
+ return context.shell if context&.respond_to?(:shell)
31
+ return context if context.is_a?(Thor::Shell)
32
+
33
+ Thor::Shell::Color.new
34
+ end
35
+
36
+ def print_info(message, context: nil)
37
+ shell_for(context).say(format(:info, message))
38
+ end
39
+
40
+ def print_success(message, context: nil)
41
+ shell_for(context).say(format(:success, message))
42
+ end
43
+
44
+ def print_warning(message, context: nil)
45
+ shell_for(context).say(format(:warning, message))
46
+ end
47
+
48
+ def print_error(message, context: nil)
49
+ shell_for(context).say_error(format(:error, message))
50
+ end
51
+
52
+ def print_hint(message, context: nil, stderr: false)
53
+ shell = shell_for(context)
54
+ formatted = format(:dim, message)
55
+ stderr ? shell.say_error(formatted) : shell.say(formatted)
56
+ end
57
+
58
+ # Standard status output with Thor's prefix formatting.
59
+ # We keep the label color via Thor, but decorate the message via Output theme.
60
+ def print_status(label, message, type: :info, context: nil)
61
+ shell = shell_for(context)
62
+ shell.say_status(label, format(type, message), thor_color(type))
63
+ end
64
+
65
+ def format(type, message)
66
+ return "" if message.nil?
67
+
68
+ styles = THEME[type]
69
+ return message.to_s unless styles
70
+
71
+ if styles.is_a?(Array)
72
+ pastel.decorate(message.to_s, *styles)
73
+ else
74
+ pastel.send(styles, message.to_s)
75
+ end
76
+ end
77
+
78
+ # Thor only understands a limited palette; keep it simple/stable.
79
+ def thor_color(type)
80
+ case type
81
+ when :success then :green
82
+ when :error then :red
83
+ when :warning then :yellow
84
+ when :info, :title, :border then :cyan
85
+ when :primary then :blue
86
+ when :secondary then :magenta
87
+ when :dim then :white
88
+ else
89
+ :white
90
+ end
91
+ end
92
+ end
93
+
94
+ # Convenience instance methods for Thor classes.
95
+ def print_info(message) = Output.print_info(message, context: self)
96
+ def print_success(message) = Output.print_success(message, context: self)
97
+ def print_warning(message) = Output.print_warning(message, context: self)
98
+ def print_error(message) = Output.print_error(message, context: self)
99
+ def print_hint(message, stderr: false) = Output.print_hint(message, context: self, stderr: stderr)
100
+ def print_status(label, message, type: :info) = Output.print_status(label, message, type: type, context: self)
101
+ end
102
+ end
103
+ end
@@ -3,7 +3,7 @@
3
3
  require_relative "../guard"
4
4
  require_relative "../terminal"
5
5
  require_relative "../credentials"
6
- require_relative "../helpers/color_helper"
6
+ require_relative "../output"
7
7
  require_relative "../helpers/datasource_helper"
8
8
  require_relative "../utils/yaml_import_resolver"
9
9
  require_relative "../utils/import_manager"
@@ -17,6 +17,7 @@ module Strata
17
17
  include Thor::Actions
18
18
  include Guard
19
19
  include Terminal
20
+ include Output
20
21
  include DatasourceHelper
21
22
 
22
23
  REQUIRED_KEYS_FOR_TABLE_MODEL = %w[name physical_name fields datasource].freeze
@@ -61,7 +62,7 @@ module Strata
61
62
  if results.values.all?
62
63
  # All checks passed - no need for additional message, spinners already show success
63
64
  else
64
- say "\n Some checks failed.", ColorHelper.error
65
+ print_error("\n Some checks failed.")
65
66
  exit(1)
66
67
  end
67
68
  end
@@ -76,7 +77,7 @@ module Strata
76
77
  rescue
77
78
  failures.each do |f|
78
79
  msg = f.is_a?(Hash) ? "#{f[:file]}: #{f[:message]}" : f.to_s
79
- say " ✖ #{msg}", ColorHelper.error
80
+ print_error(" ✖ #{msg}")
80
81
  end
81
82
  false
82
83
  end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../guard"
4
+ require_relative "../output"
5
+ require_relative "../api/client"
6
+ require_relative "../utils/git"
7
+ require "time"
8
+ require "tty-prompt"
9
+
10
+ module Strata
11
+ module CLI
12
+ module SubCommands
13
+ class Branch < Thor
14
+ include Guard
15
+ include Output
16
+
17
+ default_command :list
18
+ class_option :environment, aliases: ["e"], type: :string
19
+
20
+ desc "list", "List local and Strata server branches"
21
+ def list
22
+ config = CLI.config.get_for_environment(options[:environment])
23
+ local_branch_names = Utils::Git.local_branches
24
+ server_branches = fetch_server_branches(config)
25
+
26
+ rows = branch_rows(local_branch_names, server_branches)
27
+ if rows.empty?
28
+ print_info("No local or Strata server branches found.")
29
+ else
30
+ rows.each { |row| print_info(row) }
31
+ end
32
+ end
33
+
34
+ desc "create BRANCH", "Create and checkout a local git branch"
35
+ def create(branch_name)
36
+ branch_name = Utils::Git.create_and_checkout_branch(branch_name)
37
+ print_success("Created and checked out branch '#{branch_name}'.")
38
+ end
39
+
40
+ desc "checkout BRANCH", "Checkout a local git branch"
41
+ def checkout(branch_name)
42
+ branch_name = Utils::Git.checkout_branch(branch_name)
43
+ print_success("Checked out branch '#{branch_name}'.")
44
+ end
45
+
46
+ desc "delete", "Delete a branch from Strata server"
47
+ method_option :branch, aliases: ["b"], type: :string, desc: "Branch to delete. Defaults to current git branch."
48
+ def delete
49
+ branch_id = branch_to_delete
50
+ config = CLI.config.get_for_environment(options[:environment])
51
+ validate_delete_configuration(config)
52
+
53
+ return unless confirm_branch_deletion(branch_id)
54
+
55
+ client = API::Client.new(config["server"], config["api_key"])
56
+ server_deleted = client.delete_branch(config["project_id"], branch_id)
57
+ print_warning("Branch '#{branch_id}' was not found on Strata server. Deleting local branch only.") unless server_deleted
58
+
59
+ delete_local_branch(branch_id)
60
+
61
+ print_success("Deleted branch '#{branch_id}'.")
62
+ end
63
+
64
+ private
65
+
66
+ def branch_to_delete
67
+ explicit_branch = options[:branch].to_s.strip
68
+ branch_id = explicit_branch.empty? ? Utils::Git.current_branch.to_s.strip : explicit_branch
69
+
70
+ if branch_id.empty?
71
+ raise Strata::CommandError, "Branch name is required. Use -b BRANCH to specify one."
72
+ end
73
+
74
+ if branch_id == "HEAD"
75
+ raise Strata::CommandError, "Cannot determine current branch while in detached HEAD. Use -b BRANCH to specify one."
76
+ end
77
+
78
+ branch_id
79
+ end
80
+
81
+ def validate_delete_configuration(config)
82
+ ensure_config_present(config, "server")
83
+ ensure_config_present(config, "api_key")
84
+ ensure_config_present(config, "project_id")
85
+ end
86
+
87
+ def ensure_config_present(config, key)
88
+ return if config[key] && !config[key].to_s.strip.empty?
89
+
90
+ raise Strata::CommandError, "Missing required configuration: #{key}. Check your project.yml or .strata file."
91
+ end
92
+
93
+ def confirm_branch_deletion(branch_id)
94
+ prompt = TTY::Prompt.new
95
+ answer = prompt.ask("Type '#{branch_id}' to delete this branch from Strata:")
96
+ return true if answer.to_s == branch_id
97
+
98
+ print_warning("Branch deletion cancelled.")
99
+ false
100
+ end
101
+
102
+ def fetch_server_branches(config)
103
+ unless server_configured?(config)
104
+ print_warning("Server configuration is incomplete. Showing local branches only.")
105
+ return []
106
+ end
107
+
108
+ API::Client.new(config["server"], config["api_key"]).branches(config["project_id"])
109
+ end
110
+
111
+ def server_configured?(config)
112
+ %w[server api_key project_id].all? { |key| config[key] && !config[key].to_s.strip.empty? }
113
+ end
114
+
115
+ def branch_rows(local_branch_names, server_branches)
116
+ local_names = local_branch_names.to_h { |name| [name, true] }
117
+ server_by_uid = server_branches.to_h { |branch| [branch["uid"], branch] }
118
+ current_branch = Utils::Git.git_repo? ? Utils::Git.current_branch : nil
119
+
120
+ (local_names.keys | server_by_uid.keys).sort.map do |branch_name|
121
+ server_branch = server_by_uid[branch_name]
122
+ "#{current_branch_marker(branch_name, current_branch)}(#{branch_location(local_names.key?(branch_name), server_branch)}) - last deployed at: #{format_last_deployed_at(server_branch && server_branch["last_deployed_at"])}"
123
+ end
124
+ end
125
+
126
+ def current_branch_marker(branch_name, current_branch)
127
+ (current_branch == branch_name) ? "* #{branch_name}" : branch_name
128
+ end
129
+
130
+ def branch_location(local, server_branch)
131
+ tags = []
132
+ tags << "local" if local
133
+ tags << "server" if server_branch
134
+ tags.empty? ? "unknown" : tags.join(", ")
135
+ end
136
+
137
+ def format_last_deployed_at(value)
138
+ return "" if value.nil? || value.to_s.strip.empty?
139
+
140
+ Time.parse(value.to_s).strftime("%Y-%m-%d %H:%M:%S")
141
+ rescue ArgumentError
142
+ value.to_s
143
+ end
144
+
145
+ def delete_local_branch(branch_id)
146
+ case Utils::Git.delete_local_branch(branch_id, fallback_branches: local_delete_fallback_branches)
147
+ when :deleted
148
+ print_info("Deleted local git branch '#{branch_id}'.")
149
+ when :not_found
150
+ print_warning("Local git branch '#{branch_id}' was not found.")
151
+ when :not_git_repo
152
+ print_warning("No local git repository found. Skipped local branch deletion.")
153
+ end
154
+ end
155
+
156
+ def local_delete_fallback_branches
157
+ production_branch = CLI.config["production_branch"].to_s.strip
158
+ ([production_branch] + %w[main master]).reject(&:empty?).uniq
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -7,7 +7,6 @@ require_relative "../ui/field_editor"
7
7
  require_relative "../credentials"
8
8
  require_relative "../helpers/table_filter"
9
9
  require_relative "../ai/services/table_generator"
10
- require_relative "../helpers/color_helper"
11
10
  require_relative "../helpers/prompts"
12
11
  require_relative "../helpers/description_helper"
13
12
  require_relative "../helpers/command_context"
@@ -406,7 +405,7 @@ module Strata
406
405
 
407
406
  return unless from.strip == to.strip
408
407
 
409
- say "Warning: --from and --to have the same value. Migration will have no effect.", ColorHelper.warning
408
+ print_warning("Warning: --from and --to have the same value. Migration will have no effect.")
410
409
  end
411
410
 
412
411
  def prompt_migration_hook(operation)
@@ -3,6 +3,7 @@
3
3
  require_relative "../guard"
4
4
  require_relative "../credentials"
5
5
  require_relative "../terminal"
6
+ require_relative "../output"
6
7
  require_relative "../utils/git"
7
8
  require "tty-prompt"
8
9
  require_relative "../helpers/datasource_helper"
@@ -15,6 +16,7 @@ module Strata
15
16
  include Thor::Actions
16
17
  include Guard
17
18
  include Terminal
19
+ include Output
18
20
  include DatasourceHelper
19
21
  extend Helpers::DescriptionHelper
20
22
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative "../guard"
4
4
  require_relative "../terminal"
5
- require_relative "../helpers/color_helper"
5
+ require_relative "../output"
6
6
  require_relative "../helpers/project_helper"
7
7
  require_relative "../helpers/description_helper"
8
8
  require_relative "../api/client"
@@ -22,6 +22,7 @@ module Strata
22
22
  class Deploy < Thor
23
23
  include Guard
24
24
  include Terminal
25
+ include Output
25
26
  extend Helpers::DescriptionHelper
26
27
 
27
28
  default_command :deploy
@@ -57,7 +58,7 @@ module Strata
57
58
  # If only external imports changed, generate synthetic commit identifier
58
59
  if refreshed_imports.any? && local_file_changes.empty?
59
60
  import_commit_hash = Utils::ImportManager.generate_import_commit_hash(project_path)
60
- say "\nExternal imports change found. Proceeding with deployment", ColorHelper.info
61
+ print_info("\nExternal imports change found. Proceeding with deployment")
61
62
  metadata[:commit] = "imports-#{import_commit_hash}"
62
63
  metadata[:commit_message] = "External imports updated: #{refreshed_imports.map do |c|
63
64
  File.basename(c[:source])
@@ -68,7 +69,7 @@ module Strata
68
69
 
69
70
  env_display = options[:environment] ? " (#{options[:environment]} environment)" : ""
70
71
  server_info = config["server"] ? " (#{config["server"]})" : ""
71
- say "\nDeploying to branch '#{branch_id}' on Strata server#{env_display}#{server_info}\n", ColorHelper.info
72
+ print_info("\nDeploying to branch '#{branch_id}' on Strata server#{env_display}#{server_info}\n")
72
73
 
73
74
  deployment = submit_deployment(config, branch_id, archive_path, metadata)
74
75
 
@@ -87,7 +88,7 @@ module Strata
87
88
  deployment = client.latest_deployment(config["project_id"], branch_id)
88
89
 
89
90
  unless deployment
90
- say "No deployments found for branch '#{branch_id}'.\n", ColorHelper.info
91
+ print_info("No deployments found for branch '#{branch_id}'.\n")
91
92
  return
92
93
  end
93
94
 
@@ -331,8 +332,8 @@ module Strata
331
332
 
332
333
  if changed_paths.empty? && refreshed_imports.empty?
333
334
  unless options[:force]
334
- say "\nNo files changed since last deployment.", ColorHelper.warning
335
- say "To force deploy, run command with --force or -f flag.\n", ColorHelper.info
335
+ print_warning("\nNo files changed since last deployment.")
336
+ print_info("To force deploy, run command with --force or -f flag.\n")
336
337
  exit(0)
337
338
  end
338
339
  Utils::Archive.create(project_path, file_overrides: file_overrides)
@@ -345,7 +346,7 @@ module Strata
345
346
  change_count = files_to_include.length
346
347
  change_count += refreshed_imports.length if refreshed_imports.any?
347
348
 
348
- say "Including #{change_count} changed file(s) in archive...\n", ColorHelper.info
349
+ print_info("Including #{change_count} changed file(s) in archive...\n")
349
350
  Utils::Archive.create(project_path, files_to_include: files_to_include, file_overrides: file_overrides)
350
351
  end
351
352
  else
@@ -412,7 +413,7 @@ module Strata
412
413
  message = "Deploying to production branch '#{branch_id}'. Continue? [y/N]"
413
414
  return if prompt.yes?(message, default: false)
414
415
 
415
- say "Deployment cancelled.", ColorHelper.warning
416
+ print_warning("Deployment cancelled.")
416
417
  exit(0)
417
418
  end
418
419
 
@@ -422,7 +423,7 @@ module Strata
422
423
  project_config = YAML.safe_load_file("project.yml", permitted_classes: [Date, Time], aliases: true) || {}
423
424
  project_config["production_branch"] || "main"
424
425
  rescue => e
425
- warn "Failed to load project.yml: #{e.message}" if ENV["DEBUG"]
426
+ print_warning("Failed to load project.yml: #{e.message}") if ENV["DEBUG"]
426
427
  "main"
427
428
  end
428
429
 
@@ -436,11 +437,11 @@ module Strata
436
437
  return nil unless last_deployment && last_deployment["commit"]
437
438
 
438
439
  commit_hash = last_deployment["commit"]
439
- say "Found last successful deployment at commit: #{commit_hash[0..7]}...\n", ColorHelper.info
440
+ print_info("Found last successful deployment at commit: #{commit_hash[0..7]}...\n")
440
441
  commit_hash
441
442
  rescue Strata::CommandError
442
443
  # If we can't get last deployment (e.g., first deployment), continue with all files
443
- say "No previous deployment found. Including all files.\n", ColorHelper.info
444
+ print_info("No previous deployment found. Including all files.\n")
444
445
  nil
445
446
  end
446
447
  end
@@ -477,10 +478,10 @@ module Strata
477
478
  refreshed = Utils::ImportManager.refresh_external_imports(project_path)
478
479
 
479
480
  if refreshed.any?
480
- say "\n Skimmed #{refreshed.length} external import(s):", ColorHelper.info
481
+ print_info("\n Skimmed #{refreshed.length} external import(s):")
481
482
  refreshed.each do |import|
482
483
  filename = File.basename(import[:source])
483
- say " • #{filename}", ColorHelper.info
484
+ print_info(" • #{filename}")
484
485
  end
485
486
  end
486
487
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative "../guard"
4
4
  require_relative "../terminal"
5
- require_relative "../helpers/color_helper"
5
+ require_relative "../output"
6
6
  require_relative "../helpers/project_helper"
7
7
  require_relative "../api/client"
8
8
  require "yaml"
@@ -13,6 +13,7 @@ module Strata
13
13
  class Project < Thor
14
14
  include Guard
15
15
  include Terminal
16
+ include Output
16
17
 
17
18
  desc "link PROJECT_ID", "Link local project to an existing project on the server"
18
19
  def link(project_id)
@@ -22,13 +23,13 @@ module Strata
22
23
  project_config = YAML.safe_load_file(project_yml_path, permitted_classes: [Date, Time], aliases: true) || {}
23
24
 
24
25
  if project_config["project_id"] && !project_config["project_id"].to_s.strip.empty?
25
- say "Project is already linked to project_id: #{project_config["project_id"]}", ColorHelper.warning
26
+ print_warning("Project is already linked to project_id: #{project_config["project_id"]}")
26
27
  return
27
28
  end
28
29
 
29
30
  return unless Helpers::ProjectHelper.persist_project_id_to_yml(project_id, project_yml_path: project_yml_path)
30
31
 
31
- say "✓ Project linked successfully. project_id: #{project_id}", ColorHelper.info
32
+ print_info("✓ Project linked successfully. project_id: #{project_id}")
32
33
  end
33
34
  end
34
35
  end