Continue implementation of the license template selector and /licenses API endpoint

Signed-off-by: Rémy Coutable <remy@rymai.me>
This commit is contained in:
Rémy Coutable 2016-04-11 15:49:25 +02:00
parent 073c3d15c7
commit 13804aba86
22 changed files with 594 additions and 213 deletions

View File

@ -31,6 +31,8 @@ v 8.7.0 (unreleased)
- Fix a bug whith trailing slash in teamcity_url (Charles May)
- Allow back dating on issues when created or updated through the API
- Allow back dating on issue notes when created through the API
- Propose license template when creating a new LICENSE file
- API: Expose /licenses and /licenses/:key
- Fix avatar stretching by providing a cropping feature
- API: Expose `subscribed` for issues and merge requests (Robert Schilling)
- Allow SAML to handle external users based on user's information !3530

View File

@ -93,17 +93,15 @@
).done (projects) ->
callback(projects)
# Return text for specific license
licenseText: (key, fullname, callback) ->
url = Api.buildUrl(Api.license_path)
url = url.replace(':key', key)
# Return text for a specific license
licenseText: (key, data, callback) ->
url = Api.buildUrl(Api.license_path).replace(':key', key)
$.ajax(
url: url
data:
fullname: fullname
).done (projects) ->
callback(projects)
data: data
).done (license) ->
callback(license)
buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root?

View File

@ -1,24 +1,30 @@
class @BlobLicenseSelector
licenseRegex: /^(.+\/)?(licen[sc]e|copying)($|\.)/i
constructor: (editor)->
self = this
@licenseSelector = $('.js-license-selector')
@toggleLicenseSelector($('#file_name').val())
constructor: (editor) ->
@$licenseSelector = $('.js-license-selector')
$fileNameInput = $('#file_name')
$('#file_name').on 'input', ->
self.toggleLicenseSelector($(this).val())
initialFileNameValue = if $fileNameInput.length
$fileNameInput.val()
else if $('.editor-file-name').length
$('.editor-file-name').text().trim()
$('select.license-select').select2(
width: 'resolve'
dropdownAutoWidth: true
placeholder: 'Choose a license template'
).on 'change', (e) ->
Api.licenseText $(this).val(), $(this).data('fullname'), (data) ->
editor.setValue(data, -1)
@toggleLicenseSelector(initialFileNameValue)
if $fileNameInput
$fileNameInput.on 'keyup blur', (e) =>
@toggleLicenseSelector($(e.target).val())
$('select.license-select').on 'change', (e) ->
data =
project: $(this).data('project')
fullname: $(this).data('fullname')
Api.licenseText $(this).val(), data, (license) ->
editor.setValue(license.content, -1)
toggleLicenseSelector: (fileName) =>
if @licenseRegex.test(fileName)
@licenseSelector.show()
@$licenseSelector.show()
else
@licenseSelector.hide()
@$licenseSelector.hide()

View File

