Skip to content

Commit

Permalink
Merge 45a8a93 into ccb00ee
Browse files Browse the repository at this point in the history
  • Loading branch information
Diego committed Aug 11, 2020
2 parents ccb00ee + 45a8a93 commit 2b9811d
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 1 deletion.
12 changes: 12 additions & 0 deletions reana/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,15 @@

TIMEOUT = 300
"""Maximum timeout to wait for results when running demo analyses in CI."""

HELM_VERSION_FILE = "Chart.yaml"
"""Helm package version file."""

OPENAPI_VERSION_FILE = "openapi.json"
"""OpenAPI version file."""

JAVASCRIPT_VERSION_FILE = "package.json"
"""JavaScript package version file."""

PYTHON_VERSION_FILE = "version.py"
"""Python package version file."""
83 changes: 82 additions & 1 deletion reana/reana_dev/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

import datetime
import os
import sys
import subprocess
import sys

import click

Expand All @@ -21,9 +21,12 @@
REPO_LIST_ALL,
REPO_LIST_SHARED,
)

from reana.reana_dev.utils import (
bump_component_version,
display_message,
fetch_latest_pypi_version,
get_current_component_version_from_source_files,
get_srcdir,
run_command,
select_components,
Expand Down Expand Up @@ -84,6 +87,50 @@ def get_current_commit(srcdir):
)


def git_is_current_version_tagged(component):
"""Determine whether the current version in source code is present as a git tag."""
tags_history = run_command(
"git tag --list", component, display=False, return_output=True
)
current_version = get_current_component_version_from_source_files(component)
return current_version in tags_history if tags_history else False


def git_create_release_commit(component):
"""Create a release commit for the given component."""
if "release:" in get_current_commit(get_srcdir(component)):
display_message("Nothing to do, last commit is a release commit.", component)
return False

current_version = get_current_component_version_from_source_files(component)
if not current_version:
display_message(
f"Version cannot be autodiscovered from source files.", component
)
sys.exit(1)
elif not git_is_current_version_tagged(component):
display_message(
f"Current version ({current_version}) "
"not present as a git tag, plese release it and add a tag.",
component,
)
sys.exit(1)

next_version, modified_files = bump_component_version(component, current_version,)

if (
run_command(
"git branch --show-current", component, display=False, return_output=True,
)
== "master"
):
run_command(f"git checkout -b release-{next_version}", component)

run_command(f"git add {' '.join(modified_files)}", component)
run_command(f"git commit -m 'release: {next_version}'", component)
return True


@click.group()
def git_commands():
"""Git commands group."""
Expand Down Expand Up @@ -820,4 +867,38 @@ def _push_to_origin(components):
_push_to_origin(components)


@click.option(
"--component",
"-c",
multiple=True,
default=["CLUSTER"],
help="Which components? [shortname|name|.|CLUSTER|ALL]",
)
@git_commands.command(name="git-create-release-commit")
def git_create_release_commit_command(component): # noqa: D301
"""Create a release commit for the specified components.
\b
:param components: The option ``component`` can be repeated. The value may
consist of:
* (1) standard component name such as
'reana-workflow-controller';
* (2) short component name such as 'r-w-controller';
* (3) special value '.' indicating component of the
current working directory;
* (4) special value 'CLUSTER' that will expand to
cover all REANA cluster components [default];
* (5) special value 'CLIENT' that will expand to
cover all REANA client components;
* (6) special value 'DEMO' that will expand
to include several runable REANA demo examples;
* (7) special value 'ALL' that will expand to include
all REANA repositories.
:type component: str
"""
for comp in select_components(component):
if git_create_release_commit(comp):
display_message("Release commit created.", comp)


git_commands_list = list(git_commands.commands.values())
182 changes: 182 additions & 0 deletions reana/reana_dev/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@
"""`reana-dev` related utils."""

import datetime
import importlib.util
import json
import os
import subprocess
import sys

import click
import semver
import yaml
from packaging.version import InvalidVersion, Version

