diff --git a/.travis.yml b/.travis.yml index 6fc5e50..adb4d51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,4 +8,5 @@ install: - pipenv install script: - gitlint - - python tests.py + - pylint setup.py gitea_auto_update + - python -m unittest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f4e324c..21952f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,3 +7,4 @@ All good contributions which add a new feature or close a issue will be accepted 1. Commit messages should follow the Angular Commit Message Format: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit 2. New features should be added with a new function, if a new function is possible. 3. Test-driven development (TDD) should be followed - this means you should always create unit tests for your function before you create the corresponding function. +4. You should use the linter \ No newline at end of file diff --git a/Pipfile b/Pipfile index 4f197c4..fba1249 100644 --- a/Pipfile +++ b/Pipfile @@ -11,6 +11,7 @@ packaging = "*" fire = "*" configparser = "*" gitlint = "*" +pylint = "*" [requires] python_version = "3.7" diff --git a/README.md b/README.md index 8ea4b9a..e2dd645 100644 --- a/README.md +++ b/README.md @@ -67,9 +67,10 @@ The following instructions help you for developing. * Clone this git repo * Install pipenv: `pip install pipenv` * Install all dependencies: `pipenv install` -* You can run the tests with `python tests.py` +* You can run the tests with `python -m unittest` +* You can run pylint with `pylint gitea_auto_update` * After changes and commit, you can check if your commit message follows the contribution guidelines with `gitlint`. If there is a problem, gitlint will show you a error message. -* After pushing, you should check the build status which currently checks the tests and the commit message format. +* After pushing, you should check the build status which currently checks the tests, pylint and the commit message format. ## Contributors diff --git a/gitea_auto_update/lib/build.py b/gitea_auto_update/lib/build.py index 06ead68..f668970 100644 --- a/gitea_auto_update/lib/build.py +++ b/gitea_auto_update/lib/build.py @@ -1,24 +1,19 @@ ''' Gitea Auto Updater -Copyright 2018, 2019 The Gitea-Auto-Update Authors +Copyright 2018, 2019, 2020 The Gitea-Auto-Update Authors All rights reserved. License: GNU General Public License ''' import os -class Build: - def __init__(self, gtFile, sourceDir): - self.gtFile = gtFile - self.sourceDir = sourceDir - - def fromSource(self, tag): - # Function to build the new version from source - os.chdir(self.sourceDir) - os.system("git checkout master") - os.system("git pull") - os.system("git checkout " + tag) - os.system('TAGS="bindata sqlite sqlite_unlock_notify" make generate build') - os.system("mv gitea " + self.gtFile) \ No newline at end of file +def build_from_source(tag, gt_file, source_dir): + """Function to build the new version from source""" + os.chdir(source_dir) + os.system("git checkout master") + os.system("git pull") + os.system("git checkout " + tag) + os.system('TAGS="bindata sqlite sqlite_unlock_notify" make generate build') + os.system("mv gitea " + gt_file) diff --git a/gitea_auto_update/lib/download.py b/gitea_auto_update/lib/download.py index 5f51f0d..02682cd 100644 --- a/gitea_auto_update/lib/download.py +++ b/gitea_auto_update/lib/download.py @@ -1,79 +1,91 @@ ''' Gitea Auto Updater -Copyright 2018, 2019 The Gitea-Auto-Update Authors +Copyright 2018, 2019, 2020 The Gitea-Auto-Update Authors All rights reserved. License: GNU General Public License ''' -import requests import os +import sys import logging from shutil import which # from whichcraft import which +import requests + + +def is_tool(name): + """Function to check if tool is available""" + # Check whether `name` is on PATH and marked as executable. + return which(name) is not None + + +def download(url, file_name): + """Function to download a file""" + # open in binary mode + with open(file_name, "wb") as file: + # get request + response = requests.get(url) + # write to file + file.write(response.content) + + +def sha_check(): + """Check sha for gitea file""" + return os.system("sha256sum -c gitea.xz.sha256 > /dev/null") == 0 class Download: + """Class for downloading gitea""" - def __init__(self, tmpDir, githubVersion, githubVersionTag, gtSystem, gtFile): - if not self.isTool("xz"): + def __init__(self, tmp_dir, github_version_tag, gt_system, gt_file): + if not is_tool("xz"): logging.error('Download: missing dependency: xz') - quit() + sys.exit() - self.tmpDir = tmpDir - self.githubVersion = githubVersion - self.githubVersionTag = githubVersionTag - self.gtSystem = gtSystem - self.gtFile = gtFile + self.tmp_dir = tmp_dir + self.github_version_tag = github_version_tag + self.github_version = self.github_version_tag[1:] + self.gt_system = gt_system + self.gt_file = gt_file - self.downloadGiteaFiles() - self.checkAndExtract() + self.download_gitea_files() + self.check_and_extract() - def isTool(self, name): - # Function to check if tool is available - ##Check whether `name` is on PATH and marked as executable. - return which(name) is not None - - def download(self, url, fileName): - # Function to download a file - # open in binary mode - with open(fileName, "wb") as file: - # get request - response = requests.get(url) - # write to file - file.write(response.content) - - def downloadGiteaFiles(self): + def download_gitea_files(self): + """Download gitea files""" # Set download url - gtDownload = 'https://github.com/go-gitea/gitea/releases/download/' + self.githubVersionTag + '/gitea-' + self.githubVersion + '-' + self.gtSystem + '.xz' - logging.info('Download: Gitea file: %s', gtDownload) - shaDownload = gtDownload + '.sha256' - logging.info('Download: SHA file: %s', shaDownload) + gt_download = 'https://github.com/go-gitea/gitea/releases/download/' \ + + self.github_version_tag + '/gitea-' + self.github_version \ + + '-' + self.gt_system + '.xz' + logging.info('Download: Gitea file: %s', gt_download) + sha_download = gt_download + '.sha256' + logging.info('Download: SHA file: %s', sha_download) # Download file logging.info('Download: downloading sha256 hashsum') - self.download(shaDownload, self.tmpDir + 'gitea.xz.sha256') - logging.info('Download: downloading %s', self.githubVersionTag + 'gitea.xz') - self.tmpXz = self.tmpDir +'gitea-' + self.githubVersion + '-' + self.gtSystem + '.xz' - self.download(gtDownload, self.tmpXz) + download(sha_download, self.tmp_dir + 'gitea.xz.sha256') + logging.info('Download: downloading %s', self.github_version_tag + 'gitea.xz') + self.tmp_xz = self.tmp_dir + 'gitea-' + self.github_version + '-' + self.gt_system + '.xz' + download(gt_download, self.tmp_xz) - def shaCheck(self): - return os.system("sha256sum -c gitea.xz.sha256 > /dev/null") == 0 - - def extractFile(self): + def extract_file(self): + """Extract gitea file""" logging.info('Download: sha ok, extracting file to location') # extracting download file - cmd = "xz -d " + self.tmpXz + cmd = "xz -d " + self.tmp_xz os.system(cmd) # moving temp file to gtfile location - cmd = 'mv ' + self.tmpDir + 'gitea-' + self.githubVersion + '-' + self.gtSystem + ' ' + self.gtFile + cmd = 'mv ' + self.tmp_dir + 'gitea-' + self.github_version \ + + '-' + self.gt_system + ' ' + self.gt_file os.system(cmd) - cmd = 'chmod +x ' + self.gtFile + cmd = 'chmod +x ' + self.gt_file os.system(cmd) - def checkAndExtract(self): - os.chdir(self.tmpDir) - if self.shaCheck(): - self.extractFile() + def check_and_extract(self): + """Check file and extract""" + os.chdir(self.tmp_dir) + if sha_check(): + self.extract_file() else: logging.error('Download: error: sha256sum failed') - quit() + sys.exit() diff --git a/gitea_auto_update/lib/test_version.py b/gitea_auto_update/lib/test_version.py new file mode 100644 index 0000000..f03ecba --- /dev/null +++ b/gitea_auto_update/lib/test_version.py @@ -0,0 +1,52 @@ +''' +Gitea Auto Updater + +Copyright 2019, 2020 The Gitea-Auto-Update Authors +All rights reserved. + +License: GNU General Public License +''' +import unittest +import gitea_auto_update.lib.version + +VERSION = gitea_auto_update.lib.version + + +class TestVersion(unittest.TestCase): + """Test the version class""" + + def test_simple_version(self): + """1.9.1 should be newer than 1.9.0""" + self.assertTrue(VERSION.check_version('1.9.1', '1.9.0')) + + def test_two_int_version(self): + """1.10.0 should be newer than 1.9.0""" + self.assertTrue(VERSION.check_version('1.10.0', '1.9.0')) + + def test_false_version(self): + """1.8.0 should be older than 1.9.0""" + self.assertFalse(VERSION.check_version('1.8.0', '1.9.0')) + + def test_same_version(self): + """1.9.7 should be the same as 1.9.7""" + self.assertFalse(VERSION.check_version('1.9.7', '1.9.7')) + + def test_int(self): + """9 should be newer than 8""" + self.assertTrue(VERSION.check_version('9', '8')) + + def test_suffix(self): + """1.9.0+dev-264-g8de76b6e6 should be newer than 1.8.0""" + self.assertTrue(VERSION.check_version('1.9.0+dev-264-g8de76b6e6', '1.8.0')) + + def test_parse_file_version(self): + """It should get the version from a string""" + string = 'Gitea version 1.8.1 built with go1.12.2 : bindata, sqlite, sqlite_unlock_notify' + self.assertEqual( + VERSION.parse_file_version(string), + '1.8.1' + ) + + +if __name__ == '__main__': + unittest.main() diff --git a/gitea_auto_update/lib/version.py b/gitea_auto_update/lib/version.py index 6c8e60b..1545765 100644 --- a/gitea_auto_update/lib/version.py +++ b/gitea_auto_update/lib/version.py @@ -1,52 +1,60 @@ ''' Gitea Auto Updater -Copyright 2018, 2019 The Gitea-Auto-Update Authors +Copyright 2018, 2019, 2020 The Gitea-Auto-Update Authors All rights reserved. License: GNU General Public License ''' -from packaging import version import os -import requests import logging +from packaging import version +import requests + + +def get_github_version_tag(api_url): + """Get the version from github""" + version_tag = requests.get(api_url).json()['tag_name'] + logging.info('Version: github_version_tag = %s', version_tag) + return version_tag + + +def parse_file_version(string): + """Get the version from a file""" + return string.split(" ")[2] + + +def check_version(new_version, old_version): + """Function to check if there is a new version""" + return version.parse(new_version) > version.parse(old_version) + class Version: + """Class to get and check the gitea version""" - def __init__(self, gtSite, gtFile): - self.gtSite = gtSite - self.gtFile = gtFile + def __init__(self, gt_site, gt_file): + self.gt_site = gt_site + self.gt_file = gt_file - def checkVersion(self, newVersion, oldVersion): - # Function to check if there is a new version - return version.parse(newVersion) > version.parse(oldVersion) + def get_version_from_file(self): + """Read the version from the gitea file""" + version_string = os.popen(self.gt_file + " -v").read() + return parse_file_version(version_string) - def parseFileVersion(self, string): - return string.split(" ")[2] - - def getVersionFromFile(self): - versionString = os.popen(self.gtFile + " -v").read() - return self.parseFileVersion(versionString) - - def getCurrentVersion(self): - # Function to get the current version + def get_current_version(self): + """Function to get the current version""" try: # Try to get the version from the file - currentVersion = self.getVersionFromFile() - except: + current_version = self.get_version_from_file() + except IOError: # Get the version via the web api if the file does fail try: - currentVersion = requests.get(self.gtSite).json()['version'] - if currentVersion.status_code != 200: + current_version = requests.get(self.gt_site).json()['version'] + if current_version.status_code != 200: raise RuntimeError("Could not download version.") - except: + except RuntimeError: # To allow installation, return a default version of "0.0.0". - currentVersion = "0.0.0" + current_version = "0.0.0" finally: - logging.info('Version: current_version = %s', currentVersion) - return currentVersion - - def getGithubVersionTag(self, apiUrl): - versionTag = requests.get(apiUrl).json()['tag_name'] - logging.info('Version: github_version_tag = %s', versionTag) - return versionTag + logging.info('Version: current_version = %s', current_version) + return current_version diff --git a/gitea_auto_update/update.py b/gitea_auto_update/update.py index dabda1c..fade12b 100644 --- a/gitea_auto_update/update.py +++ b/gitea_auto_update/update.py @@ -1,7 +1,7 @@ ''' Gitea Auto Updater -Copyright 2018, 2019 The Gitea-Auto-Update Authors +Copyright 2018, 2019, 2020 The Gitea-Auto-Update Authors All rights reserved. License: GNU General Public License @@ -15,72 +15,80 @@ import gitea_auto_update.lib.version import gitea_auto_update.lib.download import gitea_auto_update.lib.build + class Update: + """ + Main class to update gitea + """ - def __init__(self, gtSite, gtFile, sourceDir, apiUrl, buildFromSource, tmpDir, gtSystem): - self.gtSite = gtSite - self.gtFile = gtFile - self.sourceDir = sourceDir - self.apiUrl = apiUrl - self.buildFromSource = buildFromSource - self.tmpDir = tmpDir - self.gtSystem = gtSystem + def __init__(self, + config): + self.config = config - self.initVersionAndBuild() - self.getVersionAndTag() - self.checkAndUpdate() + # Get version tag from github and remove first char (v) + self.github_version_tag = gitea_auto_update.lib.version.get_github_version_tag( + config.get('Gitea', 'apiUrl') + ) + # Get version from version tag + self.github_version = self.github_version_tag[1:] - def initVersionAndBuild(self): - self.version = gitea_auto_update.lib.version.Version(self.gtSite, self.gtFile) - self.build = gitea_auto_update.lib.build.Build(self.gtFile, self.sourceDir) + self.check_and_update() - def getVersionAndTag(self): - self.currentVersion = self.version.getCurrentVersion() # Version from gitea site - self.githubVersionTag = self.version.getGithubVersionTag(self.apiUrl) # Get version tag from github and remove first char (v) - self.githubVersion = self.githubVersionTag[1:] # Get version from version tag + def do_update(self): + """Execute the update""" - def doUpdate(self): - if self.buildFromSource: # Should the new version be build from source? - self.build.fromSource(self.githubVersionTag) + # Should the new version be build from source? + if self.config.get('Gitea', 'buildFromSource'): + gitea_auto_update.lib.build.build_from_source( + self.github_version_tag, + self.config.get('Gitea', 'file'), + self.config.get('Gitea', 'sourceDir') + ) else: - self.download = gitea_auto_update.lib.download.Download(self.tmpDir, - self.githubVersion, - self.githubVersionTag, - self.gtSystem, - self.gtFile) + gitea_auto_update.lib.download.Download( + self.config.get('Gitea', 'tmpDir'), + self.github_version_tag, + self.config.get('Gitea', 'system'), + self.config.get('Gitea', 'file') + ) - def checkAndUpdate(self): - if self.version.checkVersion(self.githubVersion, self.currentVersion): # Check if there is a new version + def check_and_update(self): + """Check if a update is possible and do it if it is""" + # Version from gitea site + version = gitea_auto_update.lib.version.Version( + self.config.get('Gitea', 'site'), + self.config.get('Gitea', 'file') + ) + current_version = version.get_current_version() + # Check if there is a new version + if gitea_auto_update.lib.version.check_version(self.github_version, current_version): logging.info('Update: new version available, stopping service') os.system("systemctl stop gitea.service") - self.doUpdate() + self.do_update() logging.info('Update: starting gitea.service') os.system("systemctl start gitea.service") print("update successfully") else: print("current version is uptodate") + def updater(settings='settings.ini'): + """Get the config and set logging""" # Config config = configparser.ConfigParser() config.read(settings) # Create a log file logging.basicConfig(filename=config.get('Gitea', 'logFile'), level=logging.DEBUG) # Start update - Update(config.get('Gitea', 'site'), - config.get('Gitea', 'file'), - config.get('Gitea', 'sourceDir'), - config.get('Gitea', 'apiUrl'), - config.get('Gitea', 'buildFromSource'), - config.get('Gitea', 'tmpDir'), - config.get('Gitea', 'system')) + Update(config) def main(): + """Main func""" if not sys.version_info[0] == 3: sys.exit("Sorry, Python 2 is not supported. Please update to Python 3.") fire.Fire(updater) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/setup.py b/setup.py index c83b276..58dfac7 100644 --- a/setup.py +++ b/setup.py @@ -1,32 +1,41 @@ +''' +Gitea Auto Updater + +Copyright 2018, 2019, 2020 The Gitea-Auto-Update Authors +All rights reserved. + +License: GNU General Public License +''' import setuptools with open("README.md", "r") as fh: - long_description = fh.read() + LONG_DESCRIPTION = fh.read() -setuptools.setup(name='gitea_auto_update', - version='2.0.7', - description='A script which can update gitea to a new version.', - long_description=long_description, - long_description_content_type="text/markdown", - url='https://github.com/CMiksche/gitea-auto-update', - author='Christoph Miksche', - author_email='christoph@miksche.org', - license='GPLv3', - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", - "Operating System :: Unix", - ], - keywords=['gitea', 'update', 'debian', 'linux'], - python_requires='>=3', - install_requires=[ - 'requests', - 'packaging', - 'fire', - 'configparser' - ], - packages=setuptools.find_packages(), - entry_points={ - 'console_scripts': ['gitea-auto-update=gitea_auto_update.update:main'], - } - ) \ No newline at end of file +setuptools.setup( + name='gitea_auto_update', + version='2.0.7', + description='A script which can update gitea to a new version.', + long_description=LONG_DESCRIPTION, + long_description_content_type="text/markdown", + url='https://github.com/CMiksche/gitea-auto-update', + author='Christoph Miksche', + author_email='christoph@miksche.org', + license='GPLv3', + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Operating System :: Unix", + ], + keywords=['gitea', 'update', 'debian', 'linux'], + python_requires='>=3', + install_requires=[ + 'requests', + 'packaging', + 'fire', + 'configparser' + ], + packages=setuptools.find_packages(), + entry_points={ + 'console_scripts': ['gitea-auto-update=gitea_auto_update.update:main'], + } +) diff --git a/tests.py b/tests.py deleted file mode 100644 index e401321..0000000 --- a/tests.py +++ /dev/null @@ -1,38 +0,0 @@ -''' -Gitea Auto Updater - -Copyright 2019 The Gitea-Auto-Update Authors -All rights reserved. - -License: GNU General Public License -''' -import gitea_auto_update.lib.version -import unittest - -version = gitea_auto_update.lib.version.Version('', '') - -class Tests(unittest.TestCase): - - def testSimpleVersion(self): - self.assertTrue(version.checkVersion('1.9.1', '1.9.0')) - - def testTwoIntVersion(self): - self.assertTrue(version.checkVersion('1.10.0', '1.9.0')) - - def testFalseVersion(self): - self.assertFalse(version.checkVersion('1.8.0', '1.9.0')) - - def testSameVersion(self): - self.assertFalse(version.checkVersion('1.9.7', '1.9.7')) - - def testInt(self): - self.assertTrue(version.checkVersion('9', '8')) - - def testSuffix(self): - self.assertTrue(version.checkVersion('1.9.0+dev-264-g8de76b6e6', '1.8.0')) - - def testParseFileVersion(self): - self.assertEqual(version.parseFileVersion('Gitea version 1.8.1 built with go1.12.2 : bindata, sqlite, sqlite_unlock_notify'), '1.8.1') - -if __name__ == '__main__': - unittest.main() \ No newline at end of file