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.
46 47 48 49 50 51 |
# File 'lib/core/github_flow_readiness_service.rb', line 46 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.
44 45 46 |
# File 'lib/core/github_flow_readiness_service.rb', line 44 def root_path @root_path end |
Instance Method Details
#blockers? ⇒ Boolean
57 58 59 |
# File 'lib/core/github_flow_readiness_service.rb', line 57 def blockers? results.any? { |result| result.status == :fail } end |
#exact_pin_registry_result(check) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/core/github_flow_readiness_service.rb', line 159 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.
177 178 179 |
# File 'lib/core/github_flow_readiness_service.rb', line 177 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.
172 173 174 |
# File 'lib/core/github_flow_readiness_service.rb', line 172 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).
73 74 75 |
# File 'lib/core/github_flow_readiness_service.rb', line 73 def gem_dependencies @gem_dependencies ||= load_gem_dependencies end |
#inferred_ruby_version ⇒ Object
84 85 86 87 |
# File 'lib/core/github_flow_readiness_service.rb', line 84 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
89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/core/github_flow_readiness_service.rb', line 89 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
147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/core/github_flow_readiness_service.rb', line 147 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
120 121 122 123 124 125 126 |
# File 'lib/core/github_flow_readiness_service.rb', line 120 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
128 129 130 131 132 133 |
# File 'lib/core/github_flow_readiness_service.rb', line 128 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
107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/core/github_flow_readiness_service.rb', line 107 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
77 78 79 80 81 82 |
# File 'lib/core/github_flow_readiness_service.rb', line 77 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
53 54 55 |
# File 'lib/core/github_flow_readiness_service.rb', line 53 def results @results ||= CHECKS.flat_map { |klass| wrap_check_result(klass.new(self).call) } end |
#rubygems_registry_check ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/core/github_flow_readiness_service.rb', line 135 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
103 104 105 |
# File 'lib/core/github_flow_readiness_service.rb', line 103 def sqlite_database_in_production? RepoIntrospection.sqlite_database_in_production?(root_path.to_s) end |
#summary ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/core/github_flow_readiness_service.rb', line 61 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 |