from reana.config import (
COMPONENTS_USING_SHARED_MODULE_COMMONS,
COMPONENTS_USING_SHARED_MODULE_DB,
HELM_VERSION_FILE,
JAVASCRIPT_VERSION_FILE,
OPENAPI_VERSION_FILE,
PYTHON_VERSION_FILE,
REPO_LIST_ALL,
REPO_LIST_CLIENT,
REPO_LIST_CLUSTER,
Expand Down Expand Up @@ -458,3 +467,176 @@ def update_module_in_cluster_components(
bold=True,
fg="green",
)


def get_component_version_files(component, abs_path=False):
"""Get a dictionary with all component's version files."""
version_files = {}
for file_ in [
HELM_VERSION_FILE,
OPENAPI_VERSION_FILE,
JAVASCRIPT_VERSION_FILE,
PYTHON_VERSION_FILE,
]:
file_path = run_command(
f"git ls-files | grep -w {file_} || true",
component,
display=False,
return_output=True,
)
if file_path and abs_path:
file_path = os.path.join(get_srcdir(component=component), file_path)

version_files[file_] = file_path

return version_files


def get_current_component_version_from_source_files(component):
"""Get component's current version."""
version_files = get_component_version_files(component, abs_path=True)
version = ""
if version_files.get(HELM_VERSION_FILE):
with open(version_files.get(HELM_VERSION_FILE)) as f:
chart_yaml = yaml.safe_load(f.read())
version = chart_yaml["version"]

elif version_files.get(PYTHON_VERSION_FILE):
spec = importlib.util.spec_from_file_location(
component, version_files.get(PYTHON_VERSION_FILE)
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
version = module.__version__

elif version_files.get(JAVASCRIPT_VERSION_FILE):
with open(version_files.get(JAVASCRIPT_VERSION_FILE)) as f:
package_json = json.loads(f.read())
version = package_json["version"]

return version


def bump_semver2_version(current_version, part=None, prerelease_string=None):
"""Bump a semver2 version string.
:param current_version: current version to be bumped
:type current_version: str
:return: String representation of the next version
:rtype: string
"""
if not semver.VersionInfo.isvalid(current_version):
click.echo(
f"Current version {current_version} is not a valid semver2 version. Please amend it"
)

prerelease_string = prerelease_string or "alpha"
parsed_current_version = semver.VersionInfo.parse(current_version)
next_version = ""
if parsed_current_version.build or part == "build":
next_version = parsed_current_version.bump_build()
elif parsed_current_version.prerelease or part == "prerelease":
next_version = parsed_current_version.bump_prerelease("alpha")
elif parsed_current_version.patch or part == "patch":
next_version = parsed_current_version.next_version("patch")
elif parsed_current_version.minor or part == "minor":
next_version = parsed_current_version.next_version("minor")
elif parsed_current_version.major or part == "major":
next_version = parsed_current_version.next_version("major")

return str(next_version)


def bump_pep440_version(current_version, part=None, prerelease_string=None):
"""Bump a PEP440 version string.
:param current_version: current version to be bumped
:param part: part of the PEP440 version to bump (one of: [major, minor, micro, pre]).
:type current_version: str
:type part: str
:return: String representation of the next version
:rtype: string
"""

def _bump_prerelease(prev_prerelease_number):
"""Bump a prerelease depending on its number/date based version."""
try:
default_date_format = "%Y%m%d"
extended_date_format = default_date_format + "%H%M%S"

today_ = datetime.datetime.today()
next_prerelease_date = today_.strftime(default_date_format)
prev_prerelease_date = datetime.datetime.strptime(
prev_prerelease_number, default_date_format
)
if today_ < prev_prerelease_date:
raise Exception(
"Current prerelease version is newer than today, please fix it."
)
if prev_prerelease_number == next_prerelease_date:
next_prerelease_date = today_.strftime(extended_date_format)
return next_prerelease_date
except ValueError:
return prev_prerelease_number + 1

try:
version = Version(current_version)
prerelease_string = prerelease_string or "a"
next_version = ""
if version.pre or part == "pre":
prerelease_part = ""
if version.pre:
prerelease_part = f"{version.pre[0]}{version.pre[1]+1}"
else:
prerelease_part = f"{prerelease_string}1"
next_version = Version(
f"{version.major}.{version.minor}.{version.micro}{prerelease_part}"
)
elif version.micro or part == "micro":
next_version = Version(f"{version.major}.{version.minor}.{version.micro+1}")
elif version.minor or part == "minor":
next_version = Version(f"{version.major}.{version.minor}+1.0")
elif version.micro or part == "micro":
next_version = Version(f"{version.major}+1.0.0")

return str(next_version)
except InvalidVersion as e:
click.echo(
f"Current {current_version} is not a valid PEP440 version. Please amend it"
)


def bump_component_version(component, current_version):
"""Bump to next component version."""
try:
version_files = get_component_version_files(component)
next_version = ""
files_to_update = []

if version_files.get(HELM_VERSION_FILE):
next_version = bump_semver2_version(current_version)
files_to_update.append(version_files.get(HELM_VERSION_FILE))
elif version_files.get(PYTHON_VERSION_FILE):
next_version = bump_pep440_version(current_version)
files_to_update.append(version_files.get(PYTHON_VERSION_FILE))
if version_files.get(OPENAPI_VERSION_FILE):
files_to_update.append(version_files.get(OPENAPI_VERSION_FILE))
elif version_files.get(JAVASCRIPT_VERSION_FILE):
next_version = bump_semver2_version(current_version)
files_to_update.append(version_files.get(JAVASCRIPT_VERSION_FILE))

for file_ in files_to_update:
replace_string(
file_=file_,
find=current_version,
replace=next_version,
component=component,
)

return next_version, files_to_update
except Exception as e:
display_message(
f"Something went wront while bumping the version: {e}", component
)
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"click>=7",
"colorama>=0.3.9",
"PyYAML>=5.1",
"semver>=2.10.2",
]


Expand Down

0 comments on commit 2b9811d

Please sign in to comment.