Commit 706255b9 authored by Jeroen Nijhof's avatar Jeroen Nijhof

Merge gitlab.com:gitlab-org/gitlab-ce

parents e0436005 f394ccd5
...@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.4.0 (unreleased) v 8.4.0 (unreleased)
- Add housekeeping function to project settings page - Add housekeeping function to project settings page
- The default GitLab logo now acts as a loading indicator
- Accept 2xx status codes for successful Web hook triggers (Stan Hu) - Accept 2xx status codes for successful Web hook triggers (Stan Hu)
- Fix missing date of month in network graph when commits span a month (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu)
- Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu)
...@@ -22,6 +23,7 @@ v 8.4.0 (unreleased) ...@@ -22,6 +23,7 @@ v 8.4.0 (unreleased)
- Add system hook messages for project rename and transfer (Steve Norman) - Add system hook messages for project rename and transfer (Steve Norman)
- Fix version check image in Safari - Fix version check image in Safari
- Show 'All' tab by default in the builds page - Show 'All' tab by default in the builds page
- Add Open Graph and Twitter Card data to all pages
- Fix API project lookups when querying with a namespace with dots (Stan Hu) - Fix API project lookups when querying with a namespace with dots (Stan Hu)
- Update version check images to use SVG - Update version check images to use SVG
- Validate README format before displaying - Validate README format before displaying
...@@ -32,9 +34,13 @@ v 8.4.0 (unreleased) ...@@ -32,9 +34,13 @@ v 8.4.0 (unreleased)
- API: Add support for deleting a tag via the API (Robert Schilling) - API: Add support for deleting a tag via the API (Robert Schilling)
v 8.3.3 (unreleased) v 8.3.3 (unreleased)
- Preserve CE behavior with JIRA integration by only calling API if URL is set
- Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running
- Suppress e-mails on failed builds if allow_failure is set (Stan Hu)
- Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu)
- Enable "Add key" button when user fills in a proper key (Stan Hu) - Enable "Add key" button when user fills in a proper key (Stan Hu)
- Fix error in processing reply-by-email messages (Jason Lee)
- Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu)
v 8.3.2 v 8.3.2
- Change single user API endpoint to return more detailed data (Michael Potthoff) - Change single user API endpoint to return more detailed data (Michael Potthoff)
......
...@@ -66,7 +66,7 @@ class @DropzoneInput ...@@ -66,7 +66,7 @@ class @DropzoneInput
success: (header, response) -> success: (header, response) ->
child = $(dropzone[0]).children("textarea") child = $(dropzone[0]).children("textarea")
$(child).val $(child).val() + formatLink(response.link) + "\n" $(child).val $(child).val() + response.link.markdown + "\n"
return return
error: (temp, errorMessage) -> error: (temp, errorMessage) ->
...@@ -99,11 +99,6 @@ class @DropzoneInput ...@@ -99,11 +99,6 @@ class @DropzoneInput
child = $(dropzone[0]).children("textarea") child = $(dropzone[0]).children("textarea")
formatLink = (link) ->
text = "[#{link.alt}](#{link.url})"
text = "!#{text}" if link.is_image
text
handlePaste = (event) -> handlePaste = (event) ->
pasteEvent = event.originalEvent pasteEvent = event.originalEvent
if pasteEvent.clipboardData and pasteEvent.clipboardData.items if pasteEvent.clipboardData and pasteEvent.clipboardData.items
...@@ -162,7 +157,7 @@ class @DropzoneInput ...@@ -162,7 +157,7 @@ class @DropzoneInput
closeAlertMessage() closeAlertMessage()
success: (e, textStatus, response) -> success: (e, textStatus, response) ->
insertToTextArea(filename, formatLink(response.responseJSON.link)) insertToTextArea(filename, response.responseJSON.link.markdown)
error: (response) -> error: (response) ->
showError(response.responseJSON.message) showError(response.responseJSON.message)
...@@ -202,8 +197,3 @@ class @DropzoneInput ...@@ -202,8 +197,3 @@ class @DropzoneInput
e.preventDefault() e.preventDefault()
$(@).closest('.gfm-form').find('.div-dropzone').click() $(@).closest('.gfm-form').find('.div-dropzone').click()
return return
formatLink: (link) ->
text = "[#{link.alt}](#{link.url})"
text = "!#{text}" if link.is_image
text
...@@ -206,7 +206,7 @@ module Ci ...@@ -206,7 +206,7 @@ module Ci
def trace def trace
trace = raw_trace trace = raw_trace
if project && trace.present? if project && trace.present? && project.runners_token.present?
trace.gsub(project.runners_token, 'xxxxxx') trace.gsub(project.runners_token, 'xxxxxx')
else else
trace trace
......
...@@ -50,6 +50,7 @@ class Project < ActiveRecord::Base ...@@ -50,6 +50,7 @@ class Project < ActiveRecord::Base
include Sortable include Sortable
include AfterCommitQueue include AfterCommitQueue
include CaseSensitivity include CaseSensitivity
include TokenAuthenticatable
extend Gitlab::ConfigHelper extend Gitlab::ConfigHelper
...@@ -193,10 +194,8 @@ class Project < ActiveRecord::Base ...@@ -193,10 +194,8 @@ class Project < ActiveRecord::Base
if: ->(project) { project.avatar.present? && project.avatar_changed? } if: ->(project) { project.avatar.present? && project.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i } validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
before_validation :set_runners_token_token add_authentication_token_field :runners_token
def set_runners_token_token before_save :ensure_runners_token
self.runners_token = SecureRandom.hex(15) if self.runners_token.blank?
end
mount_uploader :avatar, AvatarUploader mount_uploader :avatar, AvatarUploader
...@@ -900,4 +899,8 @@ class Project < ActiveRecord::Base ...@@ -900,4 +899,8 @@ class Project < ActiveRecord::Base
return true unless forked? return true unless forked?
Gitlab::VisibilityLevel.allowed_fork_levels(forked_from_project.visibility_level).include?(level.to_i) Gitlab::VisibilityLevel.allowed_fork_levels(forked_from_project.visibility_level).include?(level.to_i)
end end
def runners_token
ensure_runners_token!
end
end end
...@@ -73,12 +73,16 @@ class BuildsEmailService < Service ...@@ -73,12 +73,16 @@ class BuildsEmailService < Service
when 'success' when 'success'
!notify_only_broken_builds? !notify_only_broken_builds?
when 'failed' when 'failed'
true !allow_failure?(data)
else else
false false
end end
end end
def allow_failure?(data)
data[:build_allow_failure] == true
end
def all_recipients(data) def all_recipients(data)
all_recipients = recipients.split(',') all_recipients = recipients.split(',')
......
...@@ -116,6 +116,7 @@ class JiraService < IssueTrackerService ...@@ -116,6 +116,7 @@ class JiraService < IssueTrackerService
end end
def test_settings def test_settings
return unless api_url.present?
result = JiraService.get( result = JiraService.get(
jira_api_test_url, jira_api_test_url,
headers: { headers: {
...@@ -213,6 +214,7 @@ class JiraService < IssueTrackerService ...@@ -213,6 +214,7 @@ class JiraService < IssueTrackerService
end end
def send_message(url, message) def send_message(url, message)
return unless api_url.present?
result = JiraService.post( result = JiraService.post(
url, url,
body: message, body: message,
...@@ -238,6 +240,7 @@ class JiraService < IssueTrackerService ...@@ -238,6 +240,7 @@ class JiraService < IssueTrackerService
end end
def existing_comment?(issue_name, new_comment) def existing_comment?(issue_name, new_comment)
return unless api_url.present?
result = JiraService.get( result = JiraService.get(
comment_url(issue_name), comment_url(issue_name),
headers: { headers: {
......
...@@ -16,13 +16,7 @@ module Projects ...@@ -16,13 +16,7 @@ module Projects
uploader.download!(@url) uploader.download!(@url)
uploader.store! uploader.store!
filename = uploader.image? ? uploader.file.basename : uploader.file.filename uploader.to_h
{
'alt' => filename,
'url' => uploader.secure_url,
'is_image' => uploader.image?
}
end end
private private
......
...@@ -10,13 +10,7 @@ module Projects ...@@ -10,13 +10,7 @@ module Projects
uploader = FileUploader.new(@project) uploader = FileUploader.new(@project)
uploader.store!(@file) uploader.store!(@file)
filename = uploader.image? ? uploader.file.basename : uploader.file.filename uploader.to_h
{
alt: filename,
url: uploader.secure_url,
is_image: uploader.image?
}
end end
private private
......
...@@ -30,4 +30,19 @@ class FileUploader < CarrierWave::Uploader::Base ...@@ -30,4 +30,19 @@ class FileUploader < CarrierWave::Uploader::Base
def secure_url def secure_url
File.join("/uploads", @secret, file.filename) File.join("/uploads", @secret, file.filename)
end end
def to_h
filename = image? ? self.file.basename : self.file.filename
escaped_filename = filename.gsub("]", "\\]")
markdown = "[#{escaped_filename}](#{self.secure_url})"
markdown.prepend("!") if image?
{
alt: filename,
url: self.secure_url,
is_image: image?,
markdown: markdown
}
end
end end
...@@ -17,6 +17,7 @@ class NamespaceValidator < ActiveModel::EachValidator ...@@ -17,6 +17,7 @@ class NamespaceValidator < ActiveModel::EachValidator
hooks hooks
issues issues
merge_requests merge_requests
new
notes notes
profile profile
projects projects
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, remote: true, method: :delete, class: "btn btn-xs btn-remove js-remove-tr" data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, remote: true, method: :delete, class: "btn btn-xs btn-remove js-remove-tr"
%td %td
- if user - if user && !user.blocked?
= link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs" = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs"
- else
.btn.btn-xs.disabled
Already Blocked
= link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr" = link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr"
...@@ -47,14 +47,14 @@ ...@@ -47,14 +47,14 @@
= f.label :issues_events, class: 'list-label' do = f.label :issues_events, class: 'list-label' do
%strong Issues events %strong Issues events
%p.light %p.light
This url will be triggered when an issue is created This url will be triggered when an issue is created/updated/merged
%div %div
= f.check_box :merge_requests_events, class: 'pull-left' = f.check_box :merge_requests_events, class: 'pull-left'
.prepend-left-20 .prepend-left-20
= f.label :merge_requests_events, class: 'list-label' do = f.label :merge_requests_events, class: 'list-label' do
%strong Merge Request events %strong Merge Request events
%p.light %p.light
This url will be triggered when a merge request is created This url will be triggered when a merge request is created/updated/merged
%div %div
= f.check_box :build_events, class: 'pull-left' = f.check_box :build_events, class: 'pull-left'
.prepend-left-20 .prepend-left-20
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
= form.label :issues_events, class: 'list-label' do = form.label :issues_events, class: 'list-label' do
%strong Issues events %strong Issues events
%p.light %p.light
This url will be triggered when an issue is created This url will be triggered when an issue is created/updated/merged
- if @service.supported_events.include?("merge_request") - if @service.supported_events.include?("merge_request")
%div %div
= form.check_box :merge_requests_events, class: 'pull-left' = form.check_box :merge_requests_events, class: 'pull-left'
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
= form.label :merge_requests_events, class: 'list-label' do = form.label :merge_requests_events, class: 'list-label' do
%strong Merge Request events %strong Merge Request events
%p.light %p.light
This url will be triggered when a merge request is created This url will be triggered when a merge request is created/updated/merged
- if @service.supported_events.include?("build") - if @service.supported_events.include?("build")
%div %div
= form.check_box :build_events, class: 'pull-left' = form.check_box :build_events, class: 'pull-left'
......
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
.title .title
.cross-project-reference .cross-project-reference
%span#cross-project-reference %span#cross-project-reference
References: Reference:
%a{href: '#', title:project_ref} %a{href: '#', title:project_ref}
= project_ref = project_ref
= clipboard_button(clipboard_target: 'span#cross-project-reference') = clipboard_button(clipboard_target: 'span#cross-project-reference')
......
...@@ -482,6 +482,34 @@ Parameters: ...@@ -482,6 +482,34 @@ Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
## Uploads
### Upload a file
Uploads a file to the specified project to be used in an issue or merge request description, or a comment.
```
POST /projects/:id/uploads
```
Parameters:
- `id` (required) - The ID of the project
- `file` (required) - The file to be uploaded
```json
{
"alt": "dk",
"url": "/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png",
"is_image": true,
"markdown": "![dk](/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png)"
}
```
**Note**: The returned `url` is relative to the project path.
In Markdown contexts, the link is automatically expanded when the format in `markdown` is used.
## Team members ## Team members
### List project team members ### List project team members
......
...@@ -552,6 +552,6 @@ Apart from the always supported markdown style there are other rich text files t ...@@ -552,6 +552,6 @@ Apart from the always supported markdown style there are other rich text files t
If you see this message when attempting to clone a repository hosted by GitLab, If you see this message when attempting to clone a repository hosted by GitLab,
this is likely due to an outdated Nginx or Apache configuration, or a missing or this is likely due to an outdated Nginx or Apache configuration, or a missing or
misconfigured `gitlab-git-http-server` instance. Double-check that you've misconfigured gitlab-workhorse instance. Double-check that you've
[installed Go](#3-go), [installed gitlab-git-http-server](#install-gitlab-git-http-server), [installed Go](#3-go), [installed gitlab-workhorse](#install-gitlab-workhorse),
and correctly [configured Nginx](#site-configuration). and correctly [configured Nginx](#site-configuration).
# Project users # Project users
You can manage the groups and users and their access levels in all of your projects. You can also personalize the access level you give each user, per project. You can manage the groups and users and their access levels in all of your
projects. You can also personalize the access level you give each user,
per-project.
Here's how to add or import users to your projects. You should have `master` or `owner` permissions to add or import a new user
You should have 'master' or 'owner' permissions to add or import a new user
to your project. to your project.
To add or import a user, go to your project and click on "Members" on the left side of your screen: The first step to add or import a user, go to your project and click on
**Members** on the left side of your screen.
![Members](img/add_user_members_menu.png)
---
## Add a user
Right next to **People**, start typing the name or username of the user you
want to add.
![Search for people](img/add_user_search_people.png)
---
Select the user and the [permission level](../../permissions/permissions.md)
that you'd like to give the user. Note that you can select more than one user.
![Give user permissions](img/add_user_give_permissions.png)
---
Once done, hit **Add users to project** and they will be immediately added to
your project with the permissions you gave them above.
![List members](img/add_user_list_members.png)
---
From there on, you can either remove an existing user or change their access
level to the project.
## Import users from another project
You can import another project's users in your own project by hitting the
**Import members** button on the upper right corner of the **Members** menu.
In the dropdown menu, you can see only the projects you are Master on.
![Import members from another project](img/add_user_import_members_from_another_project.png)
---
Select the one you want and hit **Import project members**. A flash message
notifying you that the import was successful will appear, and the new members
are now in the project's members list. Notice that the permissions that they
had on the project you imported from are retained.
![Members list of new members](img/add_user_imported_members.png)
---
## Invite people using their e-mail address
If a user you want to give access to doesn't have an account on your GitLab
instance, you can invite them just by typing their e-mail address in the
user search field.
![Invite user by mail](img/add_user_email_search.png)
---
![Members](images/members.png) As you can imagine, you can mix inviting multiple people and adding existing
GitLab users to the project.
Select "Add members" or "Import members" on the right side of your screen: ![Invite user by mail ready to submit](img/add_user_email_ready.png)
![Add or Import](images/add-members.png) ---
If you are adding a user, select the user and the [permission level](doc/permissions/permissions.md) that you'd like to Once done, hit **Add users to project** and watch that there is a new member
give the user: with the e-mail address we used above. From there on, you can resend the
invitation, change their access level or even delete them.
![Add or Import](images/new-member.png) ![Invite user members list](img/add_user_email_accept.png)
If you are importing a user, follow the steps to select the project where you'd like to import the user from: ---
![Add or Import](images/select-project.png) Once the user accepts the invitation, they will be prompted to create a new
GitLab account using the same e-mail address the invitation was sent to.
...@@ -278,6 +278,16 @@ module API ...@@ -278,6 +278,16 @@ module API
user_project.forked_project_link.destroy user_project.forked_project_link.destroy
end end
end end
# Upload a file
#
# Parameters:
# id: (required) - The ID of the project
# file: (required) - The file to be uploaded
post ":id/uploads" do
::Projects::UploadService.new(user_project, params[:file]).execute
end
# search for projects current_user has access to # search for projects current_user has access to
# #
# Parameters: # Parameters:
......
...@@ -23,6 +23,7 @@ module Gitlab ...@@ -23,6 +23,7 @@ module Gitlab
build_started_at: build.started_at, build_started_at: build.started_at,
build_finished_at: build.finished_at, build_finished_at: build.finished_at,
build_duration: build.duration, build_duration: build.duration,
build_allow_failure: build.allow_failure,
# TODO: do we still need it? # TODO: do we still need it?
project_id: project.id, project_id: project.id,
......
...@@ -82,10 +82,7 @@ module Gitlab ...@@ -82,10 +82,7 @@ module Gitlab
attachments = Email::AttachmentUploader.new(message).execute(sent_notification.project) attachments = Email::AttachmentUploader.new(message).execute(sent_notification.project)
attachments.each do |link| attachments.each do |link|
text = "[#{link[:alt]}](#{link[:url]})" reply << "\n\n#{link[:markdown]}"
text.prepend("!") if link[:is_image]
reply << "\n\n#{text}"
end end
reply reply
......
...@@ -232,9 +232,7 @@ module Gitlab ...@@ -232,9 +232,7 @@ module Gitlab
return nil if res.nil? return nil if res.nil?
text = "[#{res['alt']}](#{res['url']})" res[:markdown]
text = "!#{text}" if res['is_image']
text
end end
def build_attachment_url(rel_url) def build_attachment_url(rel_url)
......
...@@ -7,4 +7,10 @@ describe Banzai::Filter::TaskListFilter, lib: true do ...@@ -7,4 +7,10 @@ describe Banzai::Filter::TaskListFilter, lib: true do
exp = act = %(<ul><li>Item</li></ul>) exp = act = %(<ul><li>Item</li></ul>)
expect(filter(act).to_html).to eq exp expect(filter(act).to_html).to eq exp
end end
it 'applies `task-list` to single-item task lists' do
act = filter('<ul><li>[ ] Task 1</li></ul>')
expect(act.to_html).to start_with '<ul class="task-list">'
end
end end
...@@ -14,6 +14,7 @@ describe 'Gitlab::BuildDataBuilder' do ...@@ -14,6 +14,7 @@ describe 'Gitlab::BuildDataBuilder' do
it { expect(data[:tag]).to eq(build.tag) } it { expect(data[:tag]).to eq(build.tag) }
it { expect(data[:build_id]).to eq(build.id) } it { expect(data[:build_id]).to eq(build.id) }
it { expect(data[:build_status]).to eq(build.status) } it { expect(data[:build_status]).to eq(build.status) }
it { expect(data[:build_allow_failure]).to eq(false) }
it { expect(data[:project_id]).to eq(build.project.id) } it { expect(data[:project_id]).to eq(build.project.id) }
it { expect(data[:project_name]).to eq(build.project.name_with_namespace) } it { expect(data[:project_name]).to eq(build.project.name_with_namespace) }
end end
......
...@@ -107,13 +107,16 @@ describe Gitlab::Email::Receiver, lib: true do ...@@ -107,13 +107,16 @@ describe Gitlab::Email::Receiver, lib: true do
end end
context "when everything is fine" do context "when everything is fine" do
let(:markdown) { "![image](uploads/image.png)" }
before do before do
allow_any_instance_of(Gitlab::Email::AttachmentUploader).to receive(:execute).and_return( allow_any_instance_of(Gitlab::Email::AttachmentUploader).to receive(:execute).and_return(
[ [
{ {
url: "uploads/image.png", url: "uploads/image.png",
is_image: true, is_image: true,
alt: "image" alt: "image",
markdown: markdown
} }
] ]
) )
...@@ -132,7 +135,7 @@ describe Gitlab::Email::Receiver, lib: true do ...@@ -132,7 +135,7 @@ describe Gitlab::Email::Receiver, lib: true do
note = noteable.notes.last note = noteable.notes.last
expect(note.note).to include("![image](uploads/image.png)") expect(note.note).to include(markdown)
end end
end end
end end
require 'spec_helper'
describe Ci::Build, models: true do
let(:build) { create(:ci_build) }
let(:test_trace) { 'This is a test' }
describe '#trace' do
it 'obfuscates project runners token' do
allow(build).to receive(:raw_trace).and_return("Test: #{build.project.runners_token}")
expect(build.trace).to eq("Test: xxxxxx")
end
it 'empty project runners token' do
allow(build).to receive(:raw_trace).and_return(test_trace)
# runners_token can't normally be set to nil
allow(build.project).to receive(:runners_token).and_return(nil)
expect(build.trace).to eq(test_trace)
end
end
end
require 'spec_helper'
describe BuildsEmailService do
let(:build) { create(:ci_build) }
let(:data) { Gitlab::BuildDataBuilder.build(build) }
let(:service) { BuildsEmailService.new }
describe :execute do
it "sends email" do
service.recipients = 'test@gitlab.com'
data[:build_status] = 'failed'
expect(BuildEmailWorker).to receive(:perform_async)
service.execute(data)
end
it "does not sends email with failed build and allowed_failure on" do
data[:build_status] = 'failed'
data[:build_allow_failure] = true
expect(BuildEmailWorker).not_to receive(:perform_async)
service.execute(data)
end
end
end
...@@ -353,6 +353,20 @@ describe API::API, api: true do ...@@ -353,6 +353,20 @@ describe API::API, api: true do
end end
end end
describe "POST /projects/:id/uploads" do
before { project }
it "uploads the file and returns its info" do
post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")
expect(response.status).to be(201)
expect(json_response['alt']).to eq("dk")
expect(json_response['url']).to start_with("/uploads/")
expect(json_response['url']).to end_with("/dk.png")
expect(json_response['is_image']).to eq(true)
end
end
describe 'GET /projects/:id' do describe 'GET /projects/:id' do
before { project } before { project }
before { project_member } before { project_member }
......
...@@ -33,12 +33,12 @@ describe Projects::DownloadService, services: true do ...@@ -33,12 +33,12 @@ describe Projects::DownloadService, services: true do
@link_to_file = download_file(@project, url) @link_to_file = download_file(@project, url)
end end
it { expect(@link_to_file).to have_key('alt') } it { expect(@link_to_file).to have_key(:alt) }
it { expect(@link_to_file).to have_key('url') } it { expect(@link_to_file).to have_key(:url) }
it { expect(@link_to_file).to have_key('is_image') } it { expect(@link_to_file).to have_key(:is_image) }
it { expect(@link_to_file['is_image']).to be true } it { expect(@link_to_file[:is_image]).to be true }
it { expect(@link_to_file['url']).to match('rails_sample.jpg') } it { expect(@link_to_file[:url]).to match('rails_sample.jpg') }
it { expect(@link_to_file['alt']).to eq('rails_sample') } it { expect(@link_to_file[:alt]).to eq('rails_sample') }
end end
context 'a txt file' do context 'a txt file' do
...@@ -47,12 +47,12 @@ describe Projects::DownloadService, services: true do ...@@ -47,12 +47,12 @@ describe Projects::DownloadService, services: true do
@link_to_file = download_file(@project, url) @link_to_file = download_file(@project, url)
end end
it { expect(@link_to_file).to have_key('alt') } it { expect(@link_to_file).to have_key(:alt) }
it { expect(@link_to_file).to have_key('url') } it { expect(@link_to_file).to have_key(:url) }
it { expect(@link_to_file).to have_key('is_image') } it { expect(@link_to_file).to have_key(:is_image) }
it { expect(@link_to_file['is_image']).to be false } it { expect(@link_to_file[:is_image]).to be false }
it { expect(@link_to_file['url']).to match('doc_sample.txt') } it { expect(@link_to_file[:url]).to match('doc_sample.txt') }
it { expect(@link_to_file['alt']).to eq('doc_sample.txt') } it { expect(@link_to_file[:alt]).to eq('doc_sample.txt') }
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment