18 Commits
v1.3 ... v1.8

6 changed files with 242 additions and 16 deletions

29
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,29 @@
stages:
- check
- release
build:
stage: check
image: registry.gitlab.com/wolutator/base-build-env:latest
tags:
- hottis
- linux
- docker
script:
- for I in *.py; do python -m py_compile $I; done
- for I in *.py; do python -m pycodestyle --max-line-length=120 $I; done
release:
stage: release
image: registry.gitlab.com/wolutator/base-build-env
tags:
- hottis
- linux
- docker
only:
- release
script:
- zip GitlabReleaseTool.zip gitlabreleaseuploader.py deleterelease.py
- python gitlabreleaseuploader.py -p $PRIVATE_TOKEN -i $CI_PROJECT_ID -u $CI_PROJECT_URL
-f GitlabReleaseTool.zip -F info.json -T $CI_COMMIT_REF_NAME

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Wolfgang Hottgenroth
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

56
deleterelease.py Normal file
View File

@ -0,0 +1,56 @@
#!/usr/bin/python
import requests
import json
import argparse
import sys
parser = argparse.ArgumentParser(description='Gitlab Release Deleter')
parser.add_argument('--privateToken', '-p',
help='Private token to access Gitlab', required=True)
parser.add_argument('--projectId', '-i',
help='ProjectID of the related project', required=True)
parser.add_argument('--releaseTag', '-t',
help='Tag of the release in the repo',
required=True,
default='')
parser.add_argument('--instanceUrl', '-I',
help='URL of your gitlab instance', required=False,
default='https://gitlab.com')
parser.add_argument('--verbose', '-v',
help='verbose output',
required=False,
action='store_true',
default=False)
parser.add_argument('--caBundle', '-B',
help='File with the CA certificates to trust', required=False,
default='/etc/ssl/certs/ca-certificates.crt')
args = parser.parse_args()
privateToken = args.privateToken
projectId = args.projectId
releaseTag = args.releaseTag
instanceUrl = args.instanceUrl
verbose = args.verbose
caBundle = args.caBundle
# --- delete release
deleteReleaseUrl = "%s/api/v4/projects/%s/releases/%s" % (instanceUrl, projectId, releaseTag)
headers = {"PRIVATE-TOKEN": privateToken, "Content-Type": "application/json"}
if verbose:
print("URL: %s" % deleteReleaseUrl)
deleteReleaseResult = requests.delete(deleteReleaseUrl, headers=headers, verify=caBundle)
if deleteReleaseResult.status_code != 200:
print(deleteReleaseResult)
print(deleteReleaseResult.text)
raise Exception('Unable to delete release')
if verbose:
print(deleteReleaseResult)
print(deleteReleaseResult.text)
print('Release successfully delete')

32
gitlabreleaseuploader.py Normal file → Executable file
View File

