diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..07d01c1 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,17 @@ +AllCops: + TargetRubyVersion: 2.1 + Exclude: + - _site/**/* + - vendor/**/* + +Metrics/LineLength: + Enabled: false + +Metrics/MethodLength: + Enabled: false + +Metrics/AbcSize: + Enabled: false + +Style/Documentation: + Enabled: false diff --git a/Gemfile b/Gemfile index 57fd539..30338b7 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ -source "https://rubygems.org" +source 'https://rubygems.org' -gem "github-pages" -gem "jekyll-seo-tag" +gem 'github-pages' +gem 'jekyll-seo-tag' group :development do gem 'colored' @@ -11,7 +11,8 @@ end group :test do gem 'html-proofer', '2.5.2' - gem "rake" - gem "rspec" - gem "nokogiri" + gem 'rake' + gem 'rspec' + gem 'nokogiri' + gem 'rubocop' end diff --git a/Rakefile b/Rakefile index d6a2080..3eb410c 100644 --- a/Rakefile +++ b/Rakefile @@ -1,18 +1,18 @@ -require "html/proofer" +require 'html/proofer' require 'rspec/core/rake_task' -desc "Run specs" +desc 'Run specs' RSpec::Core::RakeTask.new do |t| t.pattern = 'spec/**/*_spec.rb' - t.rspec_opts = ["--order", "rand", "--color"] + t.rspec_opts = ['--order', 'rand', '--color'] end task :test do - sh "bundle exec jekyll build --trace" - Rake::Task["spec"].invoke - HTML::Proofer.new("./_site", :check_html => true, - :validation => { :ignore_script_embeds => true }, - :href_swap => { %r{http://choosealicense.com} => "" }).run + sh 'bundle exec jekyll build' + Rake::Task['spec'].invoke + HTML::Proofer.new('./_site', check_html: true, + validation: { ignore_script_embeds: true }, + href_swap: { %r{http://choosealicense.com} => '' }).run end task :approved_licenses do @@ -20,10 +20,10 @@ task :approved_licenses do approved = approved_licenses approved.select! { |l| spdx_ids.include?(l) } puts "#{approved.count} approved licenses:" - puts approved.join(", ") + puts approved.join(', ') puts "\n" - potential = approved - licenses.map { |l| l["id"] } + potential = approved - licenses.map { |l| l['id'] } puts "#{potential.count} potential additions:" - puts potential.join(", ") + puts potential.join(', ') end diff --git a/_data/rules.yml b/_data/rules.yml index d119911..2970878 100644 --- a/_data/rules.yml +++ b/_data/rules.yml @@ -42,9 +42,3 @@ forbidden: - description: Software is provided without warranty and the software author/license owner cannot be held liable for damages. label: Hold Liable tag: no-liability -- description: This software may not be modified. - label: Modification - tag: modifications -- description: You may not distribute this software. - label: Distribution - tag: distribution diff --git a/script/check-approval b/script/check-approval index b3fe7a2..57d2867 100755 --- a/script/check-approval +++ b/script/check-approval @@ -10,52 +10,52 @@ require 'fuzzy_match' # Display usage instructions if ARGV.count != 1 - puts File.open(__FILE__).read.scan(/^# .*/)[0...3].join("\n").gsub(/^# /,"") + puts File.open(__FILE__).read.scan(/^# .*/)[0...3].join("\n").gsub(/^# /, '') end class TrueClass def to_s - "Yes".green + 'Yes'.green end end class FalseClass def to_s - "No".red + 'No'.red end end license = ARGV[0].downcase.strip approvals = { - "OSI": osi_approved_licenses, - "FSF": fsf_approved_licenses, - "OD": od_approved_licenses + 'OSI' => osi_approved_licenses, + 'FSF' => fsf_approved_licenses, + 'OD' => od_approved_licenses } id, spdx = find_spdx(license) rows = [] if spdx.nil? - id = "Invalid".red - name = "None".red + id = 'Invalid'.red + name = 'None'.red else id = id.green - name = spdx["name"].green + name = spdx['name'].green end -rows << ["SPDX ID", id] -rows << ["SPDX Name", name] +rows << ['SPDX ID', id] +rows << ['SPDX Name', name] -approvals.each do |name, licenses| - rows << ["#{name} approved", licenses.include?(license)] +approvals.each do |approver, licenses| + rows << ["#{approver} approved", licenses.include?(license)] end current = license_ids.include?(license) -rows << ["Current license", current] +rows << ['Current license', current] rows << :separator -eligible = !!(!current && spdx && approved_licenses.include?(license)) -rows << ["Eligible", eligible] +eligible = (!current && spdx && approved_licenses.include?(license)) +rows << ['Eligible', eligible] puts Terminal::Table.new title: "License: #{license}", rows: rows puts @@ -63,7 +63,7 @@ puts "Code search: https://github.com/search?q=#{license}+filename%3ALICENSE&typ if spdx.nil? puts - puts "SPDX ID not found. Some possible matches:" + puts 'SPDX ID not found. Some possible matches:' puts fm = FuzzyMatch.new(spdx_ids) diff --git a/script/cibuild b/script/cibuild index 241f1f7..4d210b3 100755 --- a/script/cibuild +++ b/script/cibuild @@ -4,3 +4,4 @@ set -e echo "building the site..." bundle exec rake test +bundle exec rubocop -D -S diff --git a/script/downcase b/script/downcase index 9939e87..2fb3147 100755 --- a/script/downcase +++ b/script/downcase @@ -1,7 +1,7 @@ #! /usr/bin/env ruby # downcases all licenses in a git-friendly way -Dir["_licenses/*"].each do |file| +Dir['_licenses/*'].each do |file| system "git mv #{file} #{file.downcase}2" system "git mv #{file.downcase}2 #{file.downcase}" end diff --git a/script/generate-docs b/script/generate-docs index bf3b8da..e7df50d 100755 --- a/script/generate-docs +++ b/script/generate-docs @@ -5,32 +5,32 @@ require 'yaml' -fields = YAML.load_file("_data/fields.yml") -meta = YAML.load_file("_data/meta.yml") -rules = YAML.load_file("_data/rules.yml") +fields = YAML.load_file('_data/fields.yml') +meta = YAML.load_file('_data/meta.yml') +rules = YAML.load_file('_data/rules.yml') puts "\n### Fields\n\n" fields.each do |field| - puts "* `#{field["name"]}` - #{field["description"]}" + puts "* `#{field['name']}` - #{field['description']}" end puts "\n### YAML front matter\n" -meta = meta.group_by { |m| m["required"] } +meta = meta.group_by { |m| m['required'] } puts "\n#### Required fields\n\n" -meta[true].each do |meta| - puts "* `#{meta["name"]}` - #{meta["description"]}" +meta[true].each do |field| + puts "* `#{field['name']}` - #{field['description']}" end puts "\n#### Optional fields\n\n" -meta[false].each do |meta| - puts "* `#{meta["name"]}` - #{meta["description"]}" +meta[false].each do |field| + puts "* `#{field['name']}` - #{field['description']}" end puts "\n### Rules\n" -rules.each do |group, rules| +rules.each do |group, group_rules| puts "\n#### #{group.capitalize}\n\n" - rules.each do |rule| - puts "* `#{rule["tag"]}` - #{rule["description"]}" + group_rules.each do |rule| + puts "* `#{rule['tag']}` - #{rule['description']}" end end diff --git a/spec/license_bom_spec.rb b/spec/license_bom_spec.rb index 883d68e..02ec086 100644 --- a/spec/license_bom_spec.rb +++ b/spec/license_bom_spec.rb @@ -1,11 +1,11 @@ require 'spec_helper' -describe "byte order marks" do - Dir["#{licenses_path}/*.txt"].each do |file| - context "the #{File.basename(file, ".txt")} license" do - it "does not begin with a byte order mark" do - bom = !!(File.open(file).read =~ /\A\xEF\xBB\xBF/) - msg = "License file begins with a Byte Order Mark. See http://stackoverflow.com/a/1068700." +describe 'byte order marks' do + Dir["#{licenses_path}/*.html"].each do |file| + context "the #{File.basename(file, '.txt')} license" do + it 'does not begin with a byte order mark' do + bom = File.open(file).read.start_with?("\u0000EF\u0000BB\u0000BF") + msg = 'License file begins with a Byte Order Mark. See http://stackoverflow.com/a/1068700.' expect(bom).to eql(false), msg end end diff --git a/spec/license_category_spec.rb b/spec/license_category_spec.rb index e90f6f4..db06f57 100644 --- a/spec/license_category_spec.rb +++ b/spec/license_category_spec.rb @@ -1,30 +1,30 @@ require 'spec_helper' -describe "license categories" do +describe 'license categories' do families.each do |family| context "the #{family} family" do - family_licenses = licenses.select { |l| l["family"] == family } - primary = family_licenses.select { |l| l["variant"] == false } - variants = family_licenses.select { |l| l["variant"] == true } + family_licenses = licenses.select { |l| l['family'] == family } + primary = family_licenses.select { |l| l['variant'] == false } + variants = family_licenses.select { |l| l['variant'] == true } - it "should only have one primary license" do + it 'should only have one primary license' do expect(primary.count).to eql(1) end - it "all other licenses should be variants" do + it 'all other licenses should be variants' do expected = family_licenses.count - 1 expect(variants.count).to eql(expected) end family_licenses.each do |license| - context "the #{license["title"]} license" do - it "should have a unique slug" do - dupes = family_licenses.select { |l| l["tab-slug"] == license["tab-slug"] }.count + context "the #{license['title']} license" do + it 'should have a unique slug' do + dupes = family_licenses.count { |l| l['tab-slug'] == license['tab-slug'] } expect(dupes).to eql(1) end - it "should have a valid tab-slug" do - expect(license["tab-slug"]).to match(/[a-z0-9_]/) + it 'should have a valid tab-slug' do + expect(license['tab-slug']).to match(/[a-z0-9_]/) end end end diff --git a/spec/license_fields_spec.rb b/spec/license_fields_spec.rb index ef2ae6b..52d04ec 100644 --- a/spec/license_fields_spec.rb +++ b/spec/license_fields_spec.rb @@ -1,11 +1,11 @@ require 'spec_helper' -describe "license fillable fields" do +describe 'license fillable fields' do licenses.each do |license| - context "The #{license["title"]} license" do - it "should only contain supported fillable fields" do - matches = license["content"].scan(/\[([a-z]+)\]/) - extra_fields = matches.flatten - fields.map { |f| f["name"] } + context "The #{license['title']} license" do + it 'should only contain supported fillable fields' do + matches = license['content'].scan(/\[([a-z]+)\]/) + extra_fields = matches.flatten - fields.map { |f| f['name'] } expect(extra_fields).to be_empty end end diff --git a/spec/license_meta_spec.rb b/spec/license_meta_spec.rb index e0f2b8e..04f8375 100644 --- a/spec/license_meta_spec.rb +++ b/spec/license_meta_spec.rb @@ -1,31 +1,30 @@ require 'spec_helper' -describe "license meta" do +describe 'license meta' do licenses.each do |license| + # Manually load the raw license so we don't get the defaults + raw_fields = SafeYAML.load_file("_licenses/#{license['id']}.txt") - # Manually load the raw license so we don't get thed defaults - raw_fields = SafeYAML.load_file("_licenses/#{license["id"]}.txt") - - context "The #{license["title"]} license" do - it "should only contain supported meta fields" do - extra_fields = raw_fields.keys - meta.map { |m| m["name"] } + context "The #{license['title']} license" do + it 'should only contain supported meta fields' do + extra_fields = raw_fields.keys - meta.map { |m| m['name'] } expect(extra_fields).to be_empty end - it "should contain all required meta fields" do - required = meta.select { |m| m["required"] }.map { |m| m["name"] } + it 'should contain all required meta fields' do + required = meta.select { |m| m['required'] }.map { |m| m['name'] } missing = required - raw_fields.keys expect(missing).to be_empty end - if license["family"] - it "should contain the required license variant fields" do - missing = ["family", "tab-slug"] - license.keys + if license['family'] + it 'should contain the required license variant fields' do + missing = ['family', 'tab-slug'] - license.keys expect(missing).to be_empty end else - it "should not contain license family specific fields" do - extra = ["variant", "family", "tab-slug"].select{ |f| raw_fields.keys.include?(f) } + it 'should not contain license family specific fields' do + extra = ['variant', 'family', 'tab-slug'].select { |f| raw_fields.keys.include?(f) } expect(extra).to be_empty end end diff --git a/spec/license_rules_spec.rb b/spec/license_rules_spec.rb index c3093da..289d142 100644 --- a/spec/license_rules_spec.rb +++ b/spec/license_rules_spec.rb @@ -1,21 +1,19 @@ require 'spec_helper' -describe "license rules" do +describe 'license rules' do licenses.each do |license| - groups = rules.keys - context "The #{license["title"]} license" do + context "The #{license['title']} license" do groups.each do |group| - - valid_tags = rules[group].map { |r| r["tag"] } + valid_tags = rules[group].map { |r| r['tag'] } context "the #{group} group" do - it "should exist" do + it 'should exist' do expect(license[group]).to_not be_nil end - it "should only contain valid tags" do + it 'should only contain valid tags' do extra = license[group] - valid_tags expect(extra).to be_empty end diff --git a/spec/license_shown_spec.rb b/spec/license_shown_spec.rb index a1b159d..37737da 100644 --- a/spec/license_shown_spec.rb +++ b/spec/license_shown_spec.rb @@ -1,10 +1,9 @@ require 'spec_helper' -describe "shown licenses" do - +describe 'shown licenses' do # Whitelist of popular licenses that are shown (non-hidden) # Note: most new licenses that are added should be hidden by default - SHOWN_LICENSES = %w[ + SHOWN_LICENSES = %w( agpl-3.0 apache-2.0 artistic-2.0 @@ -20,16 +19,16 @@ describe "shown licenses" do mit mpl-2.0 unlicense - ] + ).freeze - it "has the expected number of shown licenses" do + it 'has the expected number of shown licenses' do expect(shown_licenses.count).to eql(15) end shown_licenses.each do |license| - context "the #{license["title"]} license" do - it "is whitelisted to be shown" do - expect(SHOWN_LICENSES).to include(license["id"]) + context "the #{license['title']} license" do + it 'is whitelisted to be shown' do + expect(SHOWN_LICENSES).to include(license['id']) end end end diff --git a/spec/license_spec.rb b/spec/license_spec.rb index 07d944c..bd97837 100644 --- a/spec/license_spec.rb +++ b/spec/license_spec.rb @@ -1,30 +1,46 @@ require 'spec_helper' -describe "licenses" do - - it "matches the number of files in the _licenses folder" do +describe 'licenses' do + it 'matches the number of files in the _licenses folder' do expect(licenses.count).to eql(Dir["#{licenses_path}/*.txt"].count) end licenses.each do |license| + context "The #{license['title']} license" do + let(:id) { license['id'] } - context "The #{license["title"]} license" do - - let(:id) { license["id"] } - - it "has an SPDX ID" do + it 'has an SPDX ID' do expect(spdx_ids).to include(id) end - it "uses its SPDX name" do + it 'uses its SPDX name' do spdx = find_spdx(id) expect(spdx).to_not be_nil - expect(spdx[1]["name"].gsub(/ only$/,"")).to eql(license["title"]) + expect(spdx[1]['name'].gsub(/ only$/, '')).to eql(license['title']) end - context "industry approval" do - it "should be approved by OSI or FSF or OD" do - expect(approved_licenses).to include(id), "See https://git.io/vzCTV." + context 'industry approval' do + it 'should be approved by OSI or FSF or OD' do + expect(approved_licenses).to include(id), 'See https://git.io/vzCTV.' + end + end + + context 'minimum permissions' do + let(:permissions) { license['permitted'] } + it 'should allow commercial use' do + expect(permissions).to include('commercial-use') + end + + it 'should allow modification' do + expect(permissions).to include('modifications') + end + + it 'should allow distribution' do + expect(permissions).to include('distribution') + end + + it 'should allow private use' do + expect(permissions).to include('private-use') end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 64f8cb0..03ec6b3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,51 +4,60 @@ require 'json' require 'open-uri' require 'nokogiri' +module SpecHelper + class << self + attr_accessor :config, :licenses, :site, :spdx + attr_accessor :osi_approved_licenses, :fsf_approved_licenses, :od_approved_licenses + end +end + def config_file - File.expand_path "./_config.yml", source + File.expand_path './_config.yml', source end def source - File.expand_path("../", File.dirname(__FILE__)) + File.expand_path('../', File.dirname(__FILE__)) end def licenses_path - File.expand_path "_licenses", source + File.expand_path '_licenses', source end def config - config = Jekyll::Configuration.new.read_config_file config_file - config = Jekyll::Utils.deep_merge_hashes(config, {:source => source}) - Jekyll::Utils.deep_merge_hashes(Jekyll::Configuration::DEFAULTS, config) + SpecHelper.config ||= begin + config = Jekyll::Configuration.new.read_config_file config_file + config = Jekyll::Utils.deep_merge_hashes(config, source: source) + Jekyll::Utils.deep_merge_hashes(Jekyll::Configuration::DEFAULTS, config) + end end def licenses - $licenses ||= begin - site.collections["licenses"].docs.map do |license| - id = File.basename(license.basename, ".txt") - license.to_liquid.merge("id" => id) + SpecHelper.licenses ||= begin + site.collections['licenses'].docs.map do |license| + id = File.basename(license.basename, '.txt') + license.to_liquid.merge('id' => id) end end end def hidden_licenses - licenses.select { |l| l["hidden"] } + licenses.select { |l| l['hidden'] } end def shown_licenses - licenses.select { |l| !l["hidden"] } + licenses.select { |l| !l['hidden'] } end def license_ids - licenses.map { |l| l["id"] } + licenses.map { |l| l['id'] } end def families - licenses.map { |l| l["family"] }.compact.uniq + licenses.map { |l| l['family'] }.compact.uniq end def site - $site ||= begin + SpecHelper.site ||= begin site = Jekyll::Site.new(config) site.reset site.read @@ -57,62 +66,62 @@ def site end def rules - site.data["rules"] + site.data['rules'] end def fields - site.data["fields"] + site.data['fields'] end def meta - site.data["meta"] + site.data['meta'] end def rule?(tag, group) - rules[group].any? { |r| r["tag"] == tag } + rules[group].any? { |r| r['tag'] == tag } end def spdx_list - url = "https://raw.githubusercontent.com/sindresorhus/spdx-license-list/master/spdx.json" - $spdx ||= JSON.parse(open(url).read) + url = 'https://raw.githubusercontent.com/sindresorhus/spdx-license-list/master/spdx.json' + SpecHelper.spdx ||= JSON.parse(open(url).read) end def spdx_ids - spdx_list.map { |name, properties| name.downcase } + spdx_list.map { |name, _properties| name.downcase } end def find_spdx(license) - spdx_list.find { |name, properties| name.downcase == license } + spdx_list.find { |name, _properties| name.casecmp(license).zero? } end def osi_approved_licenses - $osi_approved_licenses ||= begin + SpecHelper.osi_approved_licenses ||= begin licenses = {} - list = spdx_list.select { |id, meta| meta["osiApproved"] } + list = spdx_list.select { |_id, meta| meta['osiApproved'] } list.each do |id, meta| - licenses[id.downcase] = meta["name"] + licenses[id.downcase] = meta['name'] end licenses end end def fsf_approved_licenses - $fsf_approved_licenses ||= begin - url = "https://www.gnu.org/licenses/license-list.en.html" + SpecHelper.fsf_approved_licenses ||= begin + url = 'https://www.gnu.org/licenses/license-list.en.html' doc = Nokogiri::HTML(open(url).read) - list = doc.css(".green dt") + list = doc.css('.green dt') licenses = {} list.each do |license| - a = license.css("a").find { |link| !link.text.nil? && !link.text.empty? && link.attr("id") } + a = license.css('a').find { |link| !link.text.nil? && !link.text.empty? && link.attr('id') } next if a.nil? - id = a.attr("id").downcase + id = a.attr('id').downcase name = a.text.strip licenses[id] = name end # FSF approved the Clear BSD, but doesn't use its SPDX ID or Name - if licenses.keys.include? "clearbsd" - licenses["bsd-3-clause-clear"] = licenses["clearbsd"] + if licenses.keys.include? 'clearbsd' + licenses['bsd-3-clause-clear'] = licenses['clearbsd'] end licenses @@ -120,13 +129,13 @@ def fsf_approved_licenses end def od_approved_licenses - $od_approved_licenses ||= begin - url = "http://licenses.opendefinition.org/licenses/groups/od.json" + SpecHelper.od_approved_licenses ||= begin + url = 'http://licenses.opendefinition.org/licenses/groups/od.json' data = open(url).read data = JSON.parse(data) licenses = {} data.each do |id, meta| - licenses[id.downcase] = meta["title"] + licenses[id.downcase] = meta['title'] end licenses end