From ac07cb70c006226d62039918bf365f0e6d7a6f7d Mon Sep 17 00:00:00 2001 From: "TJ (Thomas) Biddle" Date: Fri, 14 Jun 2013 13:12:09 -0700 Subject: [PATCH 1/5] Add support for creation and removal of branches and tags. This commit takes advantage of the commit I added to gitlab-shell. Added API endpoints for POST (Create) and DELETE (Delete, duh.) of branch and tag resources. It takes advantage using Sidekiq to throw the actions into a background process as Gitlab does for many other actions; however Gitlab is setup to cache the branches and tags - So we need to expire the cache. There's a nice existing expire_cache method in the repository model to do this. We can run into an issue with race conditions in which the expire_cache would be called *before* the branch was created, rendering it moot - But (Would need to double check this) I believe many other actions expire the cache anyhow - So on any active project it would be updated soon anyhow. I originally thought about passing along the repository object into Sidekiq but this caused Redis to lock up entirely and until I flushed all keys it wouldn't run any sidekiq jobs, even if I cleared them. This is a very useful feature as personally I integrate with Gitlab and would like to create tags and branches upon different actions when deploying to various environments (Deploy to staging - Create a release candidate branch, deploy to prod - Create a tag) --- app/models/repository.rb | 51 +++++++++++++++++++++++++++ lib/api/helpers.rb | 4 +++ lib/api/repositories.rb | 69 +++++++++++++++++++++++++++++++++++++ lib/gitlab/backend/shell.rb | 65 ++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) diff --git a/app/models/repository.rb b/app/models/repository.rb index aeec48ee5cc..6f224a3be8a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -17,6 +17,56 @@ class Repository raw_repository.empty? end + def create_branch(branch_name, ref) + GitlabShellWorker.perform_async( + :create_branch, + path_with_namespace, + branch_name, + ref + ) + # Yes - Possible race condition that the new branch may not be created in time, but + # on any active repo the cache will be cleared enough and in all testing I have yet + # to have it not create the branch first. + expire_cache + end + + def rm_branch(branch_name) + GitlabShellWorker.perform_async( + :rm_branch, + path_with_namespace, + branch_name + ) + # Yes - Possible race condition that the new branch may not be created in time, but + # on any active repo the cache will be cleared enough and in all testing I have yet + # to have it not create the branch first. + expire_cache + end + + def create_tag(tag_name, ref) + GitlabShellWorker.perform_async( + :create_tag, + path_with_namespace, + tag_name, + ref + ) + # Yes - Possible race condition that the new branch may not be created in time, but + # on any active repo the cache will be cleared enough and in all testing I have yet + # to have it not create the branch first. + expire_cache + end + + def rm_tag(branch_name) + GitlabShellWorker.perform_async( + :rm_tag, + path_with_namespace, + branch_name + ) + # Yes - Possible race condition that the new branch may not be created in time, but + # on any active repo the cache will be cleared enough and in all testing I have yet + # to have it not create the branch first. + expire_cache + end + def commit(id = nil) return nil unless raw_repository commit = Gitlab::Git::Commit.find(raw_repository, id) @@ -151,3 +201,4 @@ class Repository super end end + diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 4f189f35196..462f3d12498 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -110,6 +110,10 @@ module API render_api_error!('401 Unauthorized', 401) end + def resource_exists! + render_api_error!('Resource Already Exists', 409) + end + def not_allowed! render_api_error!('Method Not Allowed', 405) end diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index fef32d3a2fe..65f521113c5 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -23,6 +23,41 @@ module API present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject, project: user_project end + + # Create a branch + # + # Parameters: + # id (required) - The ID of a project + # branch (required) - The name of the branch + # ref (required) - SHA1 ref of branch. + # Example Request: + # POST /projects/:id/repository/branches/:branch/:ref + post ":id/repository/branches/:branch/:ref" do + @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + resource_exists! if @branch + + user_project.repository.create_branch(params[:branch], params[:ref]) + @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + + # Return 200 OK. Since the branch is created in a background process + # we can't yet return it. + end + + # Deletes a branch + # + # Parameters: + # id (required) - The ID of a project + # branch (required) - The name of the branch + # Example Request: + # DELETE /projects/:id/repository/branches/:branch + delete ":id/repository/branches/:branch" do + @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + not_found! unless @branch + + user_project.repository.rm_branch(params[:branch]) + # Returns 200 OK + end + # Get a single branch # # Parameters: @@ -84,6 +119,40 @@ module API present user_project.repo.tags.sort_by(&:name).reverse, with: Entities::RepoObject end + # Create a tag + # + # Parameters: + # id (required) - The ID of a project + # tag (required) - The name of the tag + # ref (required) - SHA1 ref of tag. + # Example Request: + # POST /projects/:id/repository/tags/:tag/:ref + post ":id/repository/tags/:tag/:ref" do + @tag = user_project.repo.tags.find { |item| item.name == params[:tag] } + resource_exists! if @tag + + user_project.repository.create_tag(params[:tag], params[:ref]) + @tag = user_project.repo.tags.find { |item| item.name == params[:tag] } + + # Return 200 OK. Since the tag is created in a background process + # we can't yet return it. + end + + # Deletes a tag + # + # Parameters: + # id (required) - The ID of a project + # tag (required) - The name of the tag + # Example Request: + # DELETE /projects/:id/repository/tags/:tag + delete ":id/repository/tags/:tag" do + @tag = user_project.repo.tags.find { |item| item.name == params[:tag] } + not_found! unless @tag + + user_project.repository.rm_tag(params[:tag]) + # Returns 200 OK + end + # Get a project repository commits # # Parameters: diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index c819ce56ac9..0f9a69ee8e9 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -2,6 +2,70 @@ module Gitlab class Shell class AccessDenied < StandardError; end + # Create a new branch in a repository. + # + # project_name - project path with namespace + # branch_name - the branch name to create + # ref - SHA1 to create the branch from + # + # Ex. + # create_branch("gitlab/gitlab-ci", "feature_1", "02a7b1270bbe35a14b3c7701bcbcff39abc646da") + # + def create_branch(project_name, branch_name, ref) + system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", + "create-branch", + "#{project_name}.git", + branch_name, + ref + end + + # Removes a branch in a repository. + # + # project_name - project path with namespace + # branch_name - the branch name to remove + # + # Ex. + # rm_branch("gitlab/gitlab-ci", "feature_1") + # + def rm_branch(project_name, branch_name) + system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", + "rm-branch", + "#{project_name}.git", + branch_name + end + + # Create a new tag in a repository. + # + # project_name - project path with namespace + # tag_name - the tag name to create + # ref - SHA1 to create the branch from + # + # Ex. + # create_tag("gitlab/gitlab-ci", "v.1.0", "02a7b1270bbe35a14b3c7701bcbcff39abc646da") + # + def create_tag(project_name, tag_name, ref) + system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", + "create-tag", + "#{project_name}.git", + tag_name, + ref + end + + # Removes a tag in a repository. + # + # project_name - project path with namespace + # tag_name - the tag name to create + # + # Ex. + # rm_tag("gitlab/gitlab-ci", "v.1.0") + # + def rm_tag(project_name, tag_name) + system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", + "rm-tag", + "#{project_name}.git", + tag_name + end + # Init new repository # # name - project path with namespace @@ -217,3 +281,4 @@ module Gitlab end end end + -- GitLab From fdef12295afe71b9f15bb6c784bd879456132553 Mon Sep 17 00:00:00 2001 From: TJ Biddle Date: Mon, 8 Jul 2013 17:52:32 -0700 Subject: [PATCH 2/5] Updating API documentation to include branch/tag creation/deletion. --- doc/api/repositories.md | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index cb0626972e5..161ca7173eb 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -39,6 +39,38 @@ Parameters: ] ``` +## Create a branch + +Create a new branch. + +``` +POST /projects/:id/repository/branches/:branch/:ref +``` + +Parameters: ++ `id` (required) - The ID of the project ++ `:branch` (required) - The name of the branch being created ++ `:ref` (required) - Reference branch is built from (Branch/Tag/SHA1/etc) + +``` +200 OK +``` + +## Delete a branch + +Delete a new branch. + +``` +DELETE /projects/:id/repository/branches/:branch +``` + +Parameters: ++ `id` (required) - The ID of the project ++ `:branch` (required) - The name of the branch being deleted + +``` +200 OK +``` ## Get single repository branch @@ -80,6 +112,39 @@ Parameters: } ``` +## Create a tag + +Create a new tag. + +``` +POST /projects/:id/repository/tags/:tag/:ref +``` + +Parameters: ++ `id` (required) - The ID of the project ++ `:tag` (required) - The name of the tag being created ++ `:ref` (required) - Reference tag is built from (Branch/Tag/SHA1/etc) + +``` +200 OK +``` + +## Delete a tag + +Delete a new tag. + +``` +DELETE /projects/:id/repository/tags/:tag +``` + +Parameters: ++ `id` (required) - The ID of the project ++ `:tag` (required) - The name of the tag being deleted + +``` +200 OK +``` + ## Protect repository branch -- GitLab From d418c3e7fa28144d33b931e47a2bbc5e023fba3c Mon Sep 17 00:00:00 2001 From: TJ Biddle Date: Mon, 22 Jul 2013 13:23:52 -0700 Subject: [PATCH 3/5] Ensuring create/delete branch/tag supports periods in the url. This fixes an issue where periods could not be in the API url (eg: /projects/1/repository/tags/v.1.0/HEAD) Also - The api methods now just return that the API call was received (Still cannot actually return branch information as that is done in a worker process). This change was made mainly due to the Ruby API wrapper expecting a JSON response; however it makes sense to return *something* rather than just an empty response. Documentation updated for this. --- doc/api/repositories.md | 24 ++++++++++++++++-------- lib/api/repositories.rb | 18 +++++++++++++----- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 161ca7173eb..0d4c72085a0 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -52,8 +52,10 @@ Parameters: + `:branch` (required) - The name of the branch being created + `:ref` (required) - Reference branch is built from (Branch/Tag/SHA1/etc) -``` -200 OK +```json +{ + "received": true +} ``` ## Delete a branch @@ -68,8 +70,10 @@ Parameters: + `id` (required) - The ID of the project + `:branch` (required) - The name of the branch being deleted -``` -200 OK +```json +{ + "received": true +} ``` ## Get single repository branch @@ -125,8 +129,10 @@ Parameters: + `:tag` (required) - The name of the tag being created + `:ref` (required) - Reference tag is built from (Branch/Tag/SHA1/etc) -``` -200 OK +```json +{ + "received": true +} ``` ## Delete a tag @@ -141,8 +147,10 @@ Parameters: + `id` (required) - The ID of the project + `:tag` (required) - The name of the tag being deleted -``` -200 OK +```json +{ + "received": true +} ``` diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 65f521113c5..5e1f70afefb 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -32,7 +32,9 @@ module API # ref (required) - SHA1 ref of branch. # Example Request: # POST /projects/:id/repository/branches/:branch/:ref - post ":id/repository/branches/:branch/:ref" do + post ":id/repository/branches/:branch/:ref", + :requirements => { :branch => /.*/, :ref => /.*/ } do + @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } resource_exists! if @branch @@ -40,7 +42,7 @@ module API @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } # Return 200 OK. Since the branch is created in a background process - # we can't yet return it. + present({ 'received' => true }) end # Deletes a branch @@ -50,12 +52,14 @@ module API # branch (required) - The name of the branch # Example Request: # DELETE /projects/:id/repository/branches/:branch - delete ":id/repository/branches/:branch" do + delete ":id/repository/branches/:branch", + :requirements => { :branch => /.*/ } do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } not_found! unless @branch user_project.repository.rm_branch(params[:branch]) # Returns 200 OK + present({ 'received' => true }) end # Get a single branch @@ -127,7 +131,8 @@ module API # ref (required) - SHA1 ref of tag. # Example Request: # POST /projects/:id/repository/tags/:tag/:ref - post ":id/repository/tags/:tag/:ref" do + post ":id/repository/tags/:tag/:ref", + :requirements => { :tag => /.*/, :ref => /.*/ } do @tag = user_project.repo.tags.find { |item| item.name == params[:tag] } resource_exists! if @tag @@ -136,6 +141,7 @@ module API # Return 200 OK. Since the tag is created in a background process # we can't yet return it. + present({ 'received' => true }) end # Deletes a tag @@ -145,12 +151,14 @@ module API # tag (required) - The name of the tag # Example Request: # DELETE /projects/:id/repository/tags/:tag - delete ":id/repository/tags/:tag" do + delete ":id/repository/tags/:tag", + :requirements => { :tag => /.*/ } do @tag = user_project.repo.tags.find { |item| item.name == params[:tag] } not_found! unless @tag user_project.repository.rm_tag(params[:tag]) # Returns 200 OK + present({ 'received' => true }) end # Get a project repository commits -- GitLab From 5fe88ea1a9d4656bcfbe8dedc3bc93cf6b7c8755 Mon Sep 17 00:00:00 2001 From: TJ Biddle Date: Wed, 7 Aug 2013 13:59:52 -0700 Subject: [PATCH 4/5] Adding tests, rebased from master, and updating previous code as it looks like something similar has been added in the meantime. --- app/models/repository.rb | 50 ----------------------- doc/api/repositories.md | 56 ++++++++++++++++++++++++-- lib/api/repositories.rb | 17 +++----- spec/requests/api/repositories_spec.rb | 44 ++++++++++++++++++++ 4 files changed, 102 insertions(+), 65 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 6f224a3be8a..0f262d2ecbb 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -17,56 +17,6 @@ class Repository raw_repository.empty? end - def create_branch(branch_name, ref) - GitlabShellWorker.perform_async( - :create_branch, - path_with_namespace, - branch_name, - ref - ) - # Yes - Possible race condition that the new branch may not be created in time, but - # on any active repo the cache will be cleared enough and in all testing I have yet - # to have it not create the branch first. - expire_cache - end - - def rm_branch(branch_name) - GitlabShellWorker.perform_async( - :rm_branch, - path_with_namespace, - branch_name - ) - # Yes - Possible race condition that the new branch may not be created in time, but - # on any active repo the cache will be cleared enough and in all testing I have yet - # to have it not create the branch first. - expire_cache - end - - def create_tag(tag_name, ref) - GitlabShellWorker.perform_async( - :create_tag, - path_with_namespace, - tag_name, - ref - ) - # Yes - Possible race condition that the new branch may not be created in time, but - # on any active repo the cache will be cleared enough and in all testing I have yet - # to have it not create the branch first. - expire_cache - end - - def rm_tag(branch_name) - GitlabShellWorker.perform_async( - :rm_tag, - path_with_namespace, - branch_name - ) - # Yes - Possible race condition that the new branch may not be created in time, but - # on any active repo the cache will be cleared enough and in all testing I have yet - # to have it not create the branch first. - expire_cache - end - def commit(id = nil) return nil unless raw_repository commit = Gitlab::Git::Commit.find(raw_repository, id) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 0d4c72085a0..d0499ee7fd6 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -54,7 +54,31 @@ Parameters: ```json { - "received": true + "name": "test_branch", + "commit": { + "id": "d67868df74c26c88b2cf1d25d91a269f237963e8", + "parents": [ + { + "id": "ccd7a20d618558b2ac17d49200500de01e6adce1" + }, + { + "id": "de60b9aa1c2c66f4cb7c76541e01a15ebdef0838" + } + ], + "tree": "90b63cf2244f93d0b3eef162dc05f8c94f3527ec", + "message": "Merge pull request #1249 from braddunbar/throttle\n\nPrevent false negatives for _.throttle tests.", + "author": { + "name": "Jeremy Ashkenas", + "email": "jashkenas@gmail.com" + }, + "committer": { + "name": "Jeremy Ashkenas", + "email": "jashkenas@gmail.com" + }, + "authored_date": "2013-08-07T15:35:30+00:00", + "committed_date": "2013-08-07T15:35:30+00:00" + }, + "protected": false } ``` @@ -72,7 +96,7 @@ Parameters: ```json { - "received": true + "success": true } ``` @@ -131,7 +155,31 @@ Parameters: ```json { - "received": true + "name": "v1.1", + "commit": { + "id": "d67868df74c26c88b2cf1d25d91a269f237963e8", + "parents": [ + { + "id": "ccd7a20d618558b2ac17d49200500de01e6adce1" + }, + { + "id": "de60b9aa1c2c66f4cb7c76541e01a15ebdef0838" + } + ], + "tree": "90b63cf2244f93d0b3eef162dc05f8c94f3527ec", + "message": "Merge pull request #1249 from braddunbar/throttle\n\nPrevent false negatives for _.throttle tests.", + "author": { + "name": "Jeremy Ashkenas", + "email": "jashkenas@gmail.com" + }, + "committer": { + "name": "Jeremy Ashkenas", + "email": "jashkenas@gmail.com" + }, + "authored_date": "2013-08-07T15:35:30+00:00", + "committed_date": "2013-08-07T15:35:30+00:00" + }, + "protected": false } ``` @@ -149,7 +197,7 @@ Parameters: ```json { - "received": true + "success": true } ``` diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 5e1f70afefb..1b42cdc9f66 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -38,11 +38,10 @@ module API @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } resource_exists! if @branch - user_project.repository.create_branch(params[:branch], params[:ref]) + user_project.repository.add_branch(params[:branch], params[:ref]) @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } - # Return 200 OK. Since the branch is created in a background process - present({ 'received' => true }) + present @branch, with: Entities::RepoObject, project: user_project end # Deletes a branch @@ -58,8 +57,7 @@ module API not_found! unless @branch user_project.repository.rm_branch(params[:branch]) - # Returns 200 OK - present({ 'received' => true }) + present({ 'success' => true }) end # Get a single branch @@ -136,12 +134,10 @@ module API @tag = user_project.repo.tags.find { |item| item.name == params[:tag] } resource_exists! if @tag - user_project.repository.create_tag(params[:tag], params[:ref]) + user_project.repository.add_tag(params[:tag], params[:ref]) @tag = user_project.repo.tags.find { |item| item.name == params[:tag] } - # Return 200 OK. Since the tag is created in a background process - # we can't yet return it. - present({ 'received' => true }) + present @tag, with: Entities::RepoObject, project: user_project end # Deletes a tag @@ -157,8 +153,7 @@ module API not_found! unless @tag user_project.repository.rm_tag(params[:tag]) - # Returns 200 OK - present({ 'received' => true }) + present({ 'success' => true }) end # Get a project repository commits diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index f15abdd3581..e4954effc5d 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -38,6 +38,50 @@ describe API::API do end end + describe "POST /projects/:id/repository/branches/:branch/:ref" do + it "should return that the request was received" do + post api("/projects/#{project.id}/repository/branches/new_branch/master", user) + response.status.should == 201 + end + + it "should return a 409 conflict if the resource already exists" do + post api("/projects/#{project.id}/repository/branches/new_design/master", user) + response.status.should == 409 + end + end + + describe "DELETE /projects/:id/repository/branches/:branch/" do + it "should return that the request was received" do + delete api("/projects/#{project.id}/repository/branches/master", user) + response.status.should == 200 + + json_response['success'].should == true + end + + it "should return a 404 not found if the resource already exists" do + delete api("/projects/#{project.id}/repository/branches/abranchthatdoesnotexist", user) + response.status.should == 404 + end + end + + describe "POST /projects/:id/repository/tags/:tag/:ref" do + it "should return that the request was received" do + post api("/projects/#{project.id}/repository/tags/v1.0/master", user) + response.status.should == 201 + end + it "should return a 409 conflict if the resource already exists" do + post api("/projects/#{project.id}/repository/tags/v0.9.4/master", user) + response.status.should == 409 + end + end + + describe "DELETE /projects/:id/repository/tags/:tag/" do + it "should return a 404 not found if the resource already exists" do + delete api("/projects/#{project.id}/repository/tags/atagthatdoesnotexist", user) + response.status.should == 404 + end + end + describe "PUT /projects/:id/repository/branches/:branch/protect" do it "should protect a single branch" do put api("/projects/#{project.id}/repository/branches/new_design/protect", user) -- GitLab From fb85cadfd8dabb54f3c21933a93b3054eb1d3913 Mon Sep 17 00:00:00 2001 From: TJ Biddle Date: Wed, 7 Aug 2013 14:06:07 -0700 Subject: [PATCH 5/5] Looks like these methods were added as well in a previous commit. --- lib/gitlab/backend/shell.rb | 64 ------------------------------------- 1 file changed, 64 deletions(-) diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 0f9a69ee8e9..114fa44c145 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -2,70 +2,6 @@ module Gitlab class Shell class AccessDenied < StandardError; end - # Create a new branch in a repository. - # - # project_name - project path with namespace - # branch_name - the branch name to create - # ref - SHA1 to create the branch from - # - # Ex. - # create_branch("gitlab/gitlab-ci", "feature_1", "02a7b1270bbe35a14b3c7701bcbcff39abc646da") - # - def create_branch(project_name, branch_name, ref) - system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", - "create-branch", - "#{project_name}.git", - branch_name, - ref - end - - # Removes a branch in a repository. - # - # project_name - project path with namespace - # branch_name - the branch name to remove - # - # Ex. - # rm_branch("gitlab/gitlab-ci", "feature_1") - # - def rm_branch(project_name, branch_name) - system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", - "rm-branch", - "#{project_name}.git", - branch_name - end - - # Create a new tag in a repository. - # - # project_name - project path with namespace - # tag_name - the tag name to create - # ref - SHA1 to create the branch from - # - # Ex. - # create_tag("gitlab/gitlab-ci", "v.1.0", "02a7b1270bbe35a14b3c7701bcbcff39abc646da") - # - def create_tag(project_name, tag_name, ref) - system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", - "create-tag", - "#{project_name}.git", - tag_name, - ref - end - - # Removes a tag in a repository. - # - # project_name - project path with namespace - # tag_name - the tag name to create - # - # Ex. - # rm_tag("gitlab/gitlab-ci", "v.1.0") - # - def rm_tag(project_name, tag_name) - system "#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects", - "rm-tag", - "#{project_name}.git", - tag_name - end - # Init new repository # # name - project path with namespace -- GitLab