Skip to content

Commit

Permalink
Universum 0.18.5
Browse files Browse the repository at this point in the history
  • Loading branch information
k-dovgan committed Apr 24, 2020
2 parents fd66ef0 + ef6d2fb commit 25a4677
Show file tree
Hide file tree
Showing 10 changed files with 403 additions and 274 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
Change log
==========

0.18.5 (2020-04-24)
-------------------

New features
~~~~~~~~~~~~

* **submit:** create and delete real CL to not interfere with any changes in default CL

Bug fixes
~~~~~~~~~

* **p4:** do not try to revert local files as they can be no longer accessible for write
to avoid creation of undeletable CLs and workspaces
* **launcher:** fix unsuccessful step launch in Ubuntu 14.04 (Python 2.7.6)


0.18.4 (2020-04-06)
-------------------

Expand Down
2 changes: 1 addition & 1 deletion _universum/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- coding: UTF-8 -*-

__title__ = "Universum"
__version__ = "0.18.4"
__version__ = "0.18.5"
2 changes: 1 addition & 1 deletion _universum/modules/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ def process_project_configs(self):

try:
with open(config_path) as config:
exec(config.read(), config_globals) # pylint: disable=exec-used
exec config.read() in config_globals # pylint: disable=exec-used

self.source_project_configs = config_globals["configs"]
dump_file = self.artifacts.create_text_file("CONFIGS_DUMP.txt")
Expand Down
87 changes: 43 additions & 44 deletions _universum/modules/vcs/perforce_vcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,29 @@ def p4reconcile(self, *args, **kwargs):
raise
return []

def reconcile_one_path(self, file_path, workspace_root, change_id, edit_only):
# TODO: cover 'not file_path.startswith("/")' case with tests
if not file_path.startswith("/"):
file_path = workspace_root + "/" + file_path
if file_path.endswith("/"):
file_path += "..."
if edit_only:
reconcile_result = self.p4reconcile("-c", change_id, "-e", convert_to_str(file_path))
if not reconcile_result:
self.out.log(
"The file was not edited. Skipping '{}'...".format(os.path.relpath(file_path, workspace_root)))
else:
reconcile_result = self.p4reconcile("-c", change_id, convert_to_str(file_path))

for line in reconcile_result:
# p4reconcile returns list of dicts AND strings if file is opened in another workspace
# so we catch TypeError if line is not dict
try:
if line["action"] == "add":
self.p4.run_reopen("-c", change_id, "-t", "+w", line["depotFile"])
except TypeError:
self.out.log(line)

