Module: RepoIntrospection
- Defined in:
- lib/core/repo_introspection.rb
Constant Summary collapse
- DEFAULT_APP_PREFIX =
"my-app"- RUBY_VERSION_DIRECTIVE_PATTERN =
/^\s*ruby\s+['"\d]/- RUBY_VERSION_DIRECTIVE_PREFIX =
/^\s*ruby\s+/
Class Method Summary collapse
-
.inferred_app_prefix(root) ⇒ Object
Returns a Control Plane-safe app prefix derived from the basename of ‘root`: lower-cased, with non-alphanumeric runs collapsed to dashes and stripped from the ends.
-
.inferred_ruby_version_string(root) ⇒ Object
Returns the first Ruby version string the repo declares, checked in the order Bundler itself uses: ‘.ruby-version`, then `.tool-versions`, then `Gemfile`.
-
.parse_ruby_version_string(source) ⇒ Object
Pure string → version-string extractor.
- .ruby_version_from_gemfile(root) ⇒ Object
- .ruby_version_from_ruby_version_file(root) ⇒ Object
- .ruby_version_from_tool_versions(root) ⇒ Object
- .safe_load_database_yml(raw_contents) ⇒ Object
- .sqlite_adapter_in_hash?(config) ⇒ Boolean
-
.sqlite_database_in_production?(root) ⇒ Boolean
Returns true if ‘config/database.yml` under `root` configures SQLite for production.
- .sqlite_database_url?(url) ⇒ Boolean
- .warn_dynamic_ruby_directive ⇒ Object
Class Method Details
.inferred_app_prefix(root) ⇒ Object
Returns a Control Plane-safe app prefix derived from the basename of ‘root`: lower-cased, with non-alphanumeric runs collapsed to dashes and stripped from the ends. Falls back to DEFAULT_APP_PREFIX when the result is empty.
65 66 67 68 69 70 71 72 |
# File 'lib/core/repo_introspection.rb', line 65 def self.inferred_app_prefix(root) sanitized = File.basename(root) .downcase .gsub(/[^a-z0-9]+/, "-") .gsub(/\A-+|-+\z/, "") sanitized.empty? ? DEFAULT_APP_PREFIX : sanitized end |
.inferred_ruby_version_string(root) ⇒ Object
Returns the first Ruby version string the repo declares, checked in the order Bundler itself uses: ‘.ruby-version`, then `.tool-versions`, then `Gemfile`. Returns nil when no source declares a version. Both `Command::Generator` and `GithubFlowReadinessService` call into this so a future format change (e.g. `.tool-versions`) only updates here.
21 22 23 24 25 |
# File 'lib/core/repo_introspection.rb', line 21 def self.inferred_ruby_version_string(root) ruby_version_from_ruby_version_file(root) || ruby_version_from_tool_versions(root) || ruby_version_from_gemfile(root) end |
.parse_ruby_version_string(source) ⇒ Object
Pure string → version-string extractor. Strips a leading ‘ruby-` prefix and returns the first `MAJOR.MINOR` found in the source, or nil.
12 13 14 15 |
# File 'lib/core/repo_introspection.rb', line 12 def self.parse_ruby_version_string(source) normalized = source.strip.sub(/\Aruby-/, "") normalized[/\d+\.\d+(?:\.\d+)?/] end |
.ruby_version_from_gemfile(root) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/core/repo_introspection.rb', line 44 def self.ruby_version_from_gemfile(root) path = File.join(root, "Gemfile") return unless File.file?(path) ruby_lines = File.readlines(path, chomp: true).select { |line| line.match?(RUBY_VERSION_DIRECTIVE_PREFIX) } ruby_line = ruby_lines.find { |line| line.match?(RUBY_VERSION_DIRECTIVE_PATTERN) } warn_dynamic_ruby_directive if ruby_lines.any? && ruby_line.nil? return unless ruby_line parse_ruby_version_string(ruby_line.sub(RUBY_VERSION_DIRECTIVE_PREFIX, "")) end |
.ruby_version_from_ruby_version_file(root) ⇒ Object
27 28 29 30 31 32 |
# File 'lib/core/repo_introspection.rb', line 27 def self.ruby_version_from_ruby_version_file(root) path = File.join(root, ".ruby-version") return unless File.file?(path) parse_ruby_version_string(File.read(path)) end |
.ruby_version_from_tool_versions(root) ⇒ Object
34 35 36 37 38 39 40 41 42 |
# File 'lib/core/repo_introspection.rb', line 34 def self.ruby_version_from_tool_versions(root) path = File.join(root, ".tool-versions") return unless File.file?(path) ruby_line = File.readlines(path, chomp: true).find { |line| line.match?(RUBY_VERSION_DIRECTIVE_PREFIX) } return unless ruby_line parse_ruby_version_string(ruby_line.sub(RUBY_VERSION_DIRECTIVE_PREFIX, "")) end |
.safe_load_database_yml(raw_contents) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/core/repo_introspection.rb', line 93 def self.safe_load_database_yml(raw_contents) # ERB conditionals can change YAML structure, so avoid guessing. Output-only # ERB is stubbed as a scalar so common Rails defaults like `pool: <%= ... %>` # still parse, but control-flow ERB returns unknown. `<%- ... %>` is a # whitespace-trimming code tag, not an output tag, so treat it as unknown too. # Callers treat unknown as non-SQLite and # emit the default Postgres scaffold rather than guessing wrong. return nil if raw_contents.match?(/<%(?![=#])/m) stubbed = raw_contents.gsub(/<%=.*?%>/m, "__erb__").gsub(/<%#.*?%>/m, "") YAML.safe_load(stubbed, aliases: true, permitted_classes: [Symbol]) rescue Psych::SyntaxError nil end |
.sqlite_adapter_in_hash?(config) ⇒ Boolean
108 109 110 111 112 113 |
# File 'lib/core/repo_introspection.rb', line 108 def self.sqlite_adapter_in_hash?(config) return false unless config.is_a?(Hash) adapter = config["adapter"] adapter.is_a?(String) && adapter.strip.start_with?("sqlite3") end |
.sqlite_database_in_production?(root) ⇒ Boolean
Returns true if ‘config/database.yml` under `root` configures SQLite for production. YAML merge keys such as `<<: *default` are resolved by safe_load, so only the final production hash should be inspected.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/core/repo_introspection.rb', line 77 def self.sqlite_database_in_production?(root) path = File.join(root, "config/database.yml") return false unless File.file?(path) parsed = safe_load_database_yml(File.read(path)) return false unless parsed.is_a?(Hash) production = parsed["production"] return false unless production.is_a?(Hash) url = production["url"] return sqlite_database_url?(url) if url.is_a?(String) && !url.strip.empty? sqlite_adapter_in_hash?(production) end |
.sqlite_database_url?(url) ⇒ Boolean
115 116 117 |
# File 'lib/core/repo_introspection.rb', line 115 def self.sqlite_database_url?(url) url.strip.downcase.start_with?("sqlite:", "sqlite3:") end |
.warn_dynamic_ruby_directive ⇒ Object
56 57 58 59 60 |
# File 'lib/core/repo_introspection.rb', line 56 def self.warn_dynamic_ruby_directive return unless ENV["CPFLOW_DEBUG"] warn "cpflow: Gemfile has a dynamic `ruby` directive; falling back to the default Ruby version" end |