From 20d4ca4cc3599b4335b73fd7c3bb0354efe397b4 Mon Sep 17 00:00:00 2001
From: Robert Schilling <rschilling@student.tugraz.at>
Date: Wed, 6 Apr 2016 13:59:50 +0200
Subject: [PATCH 1/3] API: Ability to retrieve a single tag

---
 doc/api/tags.md                | 46 +++++++++++++++++++++++++++++++++-
 lib/api/tags.rb                | 14 +++++++++++
 spec/requests/api/tags_spec.rb | 17 +++++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/doc/api/tags.md b/doc/api/tags.md
index 17d12e9cc62..d428ca0ef5c 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -38,6 +38,50 @@ Parameters:
 ]
 ```
 
+## Get a single repository tag
+
+Get a specific repository tag determined by its name. It returns 200 together
+with the tag information if the tag exists. It returns 404 if the tag does not
+exist.
+
+```
+GET /projects/:id/repository/tags/:tag_name
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `tag_name` | string | yes | The name of the tag |
+
+```bash
+curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/repository/tags/v1.0.0
+```
+
+Example Response:
+
+```json
+{
+  "name": "v5.0.0",
+  "message": null,
+  "commit": {
+    "id": "60a8ff033665e1207714d6670fcd7b65304ec02f",
+    "message": "v5.0.0\n",
+    "parent_ids": [
+      "f61c062ff8bcbdb00e0a1b3317a91aed6ceee06b"
+    ],
+    "authored_date": "2015-02-01T21:56:31.000+01:00",
+    "author_name": "Arthur Verschaeve",
+    "author_email": "contact@arthurverschaeve.be",
+    "committed_date": "2015-02-01T21:56:31.000+01:00",
+    "committer_name": "Arthur Verschaeve",
+    "committer_email": "contact@arthurverschaeve.be"
+  },
+  "release": null
+}
+```
+
 ## Create a new tag
 
 Creates a new tag in the repository that points to the supplied ref.
@@ -148,4 +192,4 @@ Parameters:
   "tag_name": "1.0.0",
   "description": "Amazing release. Wow"
 }
-```
\ No newline at end of file
+```
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 2d8a9e51bb9..731a68082ba 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -16,6 +16,20 @@ module API
                 with: Entities::RepoTag, project: user_project
       end
 
+      # Get a single repository tag
+      #
+      # Parameters:
+      #   id (required) - The ID of a project
+      #   tag_name (required) - The name of the tag
+      # Example Request:
+      #   GET /projects/:id/repository/tags/:tag_name
+      get ":id/repository/tags/:tag_name", requirements: { tag_name: /.*/ } do
+        tag = user_project.repository.find_tag(params[:tag_name])
+        not_found!('Tag') unless tag
+
+        present tag,  with: Entities::RepoTag, project: user_project
+      end
+
       # Create tag
       #
       # Parameters:
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index a15be07ed57..acbd9c3e332 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -40,6 +40,23 @@ describe API::API, api: true  do
     end
   end
 
+  describe "GET /projects/:id/repository/tags/:tag_name" do
+    let(:tag_name) { project.repository.tag_names.sort.reverse.first }
+
+    it 'should return a specific tag' do
+      get api("/projects/#{project.id}/repository/tags/#{tag_name}", user)
+
+      expect(response.status).to eq(200)
+      expect(json_response['name']).to eq(tag_name)
+    end
+
+    it 'should return 404 for an invalid tag name' do
+      get api("/projects/#{project.id}/repository/tags/foobar", user)
+
+      expect(response.status).to eq(404)
+    end
+  end
+
   describe 'POST /projects/:id/repository/tags' do
     context 'lightweight tags' do
       it 'should create a new tag' do
-- 
GitLab


From f81352f531b22d02b1b80cfbd6daed809ea8cf5d Mon Sep 17 00:00:00 2001
From: Robert Schilling <rschilling@student.tugraz.at>
Date: Tue, 12 Apr 2016 12:50:21 +0200
Subject: [PATCH 2/3] Fix minor styling issues from code review

---
 doc/api/tags.md                | 4 ++--
 lib/api/tags.rb                | 6 +++---
 spec/requests/api/tags_spec.rb | 6 +++---
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/doc/api/tags.md b/doc/api/tags.md
index d428ca0ef5c..ac9fac92f4c 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -40,8 +40,8 @@ Parameters:
 
 ## Get a single repository tag
 
-Get a specific repository tag determined by its name. It returns 200 together
-with the tag information if the tag exists. It returns 404 if the tag does not
+Get a specific repository tag determined by its name. It returns `200` together
+with the tag information if the tag exists. It returns `404` if the tag does not
 exist.
 
 ```
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 731a68082ba..d1a10479e44 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -19,15 +19,15 @@ module API
       # Get a single repository tag
       #
       # Parameters:
-      #   id (required) - The ID of a project
+      #   id (required)       - The ID of a project
       #   tag_name (required) - The name of the tag
       # Example Request:
       #   GET /projects/:id/repository/tags/:tag_name
-      get ":id/repository/tags/:tag_name", requirements: { tag_name: /.*/ } do
+      get ":id/repository/tags/:tag_name", requirements: { tag_name: /.+/ } do
         tag = user_project.repository.find_tag(params[:tag_name])
         not_found!('Tag') unless tag
 
-        present tag,  with: Entities::RepoTag, project: user_project
+        present tag, with: Entities::RepoTag, project: user_project
       end
 
       # Create tag
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index acbd9c3e332..9f9c3b1cf4c 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -40,17 +40,17 @@ describe API::API, api: true  do
     end
   end
 
-  describe "GET /projects/:id/repository/tags/:tag_name" do
+  describe 'GET /projects/:id/repository/tags/:tag_name' do
     let(:tag_name) { project.repository.tag_names.sort.reverse.first }
 
-    it 'should return a specific tag' do
+    it 'returns a specific tag' do
       get api("/projects/#{project.id}/repository/tags/#{tag_name}", user)
 
       expect(response.status).to eq(200)
       expect(json_response['name']).to eq(tag_name)
     end
 
-    it 'should return 404 for an invalid tag name' do
+    it 'returns 404 for an invalid tag name' do
       get api("/projects/#{project.id}/repository/tags/foobar", user)
 
       expect(response.status).to eq(404)
-- 
GitLab


From 08a217cfcfc2e2387c6d4070ed8b0e121f47f50c Mon Sep 17 00:00:00 2001
From: Robert Schilling <rschilling@student.tugraz.at>
Date: Tue, 12 Apr 2016 15:28:09 +0200
Subject: [PATCH 3/3] Add changelog entry

---
 CHANGELOG | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG b/CHANGELOG
index c08b148c3ac..85539b1a12a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,6 +28,7 @@ v 8.7.0 (unreleased)
   - Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.)
   - Gracefully handle notes on deleted commits in merge requests (Stan Hu)
   - Fix creation of merge requests for orphaned branches (Stan Hu)
+  - API: Ability to retrieve a single tag (Robert Schilling)
   - Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla)
   - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea)
   - Fix admin/projects when using visibility levels on search (PotHix)
-- 
GitLab