@ -1,44 +1,39 @@
class @EditBlob
constructor: (assets_path, mode)->
ace.config.set "modePath", assets_path + '/ace'
constructor: (assets_path, ace_mode = null) ->
ace.config.set "modePath", "#{assets_path}/ace"
ace.config.loadModule "ace/ext/searchbox"
if mode
ace_mode = mode
editor = ace.edit("editor")
editor.focus()
@editor = editor
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
@editor = ace.edit("editor")
@editor.focus()
@editor.getSession().setMode "ace/mode/#{ace_mode}" if ace_mode
# Before a form submission, move the content from the Ace editor into the
# submitted textarea
$('form').submit ->
$("#file-content").val(editor.getValue())
$('form').submit =>
$("#file-content").val(@editor.getValue())
editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a")
editModeLinks.click (event) ->
event.preventDefault()
currentLink = $(this)
paneId = currentLink.attr("href")
currentPane = editModePanes.filter(paneId)
editModeLinks.parent().removeClass "active hover"
currentLink.parent().addClass "active hover"
editModePanes.hide()
if paneId is "#preview"
currentPane.fadeIn 200
$.post currentLink.data("preview-url"),
content: editor.getValue()
, (response) ->
currentPane.empty().append response
currentPane.syntaxHighlight()
return
@initModePanesAndLinks()
new BlobLicenseSelector(@editor)
else
currentPane.fadeIn 200
editor.focus()
return
initModePanesAndLinks: ->
@$editModePanes = $(".js-edit-mode-pane")
@$editModeLinks = $(".js-edit-mode a")
@$editModeLinks.click @editModeLinkClickHandler
editor: ->
return @editor
editModeLinkClickHandler: (event) =>
event.preventDefault()
currentLink = $(event.target)
paneId = currentLink.attr("href")
currentPane = @$editModePanes.filter(paneId)
@$editModeLinks.parent().removeClass "active hover"
currentLink.parent().addClass "active hover"
@$editModePanes.hide()
currentPane.fadeIn 200
if paneId is "#preview"
$.post currentLink.data("preview-url"),
content: @editor.getValue()
, (response) ->
currentPane.empty().append response
currentPane.syntaxHighlight()
else
@editor.focus()

View File

@ -1,20 +0,0 @@
class @NewBlob
constructor: (assets_path, mode)->
ace.config.set "modePath", assets_path + '/ace'
ace.config.loadModule "ace/ext/searchbox"
if mode
ace_mode = mode
editor = ace.edit("editor")
editor.focus()
@editor = editor
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
# Before a form submission, move the content from the Ace editor into the
# submitted textarea
$('form').submit ->
$("#file-content").val(editor.getValue())
editor: ->
return @editor

View File

@ -122,15 +122,6 @@ class Projects::BlobController < Projects::ApplicationController
end
def editor_variables
@licenses = {
'Popular' => Licensee::License.all(featured: true).map!{ |license| [license.name, license.key] },
'Other' => Licensee::License.all(featured: false).map!{ |license| [license.name, license.key] }
}
unless @repository.empty?
@current_license_key = Licensee.license(@repository.path).try(:key)
end
@target_branch = params[:target_branch]
@file_path =

View File

@ -173,4 +173,15 @@ module BlobHelper
response.etag = @blob.id
!stale
end
def licenses_for_select
return @licenses_for_select if defined?(@licenses_for_select)
licenses = Licensee::License.all
@licenses_for_select = {
Popular: licenses.select(&:featured).map { |license| [license.name, license.key] },
Other: licenses.reject(&:featured).map { |license| [license.name, license.key] }
}
end
end

View File

@ -216,40 +216,14 @@ module ProjectsHelper
end
end
def add_contribution_guide_path(project)
if project && !project.repository.contribution_guide
namespace_project_new_blob_path(
project.namespace,
project,
project.default_branch,
file_name: "CONTRIBUTING.md",
commit_message: "Add contribution guide"
)
end
end
def add_changelog_path(project)
if project && !project.repository.changelog
namespace_project_new_blob_path(
project.namespace,
project,
project.default_branch,
file_name: "CHANGELOG",
commit_message: "Add changelog"
)
end
end
def add_license_path(project)
if project && !project.repository.license
namespace_project_new_blob_path(
project.namespace,
project,
project.default_branch,
file_name: "LICENSE",
commit_message: "Add license"
)
end
def add_special_file_path(project, file_name:, commit_message: nil)
namespace_project_new_blob_path(
project.namespace,
project,
project.default_branch || 'master',
file_name: file_name,
commit_message: commit_message || "Add #{file_name.downcase}"
)
end
def contribution_guide_path(project)
@ -272,7 +246,7 @@ module ProjectsHelper
end
def license_path(project)
filename_path(project, :license)
filename_path(project, :license_blob)
end
def version_path(project)
@ -342,6 +316,12 @@ module ProjectsHelper
@ref || @repository.try(:root_ref)
end
def license_short_name(project)
license = Licensee::License.new(project.repository.license_key)
license.nickname || license.name
end
private
def filename_path(project, filename)