@catch_p4exception()
def submit_new_change(self, description, file_list, review=False, edit_only=False):
self.connect()
Expand All @@ -159,52 +182,28 @@ def submit_new_change(self, description, file_list, review=False, edit_only=Fals
client = self.p4.fetch_client(self.settings.client)
workspace_root = client['Root']

# Make sure default CL is empty
try:
change = self.p4.fetch_change()
if "Files" in change:
text = "Default CL already contains the following files before reconciling:\n"
for line in change["Files"]:
text += " * " + line + "\n"
text += "Submitting skipped"
self.out.log(text)
return 0
except P4Exception:
pass

for file_path in file_list:
# TODO: cover 'not file_path.startswith("/")' case with tests
if not file_path.startswith("/"):
file_path = workspace_root + "/" + file_path
if file_path.endswith("/"):
file_path += "..."
if edit_only:
reconcile_result = self.p4reconcile("-e", convert_to_str(file_path))
if not reconcile_result:
self.out.log("The file was not edited. Skipping '{}'...".format(os.path.relpath(file_path, workspace_root)))
else:
reconcile_result = self.p4reconcile(convert_to_str(file_path))
change = self.p4.fetch_change()
change["Files"] = []
change["Description"] = description
change_id = self.p4.save_change(change)[0].split()[1]

for line in reconcile_result:
# p4reconcile returns list of dicts AND strings if file is opened in another workspace
# so we catch TypeError if line is not dict
try:
if line["action"] == "add":
self.p4.run_reopen("-t", "+w", line["depotFile"])
except TypeError:
self.out.log(line)

current_cl = self.p4.fetch_change()
current_cl['Description'] = description
try:
for file_path in file_list:
self.reconcile_one_path(file_path, workspace_root, change_id, edit_only)

# If no changes were reconciled, there will be no file records in CL dictionary
if "Files" not in current_cl:
return 0
current_cl = self.p4.fetch_change(change_id)
# If no changes were reconciled, there will be no file records in CL dictionary
if "Files" not in current_cl:
self.p4.run_change("-d", change_id)
return 0

result = self.p4.run_submit(current_cl, "-f", "revertunchanged")
cl_number = result[-1]['submittedChange']
self.p4.run_submit(current_cl, "-f", "revertunchanged")
except Exception:
self.p4.run_revert("-k", "-c", change_id)
self.p4.run_change("-d", change_id)
raise

return cl_number
return change_id


class PerforceWithMappings(PerforceVcs):
Expand Down Expand Up @@ -558,13 +557,13 @@ def prepare_repository(self):
def clean_workspace(self):
try:
self.p4.client = self.client_name
report = self.p4.run_revert("//...")
report = self.p4.run_revert("-C", self.client_name, "-k", "//...")
self.p4report(report)
shelves = self.p4.run_changes("-c", self.client_name, "-s", "shelved")
for item in shelves:
self.out.log("Deleting shelve from CL " + item["change"])
self.p4.run_shelve("-d", "-c", item["change"])
self.p4.run_revert("//...")
self.p4.run_revert("-C", self.client_name, "-k", "//...")
all_cls = self.p4.run_changes("-c", self.client_name, "-s", "pending")
for item in all_cls:
self.out.log("Deleting CL " + item["change"])
Expand Down
14 changes: 14 additions & 0 deletions tests/perforce_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,20 @@ def perforce_workspace(request, perforce_connection, tmpdir):
change["Description"] = "Test submit"
p4.run_submit(change)

permissions = p4.fetch_protect()
permissions['Protections'] = [
'write user * * //...',
'list user * * -//spec/...',
'super user p4user * //...', # first three rows are default
'=write user p4user * -//depot/write-protected/...' # prohibit p4user to submit changes to this branch
]
p4.save_protect(permissions)

triggers = {'Triggers': [
'test.check change-submit //depot/trigger-protected/... "false"' # trigger to prevent any submits to this branch
]}
p4.save_triggers(triggers)

yield utils.Params(p4=p4,
client_name=client_name,
depot=depot,
Expand Down
87 changes: 87 additions & 0 deletions tests/test_p4_exception_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# -*- coding: UTF-8 -*-
# pylint: disable = redefined-outer-name

import pytest

import universum
from tests.perforce_utils import P4Environment


@pytest.fixture()
def perforce_environment(perforce_workspace, tmpdir):
yield P4Environment(perforce_workspace, tmpdir, test_type="main")


def test_p4_forbidden_local_revert(perforce_environment, capsys):
p4 = perforce_environment.p4
p4_file = perforce_environment.repo_file

config = """
from _universum.configuration_support import Variations
configs = Variations([dict(name="Restrict changes", command=["chmod", "-R", "555", "."]),
dict(name="Check", command=["ls", "-la"])])
"""
p4.run_edit(perforce_environment.depot)
p4_file.write(config)
change = p4.fetch_change()
change["Description"] = "CL for shelving"
shelve_cl = p4.save_change(change)[0].split()[1]
p4.run_shelve("-fc", shelve_cl)

settings = perforce_environment.settings
settings.PerforceMainVcs.shelve_cls = [shelve_cl]
settings.Launcher.config_path = p4_file.basename

result = universum.run(settings)
# Clean up the directory at once to make sure it doesn't remain non-writable even if some assert fails
perforce_environment.temp_dir.chmod(0777, rec=1)
perforce_environment.temp_dir.remove(rec=1)

assert result != 0

assert "[Errno 13] Permission denied" in capsys.readouterr().err
# make sure there are no pending CLs in the workspace
assert not p4.run_changes("-c", perforce_environment.client_name, "-s", "pending")
# make sure there are no pending changes in default CL
assert not p4.run_opened("-C", perforce_environment.client_name)


def test_p4_print_exception_before_run(perforce_environment, stdout_checker):
p4 = perforce_environment.p4
client = p4.fetch_client(perforce_environment.client_name)
client["Options"] = "noallwrite noclobber nocompress locked nomodtime normdir"
p4.save_client(client)

settings = perforce_environment.settings
result = universum.run(settings)

# Update client at once to make sure it doesn't remain locked even if some assert fails
client = p4.fetch_client(perforce_environment.client_name)
client["Options"] = "noallwrite noclobber nocompress unlocked nomodtime normdir"
p4.save_client(client)

assert result != 0
stdout_checker.assert_has_calls_with_param(
"Errors during command execution( \"p4 client -d {}\" )".format(perforce_environment.client_name))


def test_p4_print_exception_in_finalize(perforce_environment, stdout_checker, capsys):
p4 = perforce_environment.p4
client = p4.fetch_client(perforce_environment.client_name)
client["Options"] = "noallwrite noclobber nocompress locked nomodtime normdir"
p4.save_client(client)

settings = perforce_environment.settings
settings.Main.finalize_only = True
result = universum.run(settings)

# Update client at once to make sure it doesn't remain locked even if some assert fails
client = p4.fetch_client(perforce_environment.client_name)
client["Options"] = "noallwrite noclobber nocompress unlocked nomodtime normdir"
p4.save_client(client)

assert result != 0
stdout_checker.assert_has_calls_with_param(
"Errors during command execution( \"p4 client -d {}\" )".format(perforce_environment.client_name))
assert "CiException: [Errno 2] No such file or directory" in capsys.readouterr().err
43 changes: 0 additions & 43 deletions tests/test_p4_revert_unshelved.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
import os
import pytest

import universum
from _universum.lib.gravity import construct_component
from _universum.modules.vcs import perforce_vcs
from .perforce_utils import P4Environment
from . import utils


Expand Down Expand Up @@ -133,44 +131,3 @@ def create_file(filename):

for result, expected in zip(diff, expected_path):
assert result == expected


@pytest.fixture()
def perforce_environment(perforce_workspace, tmpdir):
yield P4Environment(perforce_workspace, tmpdir, test_type="main")


def test_p4_error_revert(perforce_environment, stdout_checker, capsys):
p4 = perforce_environment.p4
p4_file = perforce_environment.repo_file

config = """
from _universum.configuration_support import Variations
configs = Variations([dict(name="Restrict changes", command=["chmod", "-R", "555", "."]),
dict(name="Check", command=["ls", "-la"])])
"""
p4.run_edit(perforce_environment.depot)
p4_file.write(config)
change = p4.fetch_change()
change["Description"] = "CL for shelving"
shelve_cl = p4.save_change(change)[0].split()[1]
p4.run_shelve("-fc", shelve_cl)

settings = perforce_environment.settings
settings.Launcher.output = "console"
settings.PerforceMainVcs.shelve_cls = [shelve_cl]
settings.Launcher.config_path = p4_file.basename

result = universum.run(settings)
# Clean up the directory at once to make sure it doesn't remain non-writable even if some assert fails
perforce_environment.temp_dir.chmod(0777, rec=1)
perforce_environment.temp_dir.remove(rec=1)

assert result != 0
# The following checks make sure all following actions were triggered despite unsuccessful:
# full revert, client deleting and sources clean up
stdout_checker.assert_has_calls_with_param("Errors during command execution( \"p4 revert //...\" )")
stdout_checker.assert_has_calls_with_param(
"Errors during command execution( \"p4 client -d {}\" )".format(perforce_environment.client_name))
assert "[Errno 13] Permission denied" in capsys.readouterr().err
2 changes: 0 additions & 2 deletions tests/test_p4_submit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def p4_submit_environment(perforce_workspace, tmpdir):


def test_fail_changing_non_checked_out_file(p4_submit_environment):

target_file = p4_submit_environment.nonwritable_file
text = utils.randomize_name("This is change ")
with pytest.raises(IOError) as excinfo:
Expand All @@ -24,7 +23,6 @@ def test_fail_changing_non_checked_out_file(p4_submit_environment):


def test_success_changing_checked_out_file(p4_submit_environment):

target_file = p4_submit_environment.nonwritable_file

p4_submit_environment.p4.run("edit", str(target_file))
Expand Down
Loading

0 comments on commit 25a4677

Please sign in to comment.