Skip to content

Commit

Permalink
Merge pull request #30 from stb-tester/hidden-snapshot-ref
Browse files Browse the repository at this point in the history
Use refs/snapshots/$username instead of refs/heads/$username/snapshot
  • Loading branch information
drothlis committed Apr 29, 2020
2 parents cdcadca + 384336c commit 81bd323
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 24 deletions.
57 changes: 47 additions & 10 deletions stbt_rig.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,13 +545,14 @@ def cmd_screenshot(args, node):
def cmd_snapshot(args, node):
branch_name = _get_snapshot_branch_name(node.portal)
TestPack(remote=args.git_remote).push_git_snapshot(branch_name)
node.portal.notify_push()


def _get_snapshot_branch_name(portal):
response = portal._get("/api/v2/user")
response.raise_for_status()
username = response.json()["login"]
return "%s/snapshot" % username
return "refs/snapshots/%s" % username


class NotInTestPack(Exception):
Expand Down Expand Up @@ -969,6 +970,9 @@ def run_tests(
job.await_completion(timeout=timeout)
return job

def notify_push(self):
self._post("/github/post-receive").raise_for_status()

def _get(self, endpoint, timeout=60, **kwargs):
return self._session.get(self.url(endpoint), timeout=timeout, **kwargs)

Expand Down Expand Up @@ -1050,25 +1054,58 @@ def take_snapshot(self):
['write-tree'],
extra_env={'GIT_INDEX_FILE': tmp_index}).strip()

if self.get_sha(obj_type="tree") == write_tree:
return base_commit
head = self._git(["rev-parse", "--symbolic-full-name", "HEAD"]).strip()
remoteref = self._git(
["for-each-ref",
"--format=%(push:remoteref)\n%(upstream:remoteref)\n",
head]).split('\n')
if remoteref and remoteref[0]:
# push:remoteref set if the repo is configured to push to a
# different place from which it fetches
remoteref = remoteref[0]
elif len(remoteref) > 1 and remoteref[1]:
# upstream:remoteref will be set otherwise, assuming we've actually
# got a remote tracking branch.
remoteref = remoteref[1]
else:
remoteref = ""

no_workingdir_changes = (self.get_sha(obj_type="tree") == write_tree)
if no_workingdir_changes:
# No changes, we still want a new commit so we can inform the portal
# which branch we're working on. We copy over the author date and
# committer date so we'll get the same SHA every time. This will
# cut down on push time and object pollution.
ad, cd = self._git(
["show", base_commit, "--no-patch",
"--format=%ad\n%cd"]).split('\n')[:2]
extra_env = {"GIT_AUTHOR_DATE": ad, "GIT_COMMITTER_DATE": cd}
else:
extra_env = {}

commit_sha = self._git(
['commit-tree', write_tree, '-p', base_commit, '-m',
"snapshot\n\nremoteref: %s" % remoteref],
extra_env=extra_env).strip()

if no_workingdir_changes:
return commit_sha, base_commit
else:
return self._git(
['commit-tree', write_tree, '-p', base_commit, '-m',
"snapshot"]).strip()
return commit_sha, commit_sha

def push_git_snapshot(self, branch, interactive=True):
commit_sha = self.take_snapshot()
commit_sha, run_sha = self.take_snapshot()
options = ['--force']
if not logger.isEnabledFor(logging.DEBUG):
options.append('--quiet')
logger.info("Pushing git snapshot to %s/%s", self.remote, branch)
logger.info("Pushing git snapshot %s to %s:%s",
commit_sha[:7], self.remote, branch)
self._git(
['push'] + options +
[self.remote,
'%s:refs/heads/%s' % (commit_sha, branch)],
'%s:%s' % (commit_sha, branch)],
interactive=interactive)
return commit_sha
return run_sha


class RetrySession(object):
Expand Down
50 changes: 36 additions & 14 deletions test_stbt_rig.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from __future__ import absolute_import, division, print_function