View File

@ -228,7 +228,8 @@ class Repository
def cache_keys
%i(size branch_names tag_names commit_count
readme version contribution_guide changelog license)
readme version contribution_guide changelog
license_blob license_key)
end
def build_cache
@ -461,27 +462,21 @@ class Repository
end
end
def license
cache.fetch(:license) do
licenses = tree(:head).blobs.find_all do |file|
file.name =~ /\A(copying|license|licence)/i
end
def license_blob
return nil if !exists? || empty?
preferences = [
/\Alicen[sc]e\z/i, # LICENSE, LICENCE
/\Alicen[sc]e\./i, # LICENSE.md, LICENSE.txt
/\Acopying\z/i, # COPYING
/\Acopying\.(?!lesser)/i, # COPYING.txt
/Acopying.lesser/i # COPYING.LESSER
]
license = nil
preferences.each do |r|
license = licenses.find { |l| l.name =~ r }
break if license
cache.fetch(:license_blob) do
if licensee_project.license
blob_at_branch(root_ref, licensee_project.matched_file.filename)
end
end
end
license
def license_key
return nil if !exists? || empty?
cache.fetch(:license_key) do
licensee_project.license.try(:key) || 'no-license'
end
end
@ -925,4 +920,8 @@ class Repository
def cache
@cache ||= RepositoryCache.new(path_with_namespace)
end
def licensee_project
@licensee_project ||= Licensee.project(path)
end
end

View File

@ -9,7 +9,7 @@
- else
.gray-content-block.second-block.center
%h3.page-title
This project does not have README yet
This project does not have a README yet
- if can?(current_user, :push_code, @project)
%p
A
@ -18,5 +18,5 @@
distributed with computer software, forming part of its documentation.
%p
We recommend you to
= link_to "add README", new_readme_path, class: 'underlined-link'
= link_to "add a README", new_readme_path, class: 'underlined-link'
file to the repository and GitLab will render it here instead of this message.

View File

@ -14,7 +14,7 @@
.pull-right
.license-selector.js-license-selector.hide
= select_tag :license_type, grouped_options_for_select(@licenses, @current_license_key), include_blank: true, class: 'select2 license-select', data: { fullname: @repository.project.creator.name }
= select_tag :license_type, grouped_options_for_select(licenses_for_select, @project.repository.license_key), include_blank: true, class: 'select2 license-select', data: {placeholder: 'Choose a license template', project: @project.name, fullname: @project.namespace.human_name}
.encoding-selector
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'select2'
@ -26,8 +26,3 @@
.center
%h2
%i.icon-spinner.icon-spin
:javascript
window.onload = function() {
new BlobLicenseSelector(blob.editor)
}

View File

@ -14,5 +14,5 @@
cancel_path: namespace_project_tree_path(@project.namespace, @project, @id)
:javascript
blob = new NewBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}", null)
blob = new EditBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}")
new NewCommitForm($('.js-new-blob-form'))

View File

@ -14,10 +14,10 @@
%p
If you already have files you can push them using command line instructions below.
%p
Otherwise you can start with adding
Otherwise you can start with adding a
= link_to "README", new_readme_path, class: 'underlined-link'
or
= link_to "LICENSE", new_license_path, class: 'underlined-link'
or a
= link_to "LICENSE", add_special_file_path(@project, file_name: 'LICENSE'), class: 'underlined-link'
file to this project.
- if can?(current_user, :push_code, @project)

View File

