badges / shields

Concise, consistent, and legible badges in SVG and raster format
https://shields.io
Creative Commons Zero v1.0 Universal
23.67k stars 5.49k forks source link

version of gem read dynamically from Gemfile #6789

Open JohnRDOrazio opened 3 years ago

JohnRDOrazio commented 3 years ago

:clipboard: Description

Seeing that it is possible to read the version of a node dependency from a github repo's package.json using https://img.shields.io/github/package-json/dependency-version/[user]/[repo]/[dependency] (and I saw that this even works for devDependencies by add dev to the path: https://img.shields.io/github/package-json/dependency-version/[user]/[repo]/dev/[dependency]), it would be nice to have a similar possibility for reading the version of a Gem from a Gemfile, using something like:

https://img.shields.io/github/gemfile/dependency-version/[user]/[repo]/[gem]

Gemfiles can group together dev dependencies or test dependencies by defining the development and test groups, it would be nice to also read from these groups, perhaps using a path similarly to the package-json path:

https://img.shields.io/github/gemfile/dependency-version/[user]/[repo]/development/[gem]

https://img.shields.io/github/gemfile/dependency-version/[user]/[repo]/test/[gem]

I can see there being some complexity involved, since some gems might be grouped as both development and test. You can have both separate groups and combined groups.

And other than reading from Gemfiles, it would be nice to be able to read the Ruby version defined in the .ruby-version file, perhaps something like this:

https://img.shields.io/github/ruby-version/[user]/[repo]/

Likewise it would be nice to have a similar route for reading the Node version for a project from the .node-version or .nvmrc files, something like:

https://img.shields.io/github/node-version/[user]/[repo]/

I've poked around on the shields.io website but I didn't seem to find any routes like the ones mentioned here?

chris48s commented 3 years ago

There's a couple of things going on here. Tbh it should probably be two separate issues.


On the ruby gems stuff: A package.json is pretty easy to parse in javascript because it is JSON. AFAIK a Gemfile is a completely custom format (or maybe its just some ruby code?). It is not impossible, but this makes it more of a challenge than package manifests in a standard format like JSON or toml because it requires a completely custom parser.


For the node version badge, the common pace for node projects to specify their node version is in .engines.node in package.json e.g: https://github.com/badges/shields/blob/42ba150abd766aa20e19cd1feb9f0a65901152f6/package.json#L244 We do have a node version badge for NPM packages. I don't think there is a variant of "parse a value out of package.json in a GH repo" for this, but it wouldn't be too hard to add this one if someone is interested in working on it so maybe lets split that into another issue.

You can do it ad-hoc with the dynamic badge though: - https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fbadges%2Fshields%2Fmaster%2Fpackage.json&query=engines.node&label=node

JohnRDOrazio commented 3 years ago

I was able to put together a ruby script that will read the Gemfile and output pretty printed JSON much similar to a package.json:

require 'bundler'
require 'json'

    def add_to_dep(dep,top_level)
      exists = top_level.key?("#{dep.name}")
      if !exists
        top_level.merge!("#{dep.name}" => "#{dep.requirement.requirements.join}")
      end
    end

    deps = Bundler::Definition.build('Gemfile',nil,nil).
       dependencies.each_with_object(Hash.new { |h,k| h[k] = {} }) do |dep,obj|
         dep.groups.each do |g|
           add_to_dep(dep,obj[g])
         end
    end

puts JSON.pretty_generate(deps)

The output looks like this:

{
  "default": {
    "rails": "~>6.1.4",
    "pg": "~>1.1",
    "puma": "~>5.0",
    "webpacker": "~>5.0",
    "turbolinks": "~>5",
    "jbuilder": "~>2.7",
    "bcrypt": "~>3.1",
    "rexml": "~>3.2>=3.2.4",
    "bootsnap": ">=1.4.4",
    "tzinfo-data": ">=0",
    "inline_svg": "~>1.7",
    "rails-i18n": "~>6.0",
    "i18n-js": "~>3.8"
  },
  "development": {
    "byebug": ">=0",
    "web-console": ">=4.1.0",
    "rack-mini-profiler": "~>2.0",
    "listen": "~>3.3",
    "spring": ">=0",
    "i18n-tasks": "~>0.9"
  },
  "test": {
    "byebug": ">=0",
    "capybara": ">=3.26",
    "selenium-webdriver": ">=0",
    "webdrivers": ">=0",
    "i18n-tasks": "~>0.9"
  }
}

With this I can generate a JSON file that I can check into the repo, and then use the dynamic badge against this JSON file.

JohnRDOrazio commented 3 years ago

I added the current ruby version as stored in .ruby-version to the output, under engines, similarly to what is done in packages.json for the node version:

-puts JSON.pretty_generate(deps)
+ruby_version = File.open(".ruby-version").readlines.map(&:chomp)[0]
+deps.merge!("engines" => { :ruby => "#{ruby_version}" })
+
+File.write("gemfile.json", JSON.pretty_generate(deps)+"\n")