import glob
import logging
import os
import platform
import random
import re
import socket
import threading
import time
from contextlib import contextmanager
Expand All @@ -31,22 +29,23 @@ def fixture_tmpdir():
with stbt_rig.named_temporary_directory(ignore_errors=True) as d:
origdir = os.path.abspath(os.curdir)
try:
os.chdir(d)
os.mkdir("%s/test-pack" % d)
os.chdir("%s/test-pack" % d)
yield d
finally:
os.chdir(origdir)


@pytest.fixture(scope="function", name="test_pack")
def fixture_test_pack(tmpdir): # pylint: disable=unused-argument
subprocess.check_call(['git', 'init'])
os.mkdir("../upstream")
subprocess.check_call(['git', 'init', '--bare'], cwd="../upstream")

subprocess.check_call(['git', 'clone', '../upstream', '.'])
subprocess.check_call([
'git', 'config', 'user.email', 'stbt-rig@stb-tester.com'])
subprocess.check_call(['git', 'config', 'user.name', 'stbt-rig tests'])

# Make git push a noop
subprocess.check_call(['git', 'remote', 'add', 'origin', '.'])

with open(".stbt.conf", "w") as f:
f.write(dedent("""\
[test_pack]
Expand All @@ -62,13 +61,24 @@ def fixture_test_pack(tmpdir): # pylint: disable=unused-argument
subprocess.check_call(
['git', 'add', '.stbt.conf', 'moo', '.gitignore', 'tests/test.py'])
subprocess.check_call(['git', 'commit', '-m', 'Test'])
subprocess.check_call(['git', 'push', '-u', 'origin', 'master:mybranch'])

return stbt_rig.TestPack()


def test_testpack_snapshot_no_change_if_no_commits(test_pack):
with assert_status_unmodified():
assert rev_parse("HEAD") == test_pack.take_snapshot()
commit_sha, run_sha = test_pack.take_snapshot()
assert rev_parse("HEAD") == run_sha
assert tree_sha(commit_sha) == tree_sha(run_sha)
assert commit_msg(commit_sha) == (
"snapshot\n\nremoteref: refs/heads/mybranch")

# Check that the SHA is deterministic:
time.sleep(1)
new_commit_sha, new_run_sha = test_pack.take_snapshot()
assert new_commit_sha == commit_sha
assert new_run_sha == run_sha


@contextmanager
Expand All @@ -89,15 +99,26 @@ def rev_parse(revision):
['git', 'rev-parse', '--verify', revision])).strip()


def tree_sha(revision):
return to_unicode(subprocess.check_output(
['git', 'show', '--format=%T', '--no-patch', revision])).strip()


def commit_msg(revision):
return to_unicode(subprocess.check_output(
['git', 'show', '--format=%s\n\n%b', '--no-patch', revision])).strip()


def test_testpack_snapshot_contains_modifications(test_pack):
with open("moo", "w") as f:
f.write("Goodbye!\n")

with assert_status_unmodified():
ss = test_pack.take_snapshot()
assert ss != rev_parse("HEAD")
assert rev_parse("%s~1" % ss) == rev_parse("HEAD")
assert cat(ss, 'moo') == "Goodbye!\n"
cs, rs = test_pack.take_snapshot()
assert cs == rs
assert rs != rev_parse("HEAD")
assert rev_parse("%s~1" % rs) == rev_parse("HEAD")
assert cat(rs, 'moo') == "Goodbye!\n"
assert cat("HEAD", 'moo') == "Hello!\n"


Expand All @@ -108,9 +129,10 @@ def test_testpack_snapshot_with_untracked_files(test_pack, capsys):

with assert_status_unmodified():
orig_sha = rev_parse("HEAD")
ss = test_pack.take_snapshot()
cs, rs = test_pack.take_snapshot()
# Untracked files aren't included in the snapshot:
assert orig_sha == ss
assert orig_sha == rs
assert tree_sha(cs) == tree_sha(orig_sha)

assert capsys.readouterr() == ("", dedent("""\
stbt-rig: Warning: Ignoring untracked files:
Expand Down

0 comments on commit 81bd323

Please sign in to comment.