Class: Pangea::CLI::Reactivity::Workspace

Inherits:
Object
  • Object
show all
Defined in:
lib/pangea/cli/reactivity.rb

Overview

A workspace in the constellation — its directory, name, declared asks, and any per-cascade-visit actions (pre/post).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, dir:, asks: [], pre_actions: [], post_actions: []) ⇒ Workspace

Returns a new instance of Workspace.



51
52
53
54
55
56
57
58
# File 'lib/pangea/cli/reactivity.rb', line 51

def initialize(name:, dir:, asks: [], pre_actions: [], post_actions: [])
  @name = name
  @dir = dir
  @asks = asks.freeze
  @pre_actions = pre_actions.freeze
  @post_actions = post_actions.freeze
  freeze
end

Instance Attribute Details

#asksObject (readonly)

Returns the value of attribute asks.



49
50
51
# File 'lib/pangea/cli/reactivity.rb', line 49

def asks
  @asks
end

#dirObject (readonly)

Returns the value of attribute dir.



49
50
51
# File 'lib/pangea/cli/reactivity.rb', line 49

def dir
  @dir
end

#nameObject (readonly)

Returns the value of attribute name.



49
50
51
# File 'lib/pangea/cli/reactivity.rb', line 49

def name
  @name
end

#post_actionsObject (readonly)

Returns the value of attribute post_actions.



49
50
51
# File 'lib/pangea/cli/reactivity.rb', line 49

def post_actions
  @post_actions
end

#pre_actionsObject (readonly)

Returns the value of attribute pre_actions.



49
50
51
# File 'lib/pangea/cli/reactivity.rb', line 49

def pre_actions
  @pre_actions
end

Class Method Details

.load(dir) ⇒ Object

Load a workspace from its pangea.yml (returns nil if the dir has no pangea.yml). Missing blocks are fine — empty arrays are used.

Schema:

reactivity:
  asks: [{layer, workspace, output, bind}]
cascade:
  default_depth: N
  pre_actions:  [synth, output, init]
  post_actions: [synth, output, init]


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/pangea/cli/reactivity.rb', line 70

def self.load(dir)
  yml_path = File.join(dir, 'pangea.yml')
  return nil unless File.exist?(yml_path)

  config = YAML.safe_load(File.read(yml_path)) || {}
  name = config['workspace'] || File.basename(dir)
  asks = Array(config.dig('reactivity', 'asks')).map { |h| Ask.from_h(h) }
  pre = validate_actions(Array(config.dig('cascade', 'pre_actions')), dir: dir)
  post = validate_actions(Array(config.dig('cascade', 'post_actions')), dir: dir)
  new(name: name, dir: dir, asks: asks, pre_actions: pre, post_actions: post)
rescue InvalidActionError
  raise
rescue StandardError
  nil
end

.validate_actions(list, dir:) ⇒ Object

Sanity-check declared actions: allowlist only, no conflicts with plan/apply/destroy/deploy. Raises InvalidActionError on violation so the user gets a clear message at scan time.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/pangea/cli/reactivity.rb', line 89

def self.validate_actions(list, dir:)
  list.map do |a|
    s = a.to_s.strip
    if CONFLICTING_ACTIONS.include?(s)
      raise InvalidActionError,
        "#{dir}/pangea.yml declares cascade action '#{s}' which " \
        "conflicts with the primary command. Use the CLI instead."
    end
    unless ALLOWED_ACTIONS.include?(s)
      raise InvalidActionError,
        "#{dir}/pangea.yml declares unknown cascade action '#{s}'. " \
        "Allowed: #{ALLOWED_ACTIONS.join(', ')}."
    end
    s
  end.freeze
end

Instance Method Details

#reactive?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/pangea/cli/reactivity.rb', line 111

def reactive?
  !asks.empty?
end

#upstream_namesObject

Names of workspaces this one asks from (its direct upstream).



107
108
109
# File 'lib/pangea/cli/reactivity.rb', line 107

def upstream_names
  asks.map(&:workspace).uniq
end