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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/strata/cli/ai/services/table_generator.rb +35 -20
- data/lib/strata/cli/api/client.rb +23 -63
- data/lib/strata/cli/api/response_error_handler.rb +115 -0
- data/lib/strata/cli/error_reporter.rb +4 -1
- data/lib/strata/cli/generators/datasource.rb +4 -3
- data/lib/strata/cli/generators/group.rb +37 -0
- data/lib/strata/cli/generators/migration.rb +2 -1
- data/lib/strata/cli/generators/project.rb +18 -11
- data/lib/strata/cli/generators/relation.rb +2 -1
- data/lib/strata/cli/generators/table.rb +5 -8
- data/lib/strata/cli/generators/templates/table.table_name.yml +1 -1
- data/lib/strata/cli/generators/test.rb +2 -1
- data/lib/strata/cli/guard.rb +4 -1
- data/lib/strata/cli/helpers/command_context.rb +8 -9
- data/lib/strata/cli/helpers/datasource_helper.rb +1 -1
- data/lib/strata/cli/helpers/description_helper.rb +2 -1
- data/lib/strata/cli/main.rb +15 -3
- data/lib/strata/cli/output.rb +103 -0
- data/lib/strata/cli/sub_commands/audit.rb +4 -3
- data/lib/strata/cli/sub_commands/branch.rb +163 -0
- data/lib/strata/cli/sub_commands/create.rb +1 -2
- data/lib/strata/cli/sub_commands/datasource.rb +2 -0
- data/lib/strata/cli/sub_commands/deploy.rb +14 -13
- data/lib/strata/cli/sub_commands/project.rb +4 -3
- data/lib/strata/cli/sub_commands/table.rb +9 -8
- data/lib/strata/cli/terminal.rb +7 -4
- data/lib/strata/cli/ui/field_editor.rb +21 -27
- data/lib/strata/cli/utils/deployment_monitor.rb +15 -34
- data/lib/strata/cli/utils/git.rb +78 -0
- data/lib/strata/cli/utils/import_manager.rb +4 -1
- data/lib/strata/cli/utils/test_reporter.rb +4 -32
- data/lib/strata/cli/utils/version_checker.rb +4 -8
- data/lib/strata/cli/utils.rb +3 -1
- data/lib/strata/cli/version.rb +1 -1
- data/lib/strata/cli.rb +4 -3
- metadata +4 -2
- 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
|
-
|
|
27
|
+
Output.print_status(:created, output_path, type: :success, context: self)
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
private
|
data/lib/strata/cli/guard.rb
CHANGED
|
@@ -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
|
-
|
|
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 "
|
|
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
|
-
|
|
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}'.",
|
|
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}'.",
|
|
44
|
-
say "Reason: #{ErrorReporter.user_message_for(e)}",
|
|
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
|
-
|
|
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
|
|
@@ -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
|
-
|
|
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
|
data/lib/strata/cli/main.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 "../
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 "../
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
335
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
481
|
+
print_info("\n Skimmed #{refreshed.length} external import(s):")
|
|
481
482
|
refreshed.each do |import|
|
|
482
483
|
filename = File.basename(import[:source])
|
|
483
|
-
|
|
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 "../
|
|
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
|
-
|
|
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
|
-
|
|
32
|
+
print_info("✓ Project linked successfully. project_id: #{project_id}")
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
end
|