Class: GithubFlowReadinessService
- Inherits:
-
Object
- Object
- GithubFlowReadinessService
- Defined in:
- lib/core/github_flow_readiness_service.rb
Overview
Drives the readiness checks that gate ‘cpflow generate-github-actions`. The actual checks live in `GithubFlowReadiness::Checks`; this class is the host that owns the shared lockfile parser, package.json parser, HTTP version cache, and registry-check helpers used across multiple checks. Add a new check by creating a class with `call` under `GithubFlowReadiness::Checks` and registering it in `CHECKS`.
Defined Under Namespace
Classes: RegistryCheck
Constant Summary collapse
- Result =
rubocop:disable Metrics/ClassLength
GithubFlowReadiness::Result
- CHECKS =
[ GithubFlowReadiness::Checks::RailsApp, GithubFlowReadiness::Checks::RubyVersion, GithubFlowReadiness::Checks::BundlerVersion, GithubFlowReadiness::Checks::Dockerfile, GithubFlowReadiness::Checks::SqliteProduction, GithubFlowReadiness::Checks::GemSources, GithubFlowReadiness::Checks::GemExactPins, GithubFlowReadiness::Checks::NpmExactPins ].freeze
- PUBLIC_RUBYGEMS_REMOTE =
"https://rubygems.org"- REGISTRY_FETCH_THREADS =
8- REGISTRY_FETCH_TIMEOUT_SECONDS =
60
Instance Attribute Summary collapse
-
#root_path ⇒ Object
readonly
Returns the value of attribute root_path.
Instance Method Summary collapse
- #blockers? ⇒ Boolean
- #exact_pin_registry_result(check) ⇒ Object
-
#fetch_npm_versions(name) ⇒ Object
Stubbed in specs; keep public.
-
#fetch_rubygems_versions(name) ⇒ Object
Stubbed in specs; keep public.
-
#gem_dependencies ⇒ Object
—————————————————————— Helpers exposed to check classes (and stubbed by specs).
- #inferred_ruby_version ⇒ Object
-
#initialize(root_path: Dir.pwd) ⇒ GithubFlowReadinessService
constructor
A new instance of GithubFlowReadinessService.
- #lockfile_bundler_version ⇒ Object
- #npm_registry_check ⇒ Object
- #package_json_parse_error ⇒ Object
- #package_json_parse_error_result ⇒ Object
- #parsed_package_json ⇒ Object
- #public_rubygems_dependency?(dependency) ⇒ Boolean
- #results ⇒ Object
- #rubygems_registry_check ⇒ Object
- #sqlite_database_in_production? ⇒ Boolean
- #summary ⇒ Object
Constructor Details
#initialize(root_path: Dir.pwd) ⇒ GithubFlowReadinessService
Returns a new instance of GithubFlowReadinessService.
47 48 49 50 51 52 |
# File 'lib/core/github_flow_readiness_service.rb', line 47 def initialize(root_path: Dir.pwd) @root_path = Pathname.new(root_path) @package_json_parse_error = false @rubygems_versions_cache = build_registry_cache @npm_versions_cache = build_registry_cache end |
Instance Attribute Details
#root_path ⇒ Object (readonly)
Returns the value of attribute root_path.
45 46 47 |
# File 'lib/core/github_flow_readiness_service.rb', line 45 def root_path @root_path end |
Instance Method Details
#blockers? ⇒ Boolean
58 59 60 |
# File 'lib/core/github_flow_readiness_service.rb', line 58 def blockers? results.any? { |result| result.status == :fail } end |
#exact_pin_registry_result(check) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/core/github_flow_readiness_service.rb', line 160 def exact_pin_registry_result(check) return Result.new(status: :info, message: check.) if check.dependencies.empty? grouped = partition_dependencies(check.dependencies, check.availability_proc) results = [] results << registry_unavailable_result(check, grouped[:unavailable]) if grouped[:unavailable].any? results << registry_unknown_result(check, grouped[:unknown]) if grouped[:unknown].any? return results if results.any? Result.new(status: :pass, message: (check)) end |
#fetch_npm_versions(name) ⇒ Object
Stubbed in specs; keep public.
178 179 180 |
# File 'lib/core/github_flow_readiness_service.rb', line 178 def fetch_npm_versions(name) fetch_with_cache(npm_versions_cache, name) { fetch_versions_from_npm(name) } end |
#fetch_rubygems_versions(name) ⇒ Object
Stubbed in specs; keep public.
173 174 175 |
# File 'lib/core/github_flow_readiness_service.rb', line 173 def fetch_rubygems_versions(name) fetch_with_cache(rubygems_versions_cache, name) { fetch_versions_from_rubygems(name) } end |
#gem_dependencies ⇒ Object
Helpers exposed to check classes (and stubbed by specs).
74 75 76 |
# File 'lib/core/github_flow_readiness_service.rb', line 74 def gem_dependencies @gem_dependencies ||= load_gem_dependencies end |
#inferred_ruby_version ⇒ Object
85 86 87 88 |
# File 'lib/core/github_flow_readiness_service.rb', line 85 def inferred_ruby_version version_string = RepoIntrospection.inferred_ruby_version_string(root_path.to_s) Gem::Version.new(version_string) if version_string end |
#lockfile_bundler_version ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/core/github_flow_readiness_service.rb', line 90 def lockfile_bundler_version file_path = root_path.join("Gemfile.lock") return unless file_path.file? lines = file_path.readlines(chomp: true) bundler_index = lines.index("BUNDLED WITH") return unless bundler_index version = lines[(bundler_index + 1)..]&.find { |line| !line.strip.empty? }&.strip return unless version Gem::Version.new(version) end |
#npm_registry_check ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/core/github_flow_readiness_service.rb', line 148 def npm_registry_check RegistryCheck.new( dependencies: exact_npm_dependencies, empty_message: "No exact-pinned direct npm packages to verify.", missing_prefix: "Direct npm package versions not available on npm", unknown_prefix: "Could not verify some exact-pinned npm packages against npm", success_noun: "direct npm package", availability_proc: method(:npm_dependency_available?), registry_name: "npm" ) end |
#package_json_parse_error ⇒ Object
121 122 123 124 125 126 127 |
# File 'lib/core/github_flow_readiness_service.rb', line 121 def package_json_parse_error # Calling `parsed_package_json` here is the explicit "make sure parsing has run" # trigger, so a reader of `package_json_parse_error` does not have to know that the # flag is populated lazily. Guarded so memoized state isn't re-fetched. parsed_package_json unless instance_variable_defined?(:@parsed_package_json) @package_json_parse_error end |
#package_json_parse_error_result ⇒ Object
129 130 131 132 133 134 |
# File 'lib/core/github_flow_readiness_service.rb', line 129 def package_json_parse_error_result Result.new( status: :warn, message: "Could not parse `package.json`; exact-pinned direct npm package readiness could not be fully verified." ) end |
#parsed_package_json ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/core/github_flow_readiness_service.rb', line 108 def parsed_package_json return @parsed_package_json if instance_variable_defined?(:@parsed_package_json) package_json_path = root_path.join("package.json") @package_json_parse_error = false return @parsed_package_json = nil unless package_json_path.file? @parsed_package_json = JSON.parse(package_json_path.read) rescue JSON::ParserError @package_json_parse_error = true @parsed_package_json = nil end |
#public_rubygems_dependency?(dependency) ⇒ Boolean
78 79 80 81 82 83 |
# File 'lib/core/github_flow_readiness_service.rb', line 78 def public_rubygems_dependency?(dependency) return false unless dependency[:source_type] == :rubygems remotes = dependency[:source_remotes] remotes.empty? || remotes.all? { |remote| remote == PUBLIC_RUBYGEMS_REMOTE } end |
#results ⇒ Object
54 55 56 |
# File 'lib/core/github_flow_readiness_service.rb', line 54 def results @results ||= CHECKS.flat_map { |klass| wrap_check_result(klass.new(self).call) } end |
#rubygems_registry_check ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/core/github_flow_readiness_service.rb', line 136 def rubygems_registry_check RegistryCheck.new( dependencies: exact_rubygems_dependencies, empty_message: "No exact-pinned direct Ruby gems to verify.", missing_prefix: "Direct Ruby gem versions not available on RubyGems", unknown_prefix: "Could not verify some exact-pinned Ruby gems against RubyGems", success_noun: "direct Ruby gem", availability_proc: method(:rubygems_requirement_available?), registry_name: "RubyGems" ) end |
#sqlite_database_in_production? ⇒ Boolean
104 105 106 |
# File 'lib/core/github_flow_readiness_service.rb', line 104 def sqlite_database_in_production? RepoIntrospection.sqlite_database_in_production?(root_path.to_s) end |
#summary ⇒ Object
62 63 64 65 66 67 68 |
# File 'lib/core/github_flow_readiness_service.rb', line 62 def summary if blockers? "Blockers found. Fix them before generating the Control Plane GitHub flow." else "No blocking readiness issues detected. Validate the real production build path before merging." end end |