Commit b3a0fe04 authored by Alex Pooley's avatar Alex Pooley

Add snippet repo URLs to REST and GraphQL APIs

Snippet repositories will be phased in. Currently endpoint URLs are
dependent on the snippet itself being attached to a repository, and the
version_snippet feature flag setting.
parent 3a166309
......@@ -65,6 +65,14 @@ module Types
calls_gitaly: true,
null: false
field :ssh_url_to_repo, type: GraphQL::STRING_TYPE,
description: 'SSH URL to the snippet repository',
null: true
field :http_url_to_repo, type: GraphQL::STRING_TYPE,
description: 'HTTP URL to the snippet repository',
null: true
markdown_field :description_html, null: true, method: :description
end
end
......@@ -312,6 +312,10 @@ class Snippet < ApplicationRecord
Digest::SHA256.hexdigest("#{title}#{description}#{created_at}#{updated_at}")
end
def versioned_enabled_for?(user)
repository_exists? && ::Feature.enabled?(:version_snippets, user)
end
class << self
# Searches for snippets with a matching title, description or file name.
#
......
......@@ -11,6 +11,14 @@ class SnippetPresenter < Gitlab::View::Presenter::Delegated
Gitlab::UrlBuilder.build(snippet, raw: true)
end
def ssh_url_to_repo
snippet.ssh_url_to_repo if snippet.versioned_enabled_for?(current_user)
end
def http_url_to_repo
snippet.http_url_to_repo if snippet.versioned_enabled_for?(current_user)
end
def can_read_snippet?
can_access_resource?("read")
end
......
......@@ -7355,6 +7355,11 @@ type Snippet implements Noteable {
"""
fileName: String
"""
HTTP URL to the snippet repository
"""
httpUrlToRepo: String
"""
Id of the snippet
"""
......@@ -7395,6 +7400,11 @@ type Snippet implements Noteable {
"""
rawUrl: String!
"""
SSH URL to the snippet repository
"""
sshUrlToRepo: String
"""
Title of the snippet
"""
......
......@@ -22213,6 +22213,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "httpUrlToRepo",
"description": "HTTP URL to the snippet repository",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "Id of the snippet",
......@@ -22320,6 +22334,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "sshUrlToRepo",
"description": "SSH URL to the snippet repository",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "title",
"description": "Title of the snippet",
......
......@@ -1161,9 +1161,11 @@ Represents a snippet entry
| `description` | String | Description of the snippet |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `fileName` | String | File Name of the snippet |
| `httpUrlToRepo` | String | HTTP URL to the snippet repository |
| `id` | ID! | Id of the snippet |
| `project` | Project | The project the snippet is associated with |
| `rawUrl` | String! | Raw URL of the snippet |
| `sshUrlToRepo` | String | SSH URL to the snippet repository |
| `title` | String! | Title of the snippet |
| `updatedAt` | Time! | Timestamp this snippet was updated |
| `userPermissions` | SnippetPermissions! | Permissions for the current user on the resource |
......
......@@ -10,6 +10,7 @@ module API
expose :web_url do |snippet|
Gitlab::UrlBuilder.build(snippet)
end
expose :ssh_url_to_repo, :http_url_to_repo, if: ->(snippet) { snippet.versioned_enabled_for?(options[:current_user]) }
end
end
end
......@@ -3,12 +3,15 @@
require 'spec_helper'
describe GitlabSchema.types['Snippet'] do
let_it_be(:user) { create(:user) }
it 'has the correct fields' do
expected_fields = [:id, :title, :project, :author,
:file_name, :description,
:visibility_level, :created_at, :updated_at,
:web_url, :raw_url, :notes, :discussions,
:user_permissions, :description_html, :blob]
:web_url, :raw_url, :ssh_url_to_repo, :http_url_to_repo,
:notes, :discussions, :user_permissions,
:description_html, :blob]
expect(described_class).to have_graphql_fields(*expected_fields)
end
......@@ -17,8 +20,55 @@ describe GitlabSchema.types['Snippet'] do
it { expect(described_class).to require_graphql_authorizations(:read_snippet) }
end
shared_examples 'response without repository URLs' do
it 'does not respond with repository URLs' do
expect(response['sshUrlToRepo']).to be_nil
expect(response['httpUrlToRepo']).to be_nil
end
end
describe 'Repository URLs' do
let(:query) do
%(
{
snippets {
nodes {
sshUrlToRepo
httpUrlToRepo
}
}
}
)
end
let(:response) { subject.dig('data', 'snippets', 'nodes')[0] }
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
context 'when snippet has repository' do
let!(:snippet) { create(:personal_snippet, :repository, :public, author: user) }
it 'responds with repository URLs' do
expect(response['sshUrlToRepo']).to eq(snippet.ssh_url_to_repo)
expect(response['httpUrlToRepo']).to eq(snippet.http_url_to_repo)
end
context 'when version_snippets feature is disabled' do
before do
stub_feature_flags(version_snippets: false)
end
it_behaves_like 'response without repository URLs'
end
end
context 'when snippet does not have a repository' do
let!(:snippet) { create(:personal_snippet, :public, author: user) }
it_behaves_like 'response without repository URLs'
end
end
describe '#blob' do
let_it_be(:user) { create(:user) }
let(:query_blob) { subject.dig('data', 'snippets', 'edges')[0]['node']['blob'] }
let(:query) do
%(
......
......@@ -713,4 +713,32 @@ describe Snippet do
it { is_expected.to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "#{snippet.project.full_path}/snippets/#{snippet.id}.git") }
end
end
describe '#versioned_enabled_for?' do
let_it_be(:user) { create(:user) }
subject { snippet.versioned_enabled_for?(user) }
context 'with repository and version_snippets enabled' do
let!(:snippet) { create(:personal_snippet, :repository, author: user) }
it { is_expected.to be_truthy }
end
context 'without repository' do
let!(:snippet) { create(:personal_snippet, author: user) }
it { is_expected.to be_falsy }
end
context 'without version_snippets feature disabled' do
let!(:snippet) { create(:personal_snippet, :repository, author: user) }
before do
stub_feature_flags(version_snippets: false)
end
it { is_expected.to be_falsy }
end
end
end
......@@ -85,7 +85,7 @@ describe API::ProjectSnippets do
describe 'GET /projects/:project_id/snippets/:id' do
let(:user) { create(:user) }
let(:snippet) { create(:project_snippet, :public, project: project) }
let(:snippet) { create(:project_snippet, :public, :repository, project: project) }
it 'returns snippet json' do
get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
......@@ -95,6 +95,18 @@ describe API::ProjectSnippets do
expect(json_response['title']).to eq(snippet.title)
expect(json_response['description']).to eq(snippet.description)
expect(json_response['file_name']).to eq(snippet.file_name)
expect(json_response['ssh_url_to_repo']).to eq(snippet.ssh_url_to_repo)
expect(json_response['http_url_to_repo']).to eq(snippet.http_url_to_repo)
end
context 'when feature flag :version_snippets is disabled' do
before do
stub_feature_flags(version_snippets: false)
get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
end
it_behaves_like 'snippet response without repository URLs'
end
it 'returns 404 for invalid snippet id' do
......
......@@ -139,8 +139,8 @@ describe API::Snippets do
describe 'GET /snippets/:id' do
let_it_be(:admin) { create(:user, :admin) }
let_it_be(:author) { create(:user) }
let_it_be(:private_snippet) { create(:personal_snippet, :private, author: author) }
let_it_be(:internal_snippet) { create(:personal_snippet, :internal, author: author) }
let_it_be(:private_snippet) { create(:personal_snippet, :repository, :private, author: author) }
let_it_be(:internal_snippet) { create(:personal_snippet, :repository, :internal, author: author) }
it 'requires authentication' do
get api("/snippets/#{private_snippet.id}", nil)
......@@ -157,6 +157,18 @@ describe API::Snippets do
expect(json_response['description']).to eq(private_snippet.description)
expect(json_response['file_name']).to eq(private_snippet.file_name)
expect(json_response['visibility']).to eq(private_snippet.visibility)
expect(json_response['ssh_url_to_repo']).to eq(private_snippet.ssh_url_to_repo)
expect(json_response['http_url_to_repo']).to eq(private_snippet.http_url_to_repo)
end
context 'when feature flag :version_snippets is disabled' do
before do
stub_feature_flags(version_snippets: false)
get api("/snippets/#{private_snippet.id}", author)
end
it_behaves_like 'snippet response without repository URLs'
end
it 'shows private snippets to an admin' do
......
......@@ -41,3 +41,10 @@ RSpec.shared_examples 'update with repository actions' do
end
end
end
RSpec.shared_examples 'snippet response without repository URLs' do
it 'skip inclusion of repository URLs' do
expect(json_response).not_to have_key('ssh_url_to_repo')
expect(json_response).not_to have_key('http_url_to_repo')
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