@ -36,9 +36,9 @@
%li
= link_to 'Changelog', changelog_path(@project)
- if @repository.license
- if @repository.license_blob
%li
= link_to 'License', license_path(@project)
= link_to license_short_name(@project), license_path(@project)
- if @repository.contribution_guide
%li
@ -47,15 +47,15 @@
- if current_user && can_push_branch?(@project, @project.default_branch)
- unless @repository.changelog
%li.missing
= link_to add_changelog_path(@project) do
= link_to add_special_file_path(@project, file_name: 'CHANGELOG') do
Add Changelog
- unless @repository.license
- unless @repository.license_blob
%li.missing
= link_to add_license_path(@project) do
= link_to add_special_file_path(@project, file_name: 'LICENSE') do
Add License
- unless @repository.contribution_guide
%li.missing
= link_to add_contribution_guide_path(@project) do
= link_to add_special_file_path(@project, file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide') do
Add Contribution guide
- if @repository.commit

View File

@ -33,6 +33,7 @@ following locations:
- [Build triggers](build_triggers.md)
- [Build Variables](build_variables.md)
- [Runners](runners.md)
- [Licenses](licenses.md)
## Authentication

147
doc/api/licenses.md Normal file
View File

@ -0,0 +1,147 @@
# Licenses
## List license templates
Get all license templates.
```
GET /licenses
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
| `popular` | boolean | no | If passed, returns only popular licenses |
```bash
curl https://gitlab.example.com/api/v3/licenses?popular=1
```
Example response:
```json
[
{
"key": "apache-2.0",
"name": "Apache License 2.0",
"nickname": null,
"featured": true,
"html_url": "http://choosealicense.com/licenses/apache-2.0/",
"source_url": "http://www.apache.org/licenses/LICENSE-2.0.html",
"description": "A permissive license that also provides an express grant of patent rights from contributors to users.",
"conditions": [
"include-copyright",
"document-changes"
],
"permissions": [
"commercial-use",
"modifications",
"distribution",
"patent-use",
"private-use"
],
"limitations": [
"trademark-use",
"no-liability"
],
"content": " Apache License\n Version 2.0, January 2004\n [...]"
},
{
"key": "gpl-3.0",
"name": "GNU General Public License v3.0",
"nickname": "GNU GPLv3",
"featured": true,
"html_url": "http://choosealicense.com/licenses/gpl-3.0/",
"source_url": "http://www.gnu.org/licenses/gpl-3.0.txt",
"description": "The GNU GPL is the most widely used free software license and has a strong copyleft requirement. When distributing derived works, the source code of the work must be made available under the same license.",
"conditions": [
"include-copyright",
"document-changes",
"disclose-source",
"same-license"
],
"permissions": [
"commercial-use",
"modifications",
"distribution",
"patent-use",
"private-use"
],
"limitations": [
"no-liability"
],
"content": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n [...]"
},
{
"key": "mit",
"name": "MIT License",
"nickname": null,
"featured": true,
"html_url": "http://choosealicense.com/licenses/mit/",
"source_url": "http://opensource.org/licenses/MIT",
"description": "A permissive license that is short and to the point. It lets people do anything with your code with proper attribution and without warranty.",
"conditions": [
"include-copyright"
],
"permissions": [
"commercial-use",
"modifications",
"distribution",
"private-use"
],
"limitations": [
"no-liability"
],
"content": "The MIT License (MIT)\n\nCopyright (c) [year] [fullname]\n [...]"
}
]
```
## Single license template
Get a single license template. You can pass parameters to replace the license
placeholder.
```
GET /licenses/:key
```
| Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- |
| `key` | string | yes | The key of the license template |
| `project` | string | no | The copyrighted project name |
| `fullname` | string | no | The full-name of the copyright holder |
>**Note:**
If you omit the `fullname` parameter but authenticate your request, the name of
the authenticated user will be used to replace the copyright holder placeholder.
```bash
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/licenses/mit?project=My+Cool+Project
```
Example response:
```json
{
"key": "mit",
"name": "MIT License",
"nickname": null,
"featured": true,
"html_url": "http://choosealicense.com/licenses/mit/",
"source_url": "http://opensource.org/licenses/MIT",
"description": "A permissive license that is short and to the point. It lets people do anything with your code with proper attribution and without warranty.",
"conditions": [
"include-copyright"
],
"permissions": [
"commercial-use",
"modifications",
"distribution",
"private-use"
],
"limitations": [
"no-liability"
],
"content": "The MIT License (MIT)\n\nCopyright (c) 2016 John Doe\n [...]"
}
```

View File

@ -439,5 +439,16 @@ module API
class Variable < Grape::Entity
expose :key, :value
end
class License < Grape::Entity
expose :key, :name, :nickname, :featured
expose :url, as: :html_url
expose(:source_url) { |license| license.meta['source'] }
expose(:description) { |license| license.meta['description'] }
expose(:conditions) { |license| license.meta['required'] }
expose(:permissions) { |license| license.meta['permitted'] }
expose(:limitations) { |license| license.meta['forbidden'] }
expose :content
end
end
end

View File

@ -1,27 +1,58 @@
module API
# Licenses API
class Licenses < Grape::API
YEAR_TEMPLATE_REGEX = /(\[|<|{)(year|yyyy)(\]|>|})/
FULLNAME_TEMPLATE_REGEX = /\[fullname\]/
PROJECT_TEMPLATE_REGEX =
/[\<\{\[]
(project|description|
one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
[\>\}\]]/xi
YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i
FULLNAME_TEMPLATE_REGEX =
/[\<\{\[]
(fullname|name\sof\s(author|copyright\sowner))
[\>\}\]]/xi
# Get the list of the available license templates
#
# Parameters:
# popular - Filter licenses to only the popular ones
#
# Example Request:
# GET /licenses
# GET /licenses?popular=1
get 'licenses' do
options = {
featured: params[:popular].present? ? true : nil
}
present Licensee::License.all(options), with: Entities::License
end
# Get text for specific license
#
# Parameters:
# key (required) - The key of a license
# fullname - Reository owner fullname
# project - Copyrighted project name
# fullname - Full name of copyright holder
#
# Example Request:
# GET /licenses/mit
get 'licenses/:key', requirements: { key: /[\w.-]*/ } do
env['api.format'] = :txt
license = Licensee::License.find(params[:key]).try(:text)
#
get 'licenses/:key', requirements: { key: /[\w\.-]+/ } do
required_attributes! [:key]
if license
license
.gsub(YEAR_TEMPLATE_REGEX, Time.now.year.to_s)
.gsub(FULLNAME_TEMPLATE_REGEX, params[:fullname])
else
error!('License not found', 404)
end
not_found!('License') unless Licensee::License.find(params[:key])
# We create a fresh Licensee::License object since we'll modify its
# content in place below.
license = Licensee::License.new(params[:key])
license.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s)
license.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present?
fullname = params[:fullname].presence || current_user.try(:name)
license.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname
present license, with: Entities::License
end
end
end

View File

@ -0,0 +1,61 @@
require 'spec_helper'
feature 'creates a license file', feature: true, js: true do
include Select2Helper
let(:project_master) { create(:user) }
let(:project) { create(:project) }
background do
project.repository.remove_file(project_master, 'LICENSE', 'Remove LICENSE', 'master')
project.team << [project_master, :master]
login_as(project_master)
visit namespace_project_path(project.namespace, project)
end
scenario 'project master creates a license file manually from a template' do
visit namespace_project_tree_path(project.namespace, project, project.repository.root_ref)
find('.add-to-tree').click
click_link 'New file'
fill_in :file_name, with: 'LICENSE'
expect(page).to have_selector('.license-selector')
select2('mit', from: '#license_type')
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
end
scenario 'project master creates a license file from the "Add license" link' do
click_link 'Add License'
expect(current_path).to eq(
namespace_project_new_blob_path(project.namespace, project, 'master'))
expect(find('#file_name').value).to eq('LICENSE')
expect(page).to have_selector('.license-selector')
select2('mit', from: '#license_type')
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
end
end

View File

@ -0,0 +1,36 @@
require 'spec_helper'
feature 'creates a license file in empty project', feature: true, js: true do
include Select2Helper
let(:project_master) { create(:user) }
let(:project) { create(:project_empty_repo) }
background do
project.team << [project_master, :master]
login_as(project_master)
visit namespace_project_path(project.namespace, project)
end
scenario 'project master creates a license file from a template' do
click_on 'LICENSE'
expect(current_path).to eq(
namespace_project_new_blob_path(project.namespace, project, 'master'))
expect(find('#file_name').value).to eq('LICENSE')
expect(page).to have_selector('.license-selector')
select2('mit', from: '#license_type')
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
end
end

View File

@ -135,22 +135,69 @@ describe Repository, models: true do
end
describe "#license" do
describe '#license_blob' do
before do
repository.send(:cache).expire(:license)
repository.send(:cache).expire(:license_blob)
repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master')
end
it 'test selection preference' do
files = [TestBlob.new('file'), TestBlob.new('license'), TestBlob.new('copying')]
expect(repository.tree).to receive(:blobs).and_return(files)
it 'looks in the root_ref only' do
repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'markdown')
repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'markdown', false)
expect(repository.license.name).to eq('license')
expect(repository.license_blob).to be_nil
end
it 'also accepts licence instead of license' do
expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('licence')])
it 'favors license file with no extension' do
repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false)
repository.commit_file(user, 'LICENSE.md', Licensee::License.new('mit').content, 'Add LICENSE.md', 'master', false)
expect(repository.license.name).to eq('licence')
expect(repository.license_blob.name).to eq('LICENSE')
end
it 'favors .md file to .txt' do
repository.commit_file(user, 'LICENSE.md', Licensee::License.new('mit').content, 'Add LICENSE.md', 'master', false)
repository.commit_file(user, 'LICENSE.txt', Licensee::License.new('mit').content, 'Add LICENSE.txt', 'master', false)
expect(repository.license_blob.name).to eq('LICENSE.md')
end
it 'favors LICENCE to LICENSE' do
repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false)
repository.commit_file(user, 'LICENCE', Licensee::License.new('mit').content, 'Add LICENCE', 'master', false)
expect(repository.license_blob.name).to eq('LICENCE')
end
it 'favors LICENSE to COPYING' do
repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false)
repository.commit_file(user, 'COPYING', Licensee::License.new('mit').content, 'Add COPYING', 'master', false)
expect(repository.license_blob.name).to eq('LICENSE')
end
it 'favors LICENCE to COPYING' do
repository.commit_file(user, 'LICENCE', Licensee::License.new('mit').content, 'Add LICENCE', 'master', false)
repository.commit_file(user, 'COPYING', Licensee::License.new('mit').content, 'Add COPYING', 'master', false)
expect(repository.license_blob.name).to eq('LICENCE')
end
end
describe '#license_key' do
before do
repository.send(:cache).expire(:license_key)
repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master')
end
it 'returns "no-license" when no license is detected' do
expect(repository.license_key).to eq('no-license')
end
it 'returns the license key' do
repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'master', false)
expect(repository.license_key).to eq('mit')
end
end

View File

@ -1,45 +1,135 @@
require 'spec_helper'
describe API::API, api: true do
describe API::Licenses, api: true do
include ApiHelpers
describe 'Entity' do
before { get api('/licenses/mit') }
it { expect(json_response['key']).to eq('mit') }
it { expect(json_response['name']).to eq('MIT License') }
it { expect(json_response['nickname']).to be_nil }
it { expect(json_response['featured']).to be true }
it { expect(json_response['html_url']).to eq('http://choosealicense.com/licenses/mit/') }
it { expect(json_response['source_url']).to eq('http://opensource.org/licenses/MIT') }
it { expect(json_response['description']).to include('A permissive license that is short and to the point.') }
it { expect(json_response['conditions']).to eq(%w[include-copyright]) }
it { expect(json_response['permissions']).to eq(%w[commercial-use modifications distribution private-use]) }
it { expect(json_response['limitations']).to eq(%w[no-liability]) }
it { expect(json_response['content']).to include('The MIT License (MIT)') }
end
describe 'GET /licenses' do
it 'returns a list of available license templates' do
get api('/licenses')
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.size).to eq(15)
expect(json_response.first['key']).to eq('agpl-3.0')
end
describe 'the popular parameter' do
context 'with popular=1' do
it 'returns a list of available popular license templates' do
get api('/licenses?popular=1')
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.size).to eq(3)
expect(json_response.first['key']).to eq('apache-2.0')
end
end
end
end
describe 'GET /licenses/:key' do
before(:each) do
get api("/licenses/#{license_type}?fullname=Anton")
end
context 'with :project and :fullname given' do
before do
get api("/licenses/#{license_type}?project=My+Awesome+Project&fullname=Anton+#{license_type.upcase}")
end
context 'for mit license name' do
let(:license_type){ 'mit' }
context 'for the mit license' do
let(:license_type) { 'mit' }
it 'returns MIT license text and replases template values' do
expect(response.body).to include('Copyright (c) 2016 Anton')
expect(response.body).to include('Copyright (c) 2016')
it 'returns the license text' do
expect(json_response['content']).to include('The MIT License (MIT)')
end
it 'replaces placeholder values' do
expect(json_response['content']).to include('Copyright (c) 2016 Anton')
end
end
context 'for the agpl-3.0 license' do
let(:license_type) { 'agpl-3.0' }
it 'returns the license text' do
expect(json_response['content']).to include('GNU AFFERO GENERAL PUBLIC LICENSE')
end
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
expect(json_response['content']).to include('Copyright (C) 2016 Anton')
end
end
context 'for the gpl-3.0 license' do
let(:license_type) { 'gpl-3.0' }
it 'returns the license text' do
expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE')
end
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
expect(json_response['content']).to include('Copyright (C) 2016 Anton')
end
end
context 'for the gpl-2.0 license' do
let(:license_type) { 'gpl-2.0' }
it 'returns the license text' do
expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE')
end
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
expect(json_response['content']).to include('Copyright (C) 2016 Anton')
end
end
context 'for the apache-2.0 license' do
let(:license_type) { 'apache-2.0' }
it 'returns the license text' do
expect(json_response['content']).to include('Apache License')
end
it 'replaces placeholder values' do
expect(json_response['content']).to include('Copyright 2016 Anton')
end
end
context 'for an uknown license' do
let(:license_type) { 'muth-over9000' }
it 'returns a 404' do
expect(response.status).to eq(404)
end
end
end
context 'for gnu license name' do
let(:license_type){ 'gpl-3.0' }
context 'with no :fullname given' do
context 'with an authenticated user' do
let(:user) { create(:user) }
it 'returns GNU license text and replases template values' do
expect(response.body).to include('GNU GENERAL PUBLIC LICENSE')
expect(response.body).to include('Copyright (C) 2016')
end
end
it 'replaces the copyright owner placeholder with the name of the current user' do
get api('/licenses/mit', user)
context 'for apache license name' do
let(:license_type){ 'apache-2.0' }
it 'returns Apache license text and replases template values' do
expect(response.body).to include('Apache License')
expect(response.body).to include('Copyright 2016')
end
end
context 'for mythic license name' do
let(:license_type){ 'muth-over9000' }
it 'returns string with error' do
expect(response).to have_http_status(404)
expect(response.body).to eq 'License not found'
expect(json_response['content']).to include("Copyright (c) 2016 #{user.name}")
end
end
end
end