@ -1,3 +1,5 @@
#!/usr/bin/python
import requests import requests
import json import json
import argparse import argparse
@ -40,6 +42,9 @@ parser.add_argument('--releaseInfoFile', '-F',
parser.add_argument('--instanceUrl', '-I', parser.add_argument('--instanceUrl', '-I',
help='URL of your gitlab instance', required=False, help='URL of your gitlab instance', required=False,
default='https://gitlab.com') default='https://gitlab.com')
parser.add_argument('--caBundle', '-B',
help='File with the CA certificates to trust', required=False,
default='/etc/ssl/certs/ca-certificates.crt')
parser.add_argument('--verbose', '-v', parser.add_argument('--verbose', '-v',
help='verbose output', help='verbose output',
required=False, required=False,
@ -58,6 +63,7 @@ releaseDescription = args.description
instanceUrl = args.instanceUrl instanceUrl = args.instanceUrl
createReleaseTag = args.createReleaseTag createReleaseTag = args.createReleaseTag
releaseInfoFilename = args.releaseInfoFile releaseInfoFilename = args.releaseInfoFile
caBundle = args.caBundle
verbose = args.verbose verbose = args.verbose
releaseInfo = {} releaseInfo = {}
@ -72,7 +78,8 @@ if (releaseInfoFilename):
if 'releaseTagTarget' in releaseInfo: if 'releaseTagTarget' in releaseInfo:
releaseTagTarget = releaseInfo['releaseTagTarget'] releaseTagTarget = releaseInfo['releaseTagTarget']
if 'createReleaseTag' in releaseInfo: if 'createReleaseTag' in releaseInfo:
createReleaseTag = (releaseInfo['createReleaseTag'] in ('true', 'True')) createReleaseTag = (releaseInfo['createReleaseTag'] in
('true', 'True'))
if 'description' in releaseInfo: if 'description' in releaseInfo:
releaseDescription = releaseInfo['description'] releaseDescription = releaseInfo['description']
@ -91,7 +98,7 @@ uploadUrl = "%s/api/v4/projects/%s/uploads" % (instanceUrl, projectId)
headers = {"PRIVATE-TOKEN": privateToken} headers = {"PRIVATE-TOKEN": privateToken}
files = {"file": open(fileToUpload, 'rb')} files = {"file": open(fileToUpload, 'rb')}
uploadResult = requests.post(uploadUrl, files=files, headers=headers) uploadResult = requests.post(uploadUrl, files=files, headers=headers, verify=caBundle)
if uploadResult.status_code != 201: if uploadResult.status_code != 201:
print(uploadResult) print(uploadResult)
@ -107,14 +114,10 @@ uploadResultJson = json.loads(uploadResult.text)
# --- create release tag # --- create release tag
if createReleaseTag: if createReleaseTag:
createReleaseTagUrl = "%s/api/v4//projects/%s/repository/tags" % (instanceUrl, projectId) createReleaseTagUrl = ("%s/api/v4//projects/%s/repository/tags" %
headers = {"PRIVATE-TOKEN": privateToken, "Content-Type": "application/json"} (instanceUrl, projectId))
headers = {"PRIVATE-TOKEN": privateToken,
# id (required) - The ID or URL-encoded path of the project owned by the authenticated user "Content-Type": "application/json"}
# tag_name (required) - The name of a tag
# ref (required) - Create tag using commit SHA, another tag name, or branch name.
# message (optional) - Creates annotated tag.
# release_description (optional) - Add release notes to the git tag and store it in the GitLab database.
payloadCreateReleaseTag = { payloadCreateReleaseTag = {
"tag_name": releaseTag, "tag_name": releaseTag,
@ -123,8 +126,10 @@ if createReleaseTag:
"message": "Tag for release %s" % releaseName "message": "Tag for release %s" % releaseName
} }
createReleaseTagResult = requests.post(createReleaseTagUrl, headers=headers, createReleaseTagResult = requests.post(createReleaseTagUrl,
data=json.dumps(payloadCreateReleaseTag)) headers=headers,
data=json.dumps(payloadCreateReleaseTag),
verify=caBundle)
if createReleaseTagResult.status_code != 201: if createReleaseTagResult.status_code != 201:
print(createReleaseTagResult) print(createReleaseTagResult)
@ -157,7 +162,8 @@ payloadCreateRelease = {
} }
createReleaseResult = requests.post(createReleaseUrl, headers=headers, createReleaseResult = requests.post(createReleaseUrl, headers=headers,
data=json.dumps(payloadCreateRelease)) data=json.dumps(payloadCreateRelease),
verify=caBundle)
if createReleaseResult.status_code != 201: if createReleaseResult.status_code != 201:
print(createReleaseResult) print(createReleaseResult)

View File

@ -1,7 +1,7 @@
{ {
"releaseTag": "v1.3", "releaseTag": "v1.8",
"createReleaseTag": "true", "createReleaseTag": "true",
"releaseName": "Fourth release of the uploader", "releaseName": "CA Bundle",
"description": "Disable forgotten debug output" "description": "Option to provide CA bundle file for ssl verification"
} }

114
readme.md Normal file
View File

@ -0,0 +1,114 @@
# Release Uploader for Gitlab
Creating releases on Gitlab seems to work only via the REST API.
This Python script handles the upload of a release file, the creation of
the required release tag in the repository and the creation of the actual
release referring to both the tag and the file.
It supports commandline options and an input file, adjusted to be used in
Gitlab CI scripts.
## Usage
wn@tron:~/workspace-python/gitlabreleaseuploader [master ≡]$ ./gitlabreleaseuploader.py -h
usage: gitlabreleaseuploader.py [-h] --privateToken PRIVATETOKEN --projectId
PROJECTID --projectUrl PROJECTURL --file FILE
[--releaseName RELEASENAME]
[--releaseTag RELEASETAG]
[--releaseTagTarget RELEASETAGTARGET]
[--createReleaseTag]
[--description DESCRIPTION]
[--releaseInfoFile RELEASEINFOFILE]
[--caBundle FILE_WITH_CA_CERTIFICATES_TO_TRUST]
[--instanceUrl INSTANCEURL] [--verbose]
Gitlab Release Uploader
optional arguments:
-h, --help show this help message and exit
--privateToken PRIVATETOKEN, -p PRIVATETOKEN
Private token to access Gitlab
--projectId PROJECTID, -i PROJECTID
ProjectID of the related project
--projectUrl PROJECTURL, -u PROJECTURL
URL of the related project at Gitlab
--file FILE, -f FILE File to be released
--releaseName RELEASENAME, -n RELEASENAME
Name of the release
--releaseTag RELEASETAG, -t RELEASETAG
Tag of the release in the repo
--releaseTagTarget RELEASETAGTARGET, -T RELEASETAGTARGET
Commit or branch the tag should point to
--createReleaseTag, -c
Shall the release be created here
--description DESCRIPTION, -d DESCRIPTION
Description of the release
--releaseInfoFile RELEASEINFOFILE, -F RELEASEINFOFILE
File containing JSON object with release info (release
tag, create release tag, description
--instanceUrl INSTANCEURL, -I INSTANCEURL
URL of your gitlab instance
--caBundle FILE_WITH_CA_CERTIFICATES_TO_TRUST, -B FILE_WITH_CA_CERTIFICATES_TO_TRUST
--verbose, -v verbose output
wn@tron:~/workspace-python/gitlabreleaseuploader [master ≡]$
### Without release info file:
gitlabreleaseuploader.py -p PRIVATE_TOKEN -i PROJECT_ID -u PROJECT_URL
-f FILE_TO_BE_RELEASED -n RELEASE_NAME
-t RELEASE_TAG -T RELEASE_TAG_TARGET -c
-d RELEASE_DESCRIPTION -I INSTANCE_URL
### With release info file:
Release Info File:
{
"releaseTag": "v1.5",
"createReleaseTag": "true",
"releaseName": "Sixth release of the uploader",
"description": "Now with CI script and automatic release upload (hey, eat your own dogfood)"
}
Command:
gitlabreleaseuploader.py -p PRIVATE_TOKEN -i PROJECT_ID -u PROJECT_URL
-f FILE_TO_BE_RELEASED -F RELEASE_INFO_FILE
### Use in CI script
The PRIVATE_TOKEN should not be entered directly into the CI script but added as protected a CI variable to you particular project.
Then add the following stage into your CI script:
release:
stage: release
image: registry.gitlab.com/wolutator/base-build-env
only:
- release
script:
- gitlabreleaseuploader.py -p $PRIVATE_TOKEN -i $CI_PROJECT_ID -u $CI_PROJECT_URL
-f gitlabreleaseuploader.py -F info.json -T $CI_COMMIT_REF_NAME
Note, please: this stage definition is for a docker worker. It uses my ``base-build-env`` image, which already contains the
uploader script. However, it is no problem to use the uploader script also in different environments. It just depends on the
``Requests`` package.
Note too, please: this job is releasing the ``gitlabreleaseuploader.py`` script itself, so you see the name of the script twice in the CI script. Don't be confused, the option ``-f`` gets the file to be released.
Most information are taken from CI builtin variables, the tag name, release name and release description should be stored in
the release info file (here: ``info.json``), which is under version control.
To avoid releasing a file with everything single push to an arbitrary branch, add the ``only`` block.