diff --git a/.gitignore b/.gitignore index ffefd5b..8bf1c4e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,6 @@ assets/vendor/clipboard/test assets/vendor/selectivizr/tests assets/vendor/qtip2/basic /vendor -Gemfile.lock /.sass-cache .ruby-version +/tmp diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4434c9..a40de79 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,17 +6,26 @@ We love Pull Requests! Your contributions help make ChooseALicense.com great. So you want to contribute to ChooseALicense. Great! We welcome any help we can get. But first, please make sure you understand what -[this site is all about](http://choosealicense.com/about). +[this site is all about](http://choosealicense.com/about). It’s not a comprehensive list of all possible licenses. -It’s not a comprehensive list of all possible licenses. +## Adding a license -If you understand the goals of this site and still want to suggest a change, -please: +Choosealicense.com is intended to demystify license choices, not present all of them. As such, there are several requirements for a license to be listed on the site: -* Make sure you have a [GitHub account](https://github.com/signup/free) -* Submit a ticket for your issue, assuming one does not already exist. - * Clearly describe the issue including steps to reproduce when it is a bug. - * Make sure you fill in the earliest version that you know has the issue. +1. The license must have [an SPDX identifier](https://spdx.org/licenses/). If your license isn't registered with SPDX, please [request that it be added](https://spdx.org/spdx-license-list/request-new-license-or-exception). +2. The license must be listed on one of the following approved lists of licenses: + * [List of OSI approved licenses](https://opensource.org/licenses/alphabetical) + * [GNU's list of free licenses](https://www.gnu.org/licenses/license-list.en.html) (*note: the license must be listed in one of thre three "free" categories*) + * [Open Definition's list of conformant licenses](http://opendefinition.org/licenses/) (non-code) +3. A [GitHub code search](https://github.com/search?q=MIT+filename%3ALICENSE&type=Code) must reveal at least *1,000* public repositories using the license + +If your proposed license meets the above criteria, here's a few other things to keep in mind as you propose the license's addition: + +* Licenses live in the `/_licenses` folder. +* Each license has both [required and optional metadata](https://github.com/github/choosealicense.com#license-metadata) that should be included. +* The text of the license should be wrapped to a 78 character width. +* The body of the file should be the text of the license in plain text. +* Almost without exception, new licenses should be added as hidden (`hidden: true` in the YAML front matter), such that they are directly linkable and detectable, but not otherwise listed. ## Making Changes diff --git a/Gemfile b/Gemfile index bf1cd2b..03c970a 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,8 @@ gem "github-pages" gem "jekyll-seo-tag" group :test do - gem "html-proofer" + gem 'html-proofer', '2.5.2' gem "rake" gem "rspec" + gem "nokogiri" end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..c0b5f8a --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + RedCloth (4.2.9) + activesupport (4.2.5) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.3.8) + blankslate (2.1.2.4) + classifier-reborn (2.0.4) + fast-stemmer (~> 1.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.10.0) + colorator (0.1) + colored (1.2) + diff-lcs (1.2.5) + ethon (0.8.1) + ffi (>= 1.3.0) + execjs (2.6.0) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) + fast-stemmer (1.0.2) + ffi (1.9.10) + gemoji (2.1.0) + github-pages (43) + RedCloth (= 4.2.9) + github-pages-health-check (= 0.6.0) + jekyll (= 2.4.0) + jekyll-coffeescript (= 1.0.1) + jekyll-feed (= 0.3.1) + jekyll-gist (= 1.4.0) + jekyll-mentions (= 0.2.1) + jekyll-paginate (= 1.1.0) + jekyll-redirect-from (= 0.9.1) + jekyll-sass-converter (= 1.3.0) + jekyll-seo-tag (= 0.1.4) + jekyll-sitemap (= 0.9.0) + jemoji (= 0.5.0) + kramdown (= 1.9.0) + liquid (= 2.6.2) + maruku (= 0.7.0) + mercenary (~> 0.3) + pygments.rb (= 0.6.3) + rdiscount (= 2.1.8) + redcarpet (= 3.3.3) + terminal-table (~> 1.4) + github-pages-health-check (0.6.0) + addressable (~> 2.3) + net-dns (~> 0.8) + public_suffix (~> 1.4) + typhoeus (~> 0.7) + html-pipeline (1.9.0) + activesupport (>= 2) + nokogiri (~> 1.4) + html-proofer (2.5.2) + addressable (~> 2.3) + colored (~> 1.2) + mercenary (~> 0.3.2) + nokogiri (~> 1.5) + parallel (~> 1.3) + typhoeus (~> 0.7) + yell (~> 2.0) + i18n (0.7.0) + jekyll (2.4.0) + classifier-reborn (~> 2.0) + colorator (~> 0.1) + jekyll-coffeescript (~> 1.0) + jekyll-gist (~> 1.0) + jekyll-paginate (~> 1.0) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 2.6.1) + mercenary (~> 0.3.3) + pygments.rb (~> 0.6.0) + redcarpet (~> 3.1) + safe_yaml (~> 1.0) + toml (~> 0.1.0) + jekyll-coffeescript (1.0.1) + coffee-script (~> 2.2) + jekyll-feed (0.3.1) + jekyll-gist (1.4.0) + octokit (~> 4.2) + jekyll-mentions (0.2.1) + html-pipeline (~> 1.9.0) + jekyll (~> 2.0) + jekyll-paginate (1.1.0) + jekyll-redirect-from (0.9.1) + jekyll (>= 2.0) + jekyll-sass-converter (1.3.0) + sass (~> 3.2) + jekyll-seo-tag (0.1.4) + jekyll (>= 2.0) + jekyll-sitemap (0.9.0) + jekyll-watch (1.3.0) + listen (~> 3.0) + jemoji (0.5.0) + gemoji (~> 2.0) + html-pipeline (~> 1.9) + jekyll (>= 2.0) + json (1.8.3) + kramdown (1.9.0) + liquid (2.6.2) + listen (3.0.5) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + maruku (0.7.0) + mercenary (0.3.5) + mini_portile2 (2.0.0) + minitest (5.8.3) + multipart-post (2.0.0) + net-dns (0.8.0) + nokogiri (1.6.7.1) + mini_portile2 (~> 2.0.0.rc2) + octokit (4.2.0) + sawyer (~> 0.6.0, >= 0.5.3) + parallel (1.6.1) + parslet (1.5.0) + blankslate (~> 2.0) + posix-spawn (0.3.11) + public_suffix (1.5.3) + pygments.rb (0.6.3) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.2.0) + rake (10.5.0) + rb-fsevent (0.9.7) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + rdiscount (2.1.8) + redcarpet (3.3.3) + rspec (3.4.0) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-core (3.4.1) + rspec-support (~> 3.4.0) + rspec-expectations (3.4.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-mocks (3.4.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-support (3.4.1) + safe_yaml (1.0.4) + sass (3.4.21) + sawyer (0.6.0) + addressable (~> 2.3.5) + faraday (~> 0.8, < 0.10) + terminal-table (1.5.2) + thread_safe (0.3.5) + toml (0.1.2) + parslet (~> 1.5.0) + typhoeus (0.8.0) + ethon (>= 0.8.0) + tzinfo (1.2.2) + thread_safe (~> 0.1) + yajl-ruby (1.2.1) + yell (2.0.5) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages + html-proofer (= 2.5.2) + jekyll-seo-tag + nokogiri + rake + rspec + +BUNDLED WITH + 1.11.2 diff --git a/README.md b/README.md index 655f049..2989483 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ Like a Choose Your Own Adventure site, but only much less interesting. A lot of repositories on GitHub.com don't have a license. GitHub provides a license chooser, but if you don't know anything about licenses, how are you supposed to make an informed decision? -[ChooseALicense.com](http://www.choosealicense.com "Choose A Licence website") is designed to help people make an informed decision about licenses. +[ChooseALicense.com](http://www.choosealicense.com "Choose A Licence website") is designed to help people make an informed decision about licenses by demystifying license choices through non-judgmental guidance. ## Immediate Goals -* Non-partisan. Our goal is to help you find a license that meets *your* goals. +* Non-judgmental. Our goal is to help you find a license that meets *your* goals. * Well designed, but that goes without saying. * The homepage should have just enough to help 99% of folks make a decision. * For the 1%, the site will contain a list of licenses common to specific communities and situations. @@ -28,11 +28,9 @@ script/server ``` Open `http://localhost:4000` in your favorite browser. -## Adding a license +## License metadata -Licenses sit in the `/_licenses` folder. The text of the license should be wrapped to a 78 character width. Each license has YAML front matter describing the license's properties. The body of the file should be the text of the license in plain text. The available metadata fields are: - -### YAML front matter +Licenses sit in the `/_licenses` folder. Each license has YAML front matter describing the license's properties. The body of the file contains the text of the license in plain text. The available metadata fields are: #### Required fields diff --git a/Rakefile b/Rakefile index fea4552..1ff9aa0 100644 --- a/Rakefile +++ b/Rakefile @@ -9,6 +9,19 @@ end task :test do sh "bundle exec jekyll build --trace" - HTML::Proofer.new("./_site", :check_html => true).run Rake::Task["spec"].invoke + HTML::Proofer.new("./_site", :check_html => true).run +end + +task :approved_licenses do + require './spec/spec_helper' + approved = approved_licenses + approved.select! { |l| spdx_ids.include?(l) } + puts "#{approved.count} approved licenses:" + puts approved.join(", ") + puts "\n" + + potential = approved - licenses.map { |l| l["id"] } + puts "#{potential.count} potential additions:" + puts potential.join(", ") end diff --git a/spec/license_spec.rb b/spec/license_spec.rb index fe4b73b..6bf43b0 100644 --- a/spec/license_spec.rb +++ b/spec/license_spec.rb @@ -1,35 +1,26 @@ require 'spec_helper' -# List of licenses that need not be OSI approved -LICENSE_WHITELIST = %w[ - unlicense - cc0-1.0 - wtfpl - bsd-3-clause-clear -] - licenses.each do |license| + + # "No license" isn't really a license, so no need to test + next if license["id"] == "no-license" + describe "The #{license["title"]} license" do - describe "SPDX compliance" do - # "No license" isn't really a license, so no need to test - unless license["id"] == "no-license" - it "#{license["id"]} should be a valid SPDX ID" do - expect(find_spdx(license["id"])).to_not be_nil - end - it "should be the proper SPDX name" do - spdx = find_spdx(license["id"]) - expect(spdx[1]["name"].gsub(/ only$/,"")).to eql(license["title"]) - end + let(:id) { license["id"] } - # CC0 and Unlicense are not OSI approved, but that's okay - unless LICENSE_WHITELIST.include? license["id"] - it "should be OSI approved" do - spdx = find_spdx(license["id"]) - approved = spdx[1]["osiApproved"] - expect(approved).to eql(true) - end - end + it "has an SPDX ID" do + expect(spdx_ids).to include(id) + end + + it "uses its SPDX name" do + spdx = find_spdx(id) + 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." end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 49dd589..4834964 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,8 @@ require 'jekyll' require 'open-uri' require 'json' +require 'open-uri' +require 'nokogiri' def config_file File.expand_path "./_config.yml", source @@ -54,6 +56,61 @@ def spdx_list $spdx ||= JSON.parse(open(url).read) end +def spdx_ids + spdx_list.map { |name, properties| name.downcase } +end + def find_spdx(license) spdx_list.find { |name, properties| name.downcase == license } end + +def osi_approved_licenses + $osi_approved_licenses ||= begin + licenses = {} + list = spdx_list.select { |id, meta| meta["osiApproved"] } + list.each do |id, meta| + 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" + doc = Nokogiri::HTML(open(url).read) + 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") } + next if a.nil? + 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"] + end + + licenses + end +end + +def od_approved_licenses + $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"] + end + licenses + end +end + +def approved_licenses + (osi_approved_licenses.keys + fsf_approved_licenses.keys + od_approved_licenses.keys).flatten.uniq.sort +end