def test_simple_release(d, repo): banner('TEST SIMPLE RELEASE') banner('Check out build tree, and stamp it as a release', 2) with NewCountedDirectory('build1') as build1: r = 'git+file://{repo}/main'.format(repo=repo) d = 'builds/01.py' v = '{root}/versions'.format(root=r) muddle(['init', r, d]) muddle(['checkout', '_all']) muddle(['stamp', 'release', 'simple', 'v1.0']) rfile = os.path.join(build1.where, 'versions', 'simple_v1.0.release') check_release_file_starts(rfile, 'simple', 'v1.0', 'tar', 'gzip', r, d, v) UNSET = '(unset)' muddle_env = read_env_as_dict('first_pkg{x86}') if not (muddle_env['MUDDLE_RELEASE_NAME'] == UNSET and muddle_env['MUDDLE_RELEASE_VERSION'] == UNSET and muddle_env['MUDDLE_RELEASE_HASH'] == UNSET): print 'MUDDLE_RELEASE_NAME=%s' % muddle_env['MUDDLE_RELEASE_NAME'] print 'MUDDLE_RELEASE_VERSION=%s' % muddle_env[ 'MUDDLE_RELEASE_VERSION'] print 'MUDDLE_RELEASE_HASH=%s' % muddle_env['MUDDLE_RELEASE_HASH'] raise GiveUp( 'Expected the MUDDLE_RELEASE_ values to be all (unset)') banner('Try "muddle release" using that stamp', 2) with NewCountedDirectory('build2') as build2: muddle(['release', rfile]) check_release_directory(build2)
def test_unstamp_update_2(repo, first_stamp): """Test the "unstamp -update" operation a bit more """ banner('TESTING UNSTAMP -UPDATE -- TEST 2') with NewCountedDirectory('build5') as d: muddle([ 'init', 'git+file://{repo}/main'.format(repo=repo), 'builds/01.py' ]) muddle(['checkout', '_all']) old_revisions = capture_revisions() # Make some amdendments and check them in with Directory('src'): with Directory('first_co'): append('Makefile.muddle', '\n# A comment\n') git('commit Makefile.muddle -m "Add a comment"') muddle(['push']) with Directory('second_co'): append('Makefile.muddle', '\n# A comment\n') bzr('commit Makefile.muddle -m "Add a comment"') muddle(['push']) with Directory('domains'): with Directory('subdomain1'): with Directory('src'): with Directory('builds'): append('01.py', '\n# A comment\n') git('commit 01.py -m "Add a comment"') muddle(['push']) new_revisions = capture_revisions() # Keep this state for later on muddle(['stamp', 'save', 'new_state.stamp']) # Revert to the original muddle(['unstamp', '-update', first_stamp]) current_revisions = capture_revisions() if revisions_differ(current_revisions, old_revisions): raise GiveUp('Update back to original failed') # And back (forwards) again muddle(['unstamp', '-update', 'new_state.stamp']) current_revisions = capture_revisions() if revisions_differ(current_revisions, new_revisions): raise GiveUp('Update forward again failed') # One of the points of using "muddle pull" internally in the # "muddle unstamp -update" command is that we want our "just pulled" # list to be available. So check that. just_pulled = read_just_pulled() if just_pulled != set([ 'checkout:first_co/checked_out', 'checkout:second_co/checked_out', 'checkout:(subdomain1)builds/checked_out' ]): print 'Read _just_pulled as:' print just_pulled raise GiveUp('Just pulled list does not match')
def test_stamping_branches(repo): """Test we cope with branches. """ banner('TESTING STAMPING BRANCHES') with NewCountedDirectory('build6') as d: muddle([ 'init', 'git+file://{repo}/main'.format(repo=repo), 'builds/01.py' ]) muddle(['checkout', '_all']) with Directory('src'): with Directory('first_co'): git('checkout -b branch1') muddle(['push']) muddle(['stamp', 'save', '01.stamp']) with NewCountedDirectory('build7'): muddle(['unstamp', d.join('01.stamp')]) # We should have got the branch for first_co, even though it's not # the branch in the build description # Check we're working with the expected branches text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "first_co branch1 <none> <not following>", "main_co master <none> <not following>", "second_co <not supported> ... ...", "(subdomain1)builds master <none> <not following>", "(subdomain1)first_co master <none> <not following>", "(subdomain1)main_co master <none> <not following>", "(subdomain1)second_co master <none> <not following>", "(subdomain1(subdomain3))builds master <none> <not following>", "(subdomain1(subdomain3))first_co master <none> <not following>", "(subdomain1(subdomain3))main_co master <none> <not following>", "(subdomain1(subdomain3))second_co master <none> <not following>", "(subdomain2)builds master <none> <not following>", "(subdomain2)first_co master <none> <not following>", "(subdomain2)main_co master <none> <not following>", "(subdomain2)second_co master <none> <not following>" ], fold_whitespace=True)
def test_stamp_is_current_working_set(first_stamp): """Check we are stamping the current working set """ with NewCountedDirectory('build3') as d2: banner('TESTING STAMP CURRENT WORKING SET') muddle(['unstamp', first_stamp]) # So, we've selected specific revisions for all of our checkouts # and thus they are all in "detached HEAD" state revisions = capture_revisions() # XXX To be considered XXX # Here, we are deliberately making a change that we do not push to the # remote repository. Thus our stamp file will contain a revision id # that no-one else can make sense of. This may be a Bad Thing. # Indeed, if we try to do this with a bzr repository, our own code # in 'muddle query checkout-id' would use 'bzr missing' and notice that # the revision was not present at the far end, and give up with a # complaint at that point. with Directory('src'): with Directory('first_co'): append('Makefile.muddle', '\n# A comment\n') git('commit Makefile.muddle -m "Add a comment"') # Don't forget that ".strip()" to remove the trailing newline! first_co_rev2 = captured_muddle(['query', 'checkout-id', 'first_co']).strip() if first_co_rev2 == revisions['first_co']: raise GiveUp('The revision of first_co did not change') revisions['first_co'] = first_co_rev2 muddle(['stamp', 'save', 'amended.stamp']) stamp = VersionStamp.from_file('amended.stamp') if len(stamp.checkouts) != len(revisions): raise GiveUp('Stamp file has %d checkouts, build tree %d' % (len(stamp.checkouts), len(revisions))) for co in stamp.checkouts: if co.domain: dom_plus_name = '(%s)%s' % (co.domain, co.name) else: dom_plus_name = co.name repo = stamp.checkouts[co][ -1] # ah, named tuples would be good here #print dom_plus_name #print ' S:',repo.revision #print ' D:',revisions[dom_plus_name] if repo.revision != revisions[dom_plus_name]: raise GiveUp( 'Checkout %s is revision %s in stamp file,' ' %s on disk' % (dom_plus_name, repo.revision, revisions[dom_plus_name]))
def test_builds_bad_upstream_2(root): with NewCountedDirectory('builds_bad_upstream_2') as d: banner( 'CHECK REPOSITORIES OUT (BAD UPSTREAM 2) illegal upstream names') text = captured_muddle([ 'init', 'git+file://{repo}/main'.format(repo=root.join('repo')), 'builds_bad_upstream_2/01.py' ], error_fails=False) check_text_endswith( text, """\ GiveUp: Upstream repository name '$@~#sausage' is not allowed """.format(root_dir=root.where))
def test_stamp_unstamp(root_dir): """Simple test of stamping and then unstamping Returns the path to the stamp file it creates """ banner('TEST BASIC STAMP AND UNSTAMP') with NewCountedDirectory('build') as d: banner('CHECK REPOSITORIES OUT', 2) checkout_build_descriptions(root_dir, d) muddle(['checkout', '_all']) check_checkout_files(d) banner('STAMP', 2) muddle(['stamp', 'version']) first_stamp = os.path.join(d.where, 'versions', '01.stamp') with NewCountedDirectory('build2') as d2: banner('UNSTAMP', 2) muddle(['unstamp', os.path.join(d.where, 'versions', '01.stamp')]) check_checkout_files(d2) return first_stamp
def test_issue_249_single_digit_version_number(d, repo): banner('TEST ISSUE 249') banner('Check out build tree, and stamp it as release version 1', 2) with NewCountedDirectory('build.version-number') as build: r = 'git+file://{repo}/main'.format(repo=repo) d = 'builds/01.py' v = '{root}/versions'.format(root=r) muddle(['init', r, d]) muddle(['checkout', '_all']) muddle(['stamp', 'release', 'simple', '1']) with Directory('versions'): check_specific_files_in_this_dir(['.git', 'simple_1.release']) check_release_file_starts('simple_1.release', 'simple', '1', 'tar', 'gzip', r, d, v)
def test_unstamp_update_identity_operation(repo, first_stamp): """Test the "unstamp -update" identity operation """ banner('TESTING UNSTAMP -UPDATE -- TEST 1 (IDENTITY)') with NewCountedDirectory('build4') as d2: muddle([ 'init', 'git+file://{repo}/main'.format(repo=repo), 'builds/01.py' ]) muddle(['checkout', '_all']) old_revisions = capture_revisions() # And check the "null" operation muddle(['unstamp', '-update', first_stamp]) new_revisions = capture_revisions() if revisions_differ(old_revisions, new_revisions): raise GiveUp('Null update changed stuff!') else: print 'The tree was not changed by the "null" update'
def test_builds_ok_upstream_3(root): with NewCountedDirectory('builds_ok_upstream_3') as d: banner( 'CHECK REPOSITORIES OUT (OK UPSTREAM 3) subdomain has extra upstream names' ) muddle([ 'init', 'git+file://{repo}/main'.format(repo=root.join('repo')), 'builds_ok_upstream_3/01.py' ]) text = captured_muddle(['query', 'upstream-repos']) check_text_endswith( text, """\ > Upstream repositories .. Repository('git', 'file://{root_dir}/repo/main', 'repo1') used by checkout:co_repo1/*, checkout:(subdomain_ok_upstream_3)co_repo1/* Repository('git', 'file://{root_dir}/repo/main', 'repo1.1') rhubarb, wombat Repository('git', 'file://{root_dir}/repo/main', 'repo1.2', push=False) insignificance, manhattan, platypus, wombat Repository('git', 'file://{root_dir}/repo/main', 'repo1.3', pull=False) platypus, rhubarb Repository('git', 'http://example.com', 'repo99') Repository('git', 'http://example.com', 'repo99-upstream') abacus """.format(root_dir=root.where))
def test_builds_bad_upstream_1(root): with NewCountedDirectory('builds_bad_upstream_1') as d: banner( 'CHECK REPOSITORIES OUT (BAD UPSTREAM 1) subdomain has extra upstreams' ) text = captured_muddle([ 'init', 'git+file://{repo}/main'.format(repo=root.join('repo')), 'builds_bad_upstream_1/01.py' ], error_fails=False) check_text_endswith( text, """\ Subdomain subdomain_bad_upstream_1 adds a new upstream to Repository('git', 'file://{root_dir}/repo/main', 'repo1') (used by checkout:co_repo1/*, checkout:(subdomain_bad_upstream_1)co_repo1/*) Original upstreams: Repository('git', 'file://{root_dir}/repo/main', 'repo1.1') rhubarb, wombat Repository('git', 'file://{root_dir}/repo/main', 'repo1.2', push=False) insignificance, wombat Repository('git', 'file://{root_dir}/repo/main', 'repo1.3', pull=False) platypus, rhubarb Subdomain subdomain_bad_upstream_1 has: Repository('git', 'file://{root_dir}/repo/main', 'repo1.X') fruitbat, rhubarb, wombat """.format(root_dir=root.where))
def test_lifecycle(root_d): """A linear sequence of plausible actions... """ # Repositories with NewCountedDirectory('repos') as d0: with NewDirectory('builds'): git('init --bare') with NewDirectory('co1'): git('init --bare') with NewDirectory('versions'): git('init --bare') repo_url = 'git+file://%s' % d0.where build_name = 'TestBuild' # First build tree with NewCountedDirectory('build1') as d1: muddle(['bootstrap', repo_url, build_name]) with Directory('src'): with Directory('builds'): os.remove('01.py') os.remove('01.pyc') touch('01.py', BUILD_DESC.format(build_name=build_name)) git('add 01.py' ) # Because we changed it since the last 'git add' git('commit -m "First commit of build description"') muddle(['push']) with NewDirectory('co1'): touch('Makefile.muddle', MUDDLE_MAKEFILE) git('init') git('add Makefile.muddle') git('commit Makefile.muddle -m "A checkout needs a makefile"') muddle(['import']) muddle(['push']) muddle(['stamp', 'version']) with Directory('versions'): check_specific_files_in_this_dir(['.git', 'TestBuild.stamp']) git('add TestBuild.stamp') git('commit -m "First stamp"') muddle(['stamp', 'push']) builds_rev_1 = captured_muddle(['query', 'checkout-id', 'builds']).strip() checkout_rev_1 = captured_muddle(['query', 'checkout-id', 'co1']).strip() # Add some more revisions, so we have something to work with with Directory('src'): with Directory('builds'): append('01.py', '# Additional comment number 1\n') git('add 01.py') git('commit -m "Add comment number 1"') builds_rev_2 = captured_muddle(['query', 'checkout-id']).strip() append('01.py', '# Additional comment number 2\n') git('commit -a -m "Add comment number 2"') builds_rev_3 = captured_muddle(['query', 'checkout-id']).strip() muddle(['push']) with Directory('co1'): append('Makefile.muddle', '# Additional comment number 1\n') git('add Makefile.muddle') git('commit -m "Add comment number 1"') checkout_rev_2 = captured_muddle(['query', 'checkout-id']).strip() append('Makefile.muddle', '# Additional comment number 2\n') git('commit -a -m "Add comment number 2"') checkout_rev_3 = captured_muddle(['query', 'checkout-id']).strip() muddle(['push']) # Find out what branches we are working with text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "co1 master <none> <not following>" ], fold_whitespace=True) print 'builds/' print ' ', builds_rev_1 print ' ', builds_rev_2 print ' ', builds_rev_3 print 'co1/' print ' ', checkout_rev_1 print ' ', checkout_rev_2 print ' ', checkout_rev_3 # Second build tree, where the build description gives a specific revision # for a checkout. with NewCountedDirectory('build2') as d2: muddle(['init', repo_url, 'builds/01.py']) # But we want to specify the revision for our source checkout with Directory(d2.join('src', 'builds')): # Note we don't need to specify ALL of the SHA1 string, we can # just specify some non-ambiguous subset... touch( '01.py', BUILD_DESC_WITH_REVISION.format(revision=checkout_rev_2[:8], build_name=build_name)) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') muddle(['checkout', '_all']) check_revision('co1', checkout_rev_2) # If we attempt to 'muddle pull' in the checkout, that should fail # because we are already at the requested revision text = captured_muddle(['pull', 'co1'], error_fails=False).strip() if not text.endswith('checkout past the specified revision.'): raise GiveUp( 'Expected muddle pull to fail trying to go "past" revision:\n%s' % text) # Merging should behave just the same text = captured_muddle(['merge', 'co1'], error_fails=False).strip() if not text.endswith('checkout past the specified revision.'): raise GiveUp( 'Expected muddle pull to fail trying to go "past" revision:\n%s' % text) # What if the checkout is at the wrong revision? (e.g., someone used # git explicitly to change it, or equally we changed the build description # itself). # All muddle can really do is go to the revision specified in the # build description... with Directory(d2.join('src', 'co1')): git('checkout %s' % checkout_rev_1) muddle(['pull']) check_revision('co1', checkout_rev_2) git('checkout %s' % checkout_rev_1) muddle(['merge']) check_revision('co1', checkout_rev_2) # What if we try to do work on that specified revision # (and, in git terms, at a detached HEAD) with Directory(d2.join('src', 'co1')): append('Makefile.muddle', '# Additional comment number 3\n') git('commit -a -m "Add comment number 3"') checkout_rev_4 = captured_muddle(['query', 'checkout-id']).strip() # We're not on a branch, so that commit is likely to get lost, # so we'd better allow the user ways of being told that # - muddle status should say something rc, text = captured_muddle2(['status']) if 'Note that this checkout has a detached HEAD' not in text: raise GiveUp('Expected to be told checkout is in detached' ' HEAD state, instead got:\n%s' % text) # And trying to push should fail rc, text = captured_muddle2(['push']) text = text.strip() if 'This checkout is in "detached HEAD" state' not in text: raise GiveUp('Expected to be told checkout is in detached' ' HEAD state, instead got:\n%s' % text) print 'co1/' print ' ', checkout_rev_1 print ' ', checkout_rev_2 print ' ', checkout_rev_3 print ' ', checkout_rev_4 # So fix that by using a branch checkout_branch = 'this-is-a-branch' with Directory('src'): with Directory('builds'): touch( '01.py', BUILD_DESC_WITH_BRANCH.format(branch=checkout_branch, build_name=build_name)) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') with Directory('co1'): git('checkout -b %s' % checkout_branch) muddle(['status']) muddle(['push']) check_revision('co1', checkout_rev_4) # Find out what branches we are working with text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "co1 this-is-a-branch this-is-a-branch <not following>" ], fold_whitespace=True) # What happens if we specify a revision on a branch? # First, choose the revision before the branch with Directory('src'): with Directory('builds'): touch( '01.py', BUILD_DESC_WITH_REVISION.format(revision=checkout_rev_3, build_name=build_name)) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') with Directory('co1'): muddle(['status']) # Doing 'muddle pull' is the obvious way to get us back to # the right revision muddle(['pull']) check_revision('co1', checkout_rev_3) # Because we specified an exact revision, we should be detached if not is_detached_head(): raise GiveUp('Expected to have a detached HEAD') # Find out what branches we are working with text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "co1 <none> <none> <not following>" ], fold_whitespace=True) # Then the revision after the branch with Directory('src'): with Directory('builds'): touch( '01.py', BUILD_DESC_WITH_REVISION.format(revision=checkout_rev_4, build_name=build_name)) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') with Directory('co1'): # We're still on the old revision, and detached check_revision('co1', checkout_rev_3) # Because we specified an exact revision, we should be detached if not is_detached_head(): raise GiveUp('Expected to have a detached HEAD') rc, text = captured_muddle2(['status']) if 'Note that this checkout has a detached HEAD' not in text: raise GiveUp('Expected to be told checkout is in detached' ' HEAD state, instead got:\n%s' % text) # Doing 'muddle pull' is the obvious way to get us back to # the right revision muddle(['pull']) check_revision('co1', checkout_rev_4) # Because we specified an exact revision, we should be detached if not is_detached_head(): raise GiveUp('Expected to have a detached HEAD') # But what if we go to "the same place" by a different means? git('checkout %s' % checkout_branch) muddle(['status']) # We're still at the requested revision check_revision('co1', checkout_rev_4) # But we're no longer a detached HEAD if is_detached_head(): raise GiveUp('Surprised to have a detached HEAD') # muddle pull shouldn't need to do anything... text = captured_muddle(['pull'], error_fails=False).strip() if not text.endswith('checkout past the specified revision.'): raise GiveUp( 'Expected muddle pull to fail trying to go "past" revision:\n%s' % text) # Find out what branches we are working with text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "co1 this-is-a-branch <none> <not following>" ], fold_whitespace=True) # Third build tree, investigating use of "muddle branch-tree" with NewCountedDirectory('build3') as d3: muddle(['init', repo_url, 'builds/01.py']) muddle(['checkout', '_all']) # Check the branches of our checkouts check_branch('src/builds', 'master') check_branch('src/co1', 'master') # And change it muddle(['branch-tree', 'test-v0.1']) # Check the branches of our checkouts - since this isn't using muddle, # it should still show both at the new branch check_branch('src/builds', 'test-v0.1') check_branch('src/co1', 'test-v0.1') # Doing a "mudddle sync" on the checkout should put it back to the # master branch, as that's what is (implicitly) asked for in the # build description. It shouldn't affect the build description. muddle(['sync', 'co1']) check_branch('src/builds', 'test-v0.1') check_branch('src/co1', 'master') # If we amend the build description, though: print 'Setting build description for "follow my branch"' with Directory('src'): with Directory('builds'): append('01.py', ' builder.follow_build_desc_branch = True\n') # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') # and sync again, our checkout should now follow the build # description's branch muddle(['sync', 'co1']) check_branch('src/builds', 'test-v0.1') check_branch('src/co1', 'test-v0.1') # Let's commit and push... with Directory('src'): with Directory('builds'): git('commit -a -m "Branched"') muddle(['push']) with Directory('co1'): # We hadn't changed any files in our checkout muddle(['push']) # Find out what branches we are working with text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds test-v0.1 <none> <it's own>", "co1 test-v0.1 <none> test-v0.1" ], fold_whitespace=True) # And a variant like the documentation with NewCountedDirectory('build4') as d4: muddle(['init', repo_url, 'builds/01.py']) muddle(['checkout', '_all']) # And change it muddle(['branch-tree', 'Widget-v0.1-maintenance']) with Directory('src'): with Directory('builds'): append('01.py', ' builder.follow_build_desc_branch = True\n') # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') muddle([ 'runin', '_all_checkouts', 'git commit -a -m "Create maintenance branch"' ]) muddle(['push', '_all']) # Find out what branches we are working with text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds Widget-v0.1-maintenance <none> <it's own>", "co1 Widget-v0.1-maintenance <none> Widget-v0.1-maintenance" ], fold_whitespace=True) muddle(['stamp', 'version']) with Directory('versions'): check_specific_files_in_this_dir( ['.git', 'TestBuild.Widget-v0.1-maintenance.stamp']) with NewCountedDirectory('build4a') as d4a: muddle([ 'unstamp', d4.join('versions', 'TestBuild.Widget-v0.1-maintenance.stamp') ]) # Check we're working with the expected branches text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds Widget-v0.1-maintenance Widget-v0.1-maintenance <it's own>", "co1 Widget-v0.1-maintenance <none> Widget-v0.1-maintenance" ], fold_whitespace=True) muddle(['stamp', 'version']) with Directory('versions'): check_specific_files_in_this_dir( ['.git', 'TestBuild.Widget-v0.1-maintenance.stamp']) # And that stamp file should be identical to the one we had before # (if we ignore the first few lines with the timestamp comments) with open( d4.join('versions', 'TestBuild.Widget-v0.1-maintenance.stamp')) as fd: that = fd.readlines() with open( os.path.join('versions', 'TestBuild.Widget-v0.1-maintenance.stamp')) as fd: this = fd.readlines() check_text_lines_v_lines(actual_lines=this[3:], wanted_lines=that[3:]) with NewCountedDirectory('build5') as d5: muddle([ 'init', '-branch', 'Widget-v0.1-maintenance', repo_url, 'builds/01.py' ]) muddle(['checkout', '_all']) # Find out what branches we are working with text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds Widget-v0.1-maintenance Widget-v0.1-maintenance <it's own>", "co1 Widget-v0.1-maintenance <none> Widget-v0.1-maintenance" ], fold_whitespace=True) muddle(['stamp', 'version']) with Directory('versions'): check_specific_files_in_this_dir( ['.git', 'TestBuild.Widget-v0.1-maintenance.stamp']) # And that stamp file should also be identical to the one we had before # (if we ignore the first few lines with the timestamp comments) with open( d4.join('versions', 'TestBuild.Widget-v0.1-maintenance.stamp')) as fd: that = fd.readlines() with open( os.path.join('versions', 'TestBuild.Widget-v0.1-maintenance.stamp')) as fd: this = fd.readlines() check_text_lines_v_lines(actual_lines=this[3:], wanted_lines=that[3:]) # Now let's push a change with Directory('src'): with Directory('co1'): append('Makefile.muddle', '# This, this is not a change\n') git('commit Makefile.muddle -m "But a small thing"') muddle(['push']) co1_revision_id = captured_muddle(['query', 'checkout-id', 'co1']).strip() # And pull it elsewhere with Directory(d4a.join('src', 'co1')): old_revision_id = captured_muddle(['query', 'checkout-id']).strip() muddle(['pull']) new_revision_id = captured_muddle(['query', 'checkout-id']).strip() if old_revision_id == new_revision_id: raise GiveUp('Pull did nothing') if new_revision_id != co1_revision_id: raise GiveUp('Result of pull was unexpected\n' 'got: %s\nnot: %s' % (new_revision_id, co1_revision_id)) # And let's be really awkward... with Directory(d4.join('src', 'co1')): git('checkout master') rv, text = run2('git branch') check_text_v_lines(text, [' Widget-v0.1-maintenance', '* master']) old_revision_id = captured_muddle(['query', 'checkout-id']).strip() # We're fondly expecting "muddle pull" to put us back onto the # "following" branch muddle(['pull']) rv, text = run2('git branch') check_text_v_lines(text, ['* Widget-v0.1-maintenance', ' master']) new_revision_id = captured_muddle(['query', 'checkout-id']).strip() if old_revision_id == new_revision_id: raise GiveUp('Pull did nothing') if new_revision_id != co1_revision_id: raise GiveUp('Result of pull was unexpected\n' 'got: %s\nnot: %s' % (new_revision_id, co1_revision_id))
def test_branch_tree(root_d): """Test doing "muddle branch-tree". """ with NewCountedDirectory('branch-tree.repo') as d: repo = create_multiplex_repo('test-build') with Directory(repo): with Directory('co.fred'): co_fred_revision = captured_muddle(['query', 'checkout-id']).strip() with Directory('co.branch1.fred'): co_branch1_fred_revision = captured_muddle( ['query', 'checkout-id']).strip() with NewCountedDirectory('branch-tree.branch'): muddle([ 'init', '-branch', 'branch0', 'git+file://' + repo, 'builds/01.py' ]) muddle(['checkout', '_all']) # Our checkouts should be as in the build description check_branch('src/builds', 'branch0') check_branch('src/co1', 'master') check_branch('src/co.branch1', 'branch1') check_revision('co.fred', co_fred_revision) check_revision('co.branch1.fred', co_branch1_fred_revision) # This branch of the build description doesn't have co.bzr retcode, text = captured_muddle2(['branch-tree', 'test-v0.1']) if retcode != 1: raise GiveUp("Expected 'muddle branch-tree test-v0.1 to fail with" " retcode 1, got %d" % retcode) check_text_endswith( text, """\ Unable to branch-tree to test-v0.1, because: checkout:co.branch1.fred/checked_out explicitly specifies revision "fred" in the build description checkout:co.branch1/checked_out explicitly specifies branch "branch1" in the build description checkout:co.fred/checked_out explicitly specifies revision "fred" in the build description """) # OK, force it muddle(['branch-tree', '-f', 'test-v0.1']) # And those checkouts without explicit branch/revision should now be # branched check_branch('src/builds', 'test-v0.1') check_branch('src/co1', 'test-v0.1') check_branch('src/co.branch1', 'branch1') check_revision('co.fred', co_fred_revision) check_revision('co.branch1.fred', co_branch1_fred_revision) # But if we sync... muddle(['sync', '_all']) # We should undo that... check_branch('src/builds', 'branch0') check_branch('src/co1', 'master') check_branch('src/co.branch1', 'branch1') check_revision('co.fred', co_fred_revision) check_revision('co.branch1.fred', co_branch1_fred_revision) # Try again muddle(['branch-tree', '-f', 'test-v0.1']) check_branch('src/builds', 'test-v0.1') check_branch('src/co1', 'test-v0.1') check_branch('src/co.branch1', 'branch1') check_revision('co.fred', co_fred_revision) check_revision('co.branch1.fred', co_branch1_fred_revision) # Now amend the build description so things follow it with Directory('src'): with Directory('builds'): touch('01.py', NO_BZR_BUILD_DESC + FOLLOW_LINE) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') muddle(['sync', '-v', '_all']) # And this time, things should follow the build description if they're # allowed to check_branch('src/builds', 'test-v0.1') check_branch('src/co1', 'test-v0.1') check_branch('src/co.branch1', 'branch1') check_revision('co.fred', co_fred_revision) check_revision('co.branch1.fred', co_branch1_fred_revision) # If we make amendments to the checkouts that are "following", can # we push them? with Directory('src'): with Directory('builds'): append('01.py', '# This should make no difference\n') # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') git('commit -a -m "Add a comment at the end"') muddle(['push']) with Directory('co1'): append('Makefile.muddle', '# This should make no difference\n') git('commit -a -m "Add a comment at the end"') muddle(['push']) # Let's see if that took with NewCountedDirectory('branch-tree.cloned'): muddle([ 'init', '-branch', 'test-v0.1', 'git+file://' + repo, 'builds/01.py' ]) muddle(['checkout', '_all']) check_branch('src/builds', 'test-v0.1') check_branch('src/co1', 'test-v0.1') check_branch('src/co.branch1', 'branch1') check_revision('co.fred', co_fred_revision) check_revision('co.branch1.fred', co_branch1_fred_revision) with Directory('src'): with Directory('builds'): with open('01.py') as fd: text = fd.read() check_text_endswith(text, '# This should make no difference\n') with Directory('co1'): with open('Makefile.muddle') as fd: text = fd.read() check_text_endswith(text, '# This should make no difference\n') # And another variation with NewCountedDirectory('branch-tree.cloned'): muddle([ 'init', '-branch', 'branch.follow', 'git+file://' + repo, 'builds/01.py' ]) muddle(['checkout', '_all']) check_branch('src/builds', 'branch.follow') check_branch('src/co1', 'branch.follow') check_branch('src/co.branch1', 'branch1') check_revision('co.fred', co_fred_revision) check_revision('co.branch1.fred', co_branch1_fred_revision) muddle(['branch-tree', '-f', 'test-v0.1']) with Directory('src'): with Directory('builds'): with open('01.py') as fd: text = fd.read() check_text_endswith(text, '# This should make no difference\n') with Directory('co1'): with open('Makefile.muddle') as fd: text = fd.read() check_text_endswith(text, '# This should make no difference\n')
def test_init_with_branch(root_d): """Test muddle init: * without a branch name * with a branch name, but not following the build description * with a branch name, and following the build description """ with NewCountedDirectory('init.branch.repo') as d: repo = create_multiplex_repo('test-build') with NewCountedDirectory('init.with.no.branch'): muddle(['init', 'git+file://' + repo, 'builds/01.py']) muddle(['checkout', '_all']) with Directory('src'): with Directory('builds'): check_file_v_text('01.py', EMPTY_BUILD_DESC) # And our empty build description should not have checked any # of our checkouts out for name in ('co1', 'co.branch1', 'co.fred', 'co.branch1.fred'): if os.path.isdir(name): raise GiveUp('Unexpectedly found "%s" directory' % name) with NewCountedDirectory('init.with.branch1.no.follow'): muddle([ 'init', '-branch', 'branch1', 'git+file://' + repo, 'builds/01.py' ]) muddle(['checkout', '_all']) with Directory('src'): with Directory('builds'): check_file_v_text('01.py', NONFOLLOW_BUILD_DESC) # The build description did not ask us to follow it with Directory('co1'): # -- root check_specific_files_in_this_dir(['.git', 'Makefile.muddle']) check_file_v_text('Makefile.muddle', MUDDLE_MAKEFILE) with Directory('co.branch1'): # -- branch1 check_specific_files_in_this_dir( ['.git', 'Makefile.muddle', 'README.txt']) check_file_v_text('Makefile.muddle', MUDDLE_MAKEFILE) check_file_v_text('README.txt', EMPTY_README_TEXT) with Directory('co.fred'): # Revision 'fred' == tag on branch 'branch.follow' check_specific_files_in_this_dir( ['.git', 'Makefile.muddle', 'README.txt', 'program3.c']) check_file_v_text('Makefile.muddle', MUDDLE_MAKEFILE) check_file_v_text('README.txt', EMPTY_README_TEXT) check_file_v_text('program3.c', EMPTY_C_FILE) # If we attempt to 'muddle pull' in the checkout, that should # fail because we are already at the requested revision # (even though that revision was specified as a tag) text = captured_muddle(['pull', 'co.fred'], error_fails=False).strip() if not text.endswith('checkout past the specified revision.'): raise GiveUp( 'Expected muddle pull to fail trying to go "past" revision:\n%s' % text) with Directory('co.branch1.fred'): # Revision 'fred' and branch 'branch1' - the revision wins # -- fred check_specific_files_in_this_dir( ['.git', 'Makefile.muddle', 'README.txt', 'program4.c']) check_file_v_text('Makefile.muddle', MUDDLE_MAKEFILE) check_file_v_text('README.txt', EMPTY_README_TEXT) check_file_v_text('program4.c', EMPTY_C_FILE) # If we attempt to 'muddle pull' in the checkout, that should # fail because we are already at the requested revision # (even though that revision was specified as a tag) text = captured_muddle(['pull', 'co.fred'], error_fails=False).strip() if not text.endswith('checkout past the specified revision.'): raise GiveUp( 'Expected muddle pull to fail trying to go "past" revision:\n%s' % text) with Directory('co.bzr'): # Since this is using bzr, we always get HEAD check_specific_files_in_this_dir( ['.bzr', 'Makefile.muddle', 'README.txt', 'program5.c']) check_file_v_text('Makefile.muddle', MUDDLE_MAKEFILE) check_file_v_text('README.txt', EMPTY_README_TEXT) check_file_v_text('program5.c', EMPTY_C_FILE) with NewCountedDirectory('init.branch.with.branch1.follow'): muddle([ 'init', '-branch', 'branch.follow', 'git+file://' + repo, 'builds/01.py' ]) muddle(['checkout', '_all']) with Directory('src'): with Directory('builds'): check_file_v_text('01.py', FOLLOW_BUILD_DESC) with Directory('co1'): # The build description asked us to follow it check_specific_files_in_this_dir( ['.git', 'Makefile.muddle', 'README.txt', 'program1.c']) check_file_v_text('Makefile.muddle', MUDDLE_MAKEFILE) check_file_v_text('README.txt', EMPTY_README_TEXT) check_file_v_text('program1.c', EMPTY_C_FILE) with NewCountedDirectory('init.branch.with.branch1.bzr.follow.error'): muddle([ 'init', '-branch', 'branch.follow', 'git+file://' + repo, 'builds/01.py' ]) # Now let us make the build description erroneous, by changing it so # that the Bazaar checkout is also required to follow the build # description with Directory('src'): with Directory('builds'): touch('01.py', NONFOLLOW_BUILD_DESC + FOLLOW_LINE) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') # And our checkout all should now fail... retcode, text = captured_muddle2(['checkout', '_all']) if retcode != 1: raise GiveUp( 'Expected retcode 1 from "muddle checkout _all", got %d' % retcode) check_text_endswith( text, """\ The build description wants checkouts to follow branch 'branch.follow', but checkout co.bzr uses VCS Bazaar for which we do not support branching. The build description should specify a revision for checkout co.bzr, or specify the 'no_follow' option. """) with NewCountedDirectory('init.branch.with.branch1.bzr.no_follow.option'): muddle([ 'init', '-branch', 'branch.follow', 'git+file://' + repo, 'builds/01.py' ]) # Now let us make a build description in which our Bazaar checkout # specifically says it should not follow the build description with Directory('src'): with Directory('builds'): touch('01.py', NO_BZR_BUILD_DESC + BZR_CO_NO_FOLLOW + FOLLOW_LINE) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') # And our checkout _all should now be OK... muddle(['checkout', '_all']) with NewCountedDirectory( 'init.branch.with.branch1.nobranch.follow.error') as d: muddle([ 'init', '-branch', 'branch.follow', 'git+file://' + repo, 'builds/01.py' ]) # Now let us make the build description erroneous, by changing it so # that we have co6, which does not have branch branch.follow # description with Directory('src'): with Directory('builds'): touch('01.py', FOLLOW_BUILD_DESC + CO6_WHICH_HAS_NO_BRANCH_FOLLOW) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') # And our checkout all should now fail... retcode, text = captured_muddle2(['checkout', '_all']) if retcode != 1: raise GiveUp( 'Expected retcode 1 from "muddle checkout _all", got %d' % retcode) # The error text we get isn't particularly friendly, but should do check_text_endswith( text, """\ Cloning into 'co6'... fatal: Remote branch branch.follow not found in upstream origin fatal: The remote end hung up unexpectedly Failure checking out checkout:co6/checked_out in {where}/src: Command 'git clone -b branch.follow file://{repo}/co6 co6' failed with retcode 128 """.format(where=d.where, repo=repo))
def main(args): keep = False if args: if len(args) == 1 and args[0] == '-keep': keep = True else: print __doc__ raise GiveUp('Unexpected arguments %s' % ' '.join(args)) # Working in a local transient directory seems to work OK # although if it's anyone other than me they might prefer # somewhere in $TMPDIR... root_dir = normalise_dir(os.path.join(os.getcwd(), 'transient')) with TransientDirectory(root_dir, keep_on_error=True, keep_anyway=keep) as root_d: banner('MAKE REPOSITORIES') make_repos_with_subdomain(root_dir) with NewCountedDirectory('build.original') as d1: banner('CHECK REPOSITORIES OUT INTO FIRST BUILD') checkout_build_descriptions(root_dir, d1) muddle(['checkout', '_all']) orig_dir = d1.where banner('TEST A SIMPLE CHANGE') # With an insignificant change, this should work identically by # both mechanisms with NewCountedDirectory('build.simple.noreload.pull') as d2: banner('CHECK REPOSITORIES OUT', 2) checkout_build_descriptions(root_dir, d2) muddle(['checkout', '_all']) pass1_noreload_dir = d2.where with NewCountedDirectory('build.simple.default.pull') as d3: banner('CHECK REPOSITORIES OUT', 2) checkout_build_descriptions(root_dir, d3) muddle(['checkout', '_all']) pass1_default_dir = d3.where with Directory(orig_dir) as d: banner('AMEND SUB1 BUILD DESCRIPTION AND PUSH', 2) amend_sub1_build_desc_and_push(root_dir, d) with Directory(pass1_noreload_dir) as d: banner('PULL IN THE ORIGINAL MANNER', 2) muddle(['pull', '-noreload', '_all']) check_original_build_descs(d) check_file_v_text(d.join('.muddle', '_just_pulled'), [ 'checkout:(sub1)builds/checked_out\n', ]) with Directory(pass1_default_dir) as d: banner('PULL WITH BUILD DESCRIPTIONS PULLED FIRST', 2) muddle(['pull', '_all']) check_original_build_descs(d) check_file_v_text(d.join('.muddle', '_just_pulled'), [ 'checkout:(sub1)builds/checked_out\n', ]) banner('TEST A MORE COMPLICATED CHANGE') # Since we're changing the layout of the build, this should # work substantially differently by the two mechanisms with NewCountedDirectory('build.swap.noreload.pull') as d2: banner('CHECK REPOSITORIES OUT', 2) checkout_build_descriptions(root_dir, d2) muddle(['checkout', '_all']) pass2_noreload_dir = d2.where with NewCountedDirectory('build.swap.default.pull') as d3: banner('CHECK REPOSITORIES OUT', 2) checkout_build_descriptions(root_dir, d3) muddle(['checkout', '_all']) pass2_default_dir = d3.where with Directory(orig_dir) as d: banner('SWAP SUBDOMAIN BUILD DESCRIPTIONS AND PUSH', 2) swap_subdomains_and_push(root_dir, d) with Directory(pass2_noreload_dir) as d: banner('PULL IN THE ORIGINAL MANNER', 2) banner('PULL THE FIRST', 3) muddle(['pull', '-noreload', '_all']) check_original_build_descs(d) check_file_v_text(d.join('.muddle', '_just_pulled'), [ 'checkout:(sub1)builds/checked_out\n', 'checkout:(sub2)builds/checked_out\n', ]) banner('PULL THE SECOND', 3) # Our *second* pull should bring us to the same place as the # single pull with the "slow" mechanism would achieve. # # Note that it shouldn't matter where in the build tree we # do this command from... with Directory('src'): with Directory('builds'): muddle(['pull', '-noreload', '_all']) # We should have files following the amended build description check_amended_build_descs(d) # But we have not deleted the files from the original description check_original_build_descs(d) check_file_v_text(d.join('.muddle', '_just_pulled'), [ 'checkout:(sub1(sub4))co0/checked_out\n', 'checkout:(sub1(sub5))co0/checked_out\n', 'checkout:(sub2(sub3))co0/checked_out\n', ]) with Directory(pass2_default_dir) as d: banner('PULL WITH BUILD DESCRIPTIONS PULLED FIRST', 2) # Note that it shouldn't matter where in the build tree we # do this command from... with Directory('src'): with Directory('builds'): muddle(['pull', '_all']) # We should have files following the amended build description check_amended_build_descs(d) # But we have not deleted the files from the original description check_original_build_descs(d) check_file_v_text(d.join('.muddle', '_just_pulled'), [ 'checkout:(sub1)builds/checked_out\n', 'checkout:(sub1(sub4))builds/checked_out\n', 'checkout:(sub1(sub4))co0/checked_out\n', 'checkout:(sub1(sub5))builds/checked_out\n', 'checkout:(sub1(sub5))co0/checked_out\n', 'checkout:(sub2)builds/checked_out\n', 'checkout:(sub2(sub3))builds/checked_out\n', 'checkout:(sub2(sub3))co0/checked_out\n', ]) banner('TEST NOT CHANGING THE BUILD DESCRIPTIONS') # This should work identically by both mechanisms with NewCountedDirectory('build.nodesc.noreload.pull') as d2: banner('CHECK REPOSITORIES OUT', 2) checkout_amended_build_descriptions(root_dir, d2) muddle(['checkout', '_all']) pass3_noreload_dir = d2.where with NewCountedDirectory('build.nodesc.default.pull') as d3: banner('CHECK REPOSITORIES OUT', 2) checkout_amended_build_descriptions(root_dir, d3) muddle(['checkout', '_all']) pass3_default_dir = d3.where with Directory(orig_dir) as d: banner('CHANGE SOMETHING NOT A BUILD DESCRIPTION AND PUSH', 2) change_something_else_and_push(root_dir, d) with Directory(pass3_noreload_dir) as d: banner('PULL IN THE ORIGINAL MANNER', 2) muddle(['pull', '-noreload', '_all']) check_amended_build_descs(d) check_file_v_text(d.join('.muddle', '_just_pulled'), [ 'checkout:(sub1)co0/checked_out\n', ]) with Directory(pass3_default_dir) as d: banner('PULL WITH BUILD DESCRIPTIONS PULLED FIRST', 2) muddle(['pull', '_all']) check_amended_build_descs(d) check_file_v_text(d.join('.muddle', '_just_pulled'), [ 'checkout:(sub1)co0/checked_out\n', ])
def test_guess_version_number(d, repo): banner('TEST GUESS VERSION NUMBER') banner('Check out build tree, and stamp it as a release', 2) with NewCountedDirectory('build.version-number') as build1: r = 'git+file://{repo}/main'.format(repo=repo) d = 'builds/01.py' v = '{root}/versions'.format(root=r) muddle(['init', r, d]) muddle(['checkout', '_all']) muddle(['stamp', 'release', 'simple', '-next']) with Directory('versions'): check_specific_files_in_this_dir(['.git', 'simple_v0.0.release']) touch('versions/simple_v0.01.release', '') muddle(['stamp', 'release', 'simple', '-next']) with Directory('versions'): check_specific_files_in_this_dir([ '.git', 'simple_v0.0.release', 'simple_v0.01.release', 'simple_v0.2.release', ]) # Whilst 0.03 and 0.3 are "the same" version, that doesn't matter # if they already exist - we only care about the next version touch('versions/simple_v0.3.release', '') touch('versions/simple_v0.03.release', '') muddle(['stamp', 'release', 'simple', '-next']) with Directory('versions'): check_specific_files_in_this_dir([ '.git', 'simple_v0.0.release', 'simple_v0.01.release', 'simple_v0.2.release', 'simple_v0.03.release', 'simple_v0.3.release', 'simple_v0.03.release', 'simple_v0.4.release', ]) # We require major.minor, not any other variation - we won't # take notice of a file that doesn't match touch('versions/simple_v3.release', '') muddle(['stamp', 'release', 'simple', '-next']) with Directory('versions'): check_specific_files_in_this_dir([ '.git', 'simple_v0.0.release', 'simple_v0.01.release', 'simple_v0.2.release', 'simple_v0.03.release', 'simple_v0.3.release', 'simple_v0.03.release', 'simple_v0.4.release', 'simple_v0.5.release', 'simple_v3.release', ]) touch('versions/simple_v3.1.1.release', '') muddle(['stamp', 'release', 'simple', '-next']) with Directory('versions'): check_specific_files_in_this_dir([ '.git', 'simple_v0.0.release', 'simple_v0.01.release', 'simple_v0.2.release', 'simple_v0.03.release', 'simple_v0.3.release', 'simple_v0.03.release', 'simple_v0.4.release', 'simple_v0.5.release', 'simple_v0.6.release', 'simple_v3.release', 'simple_v3.1.1.release', ]) touch('versions/simple_v1.999999999.release', '') muddle(['stamp', 'release', 'simple', '-next']) with Directory('versions'): check_specific_files_in_this_dir([ '.git', 'simple_v0.0.release', 'simple_v0.01.release', 'simple_v0.2.release', 'simple_v0.03.release', 'simple_v0.3.release', 'simple_v0.03.release', 'simple_v0.4.release', 'simple_v0.5.release', 'simple_v0.6.release', 'simple_v3.release', 'simple_v3.1.1.release', 'simple_v1.999999999.release', 'simple_v1.1000000000.release', ])
def main(args): keep = False if args: if len(args) == 1 and args[0] == '-keep': keep = True else: print __doc__ raise GiveUp('Unexpected arguments %s' % ' '.join(args)) # Working in a local transient directory seems to work OK # although if it's anyone other than me they might prefer # somewhere in $TMPDIR... root_dir = normalise_dir(os.path.join(os.getcwd(), 'transient')) with TransientDirectory(root_dir, keep_on_error=True, keep_anyway=keep) as root: banner('MAKE REPOSITORIES') make_repos(root_dir) with NewCountedDirectory('build') as d: banner('CHECK REPOSITORIES OUT') muddle([ 'init', 'git+file://{repo}/main'.format(repo=root.join('repo')), 'builds/01.py' ]) muddle(['checkout', '_all']) banner('BUILD') muddle([]) banner('STAMP VERSION') muddle(['stamp', 'version']) with Directory(g_UPSTREAMS['repo1.1']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master']) with Directory(g_UPSTREAMS['repo1.2']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master']) with Directory(g_UPSTREAMS['repo1.3']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master']) banner('CHECK USING UPSTREAMS') test_using_upstreams(root_dir) text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "co_repo1 master <none> <not following>", "(subdomain1)builds master <none> <not following>", "(subdomain1)co_repo1 master <none> <not following>", "(subdomain2)builds master <none> <not following>", "(subdomain2)co_repo1.1 master <none> <not following>" ], fold_whitespace=True) # What happens if we try to "follow" a subdomain? with Directory('domains'): with Directory('subdomain1'): with Directory('src'): with Directory('builds'): append( '01.py', ' builder.follow_build_desc_branch = True\n' ) # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') # It shouldn't make a difference - only the top-level build # description gets followed text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "co_repo1 master <none> <not following>", "(subdomain1)builds master <none> <not following>", "(subdomain1)co_repo1 master <none> <not following>", "(subdomain2)builds master <none> <not following>", "(subdomain2)co_repo1.1 master <none> <not following>" ], fold_whitespace=True) # Even if we branch that build description... with Directory('domains'): with Directory('subdomain1'): with Directory('src'): with Directory('builds'): git('branch Fred') text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds master <none> <not following>", "co_repo1 master <none> <not following>", "(subdomain1)builds master <none> <not following>", "(subdomain1)co_repo1 master <none> <not following>", "(subdomain2)builds master <none> <not following>", "(subdomain2)co_repo1.1 master <none> <not following>" ], fold_whitespace=True) banner('BRANCH TREE') muddle(['branch-tree', 'v1-maintenance']) print 'Setting build description for "follow my branch"' with Directory('src'): with Directory('builds'): append('01.py', ' builder.follow_build_desc_branch = True\n') # Then remove the .pyc file, because Python probably won't realise # that this new 01.py is later than the previous version os.remove('01.pyc') text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds v1-maintenance <none> <it's own>", "co_repo1 v1-maintenance <none> v1-maintenance", "(subdomain1)builds v1-maintenance <none> v1-maintenance", "(subdomain1)co_repo1 v1-maintenance <none> v1-maintenance", "(subdomain2)builds v1-maintenance <none> v1-maintenance", "(subdomain2)co_repo1.1 v1-maintenance <none> v1-maintenance" ], fold_whitespace=True) muddle([ 'runin', '_all_checkouts', 'git commit -a -m "Create maintenance branch"' ]) muddle(['push', '_all']) # The push causes "(subdomain2)co_repo1.1" to push to our "repo1.1", # which it is using as its "local" repository, so we see our branch # already there with Directory(g_UPSTREAMS['repo1.1']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master', ' v1-maintenance']) with Directory(g_UPSTREAMS['repo1.2']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master']) with Directory(g_UPSTREAMS['repo1.3']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master']) with NewCountedDirectory('rebuild') as d: banner('CHECK REPOSITORIES OUT BRANCHED') muddle([ 'init', '-branch', 'v1-maintenance', 'git+file://{repo}/main'.format(repo=root.join('repo')), 'builds/01.py' ]) # The subdomain build descriptions should be following the # top level build description text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds v1-maintenance v1-maintenance <it's own>", "co_repo1 <can't tell> <none> v1-maintenance", "(subdomain1)builds v1-maintenance <none> v1-maintenance", "(subdomain1)co_repo1 <can't tell> <none> v1-maintenance", "(subdomain2)builds v1-maintenance <none> v1-maintenance", "(subdomain2)co_repo1.1 <can't tell> <none> v1-maintenance" ], fold_whitespace=True) muddle(['checkout', '_all']) text = captured_muddle(['query', 'checkout-branches']) lines = text.splitlines() lines = lines[3:] # ignore the header lines check_text_lines_v_lines(lines, [ "builds v1-maintenance v1-maintenance <it's own>", "co_repo1 v1-maintenance <none> v1-maintenance", "(subdomain1)builds v1-maintenance <none> v1-maintenance", "(subdomain1)co_repo1 v1-maintenance <none> v1-maintenance", "(subdomain2)builds v1-maintenance <none> v1-maintenance", "(subdomain2)co_repo1.1 v1-maintenance <none> v1-maintenance" ], fold_whitespace=True) # What happens if we push upstream? muddle(['push-upstream', 'co_repo1', '-u', 'rhubarb', 'platypus']) # That should succeed, as we're allowed to push to both of those # And now we should see our branch on repo1.3 as well with Directory(g_UPSTREAMS['repo1.1']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master', ' v1-maintenance']) with Directory(g_UPSTREAMS['repo1.2']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master']) with Directory(g_UPSTREAMS['repo1.3']): text = get_stdout('git branch -a') check_text_v_lines(text, ['* master', ' v1-maintenance']) # If we try to pull upstream from wombat, we should fail # as it does not have our branch retcode, text = captured_muddle2( ['pull-upstream', 'co_repo1', '-u', 'wombat']) if not retcode: raise GiveUp("Expected error trying to pull from wombat, but" " got %d:\n%s" % (retcode, text)) if "fatal: remotes/wombat/v1-maintenance - not something we can merge" not in text: raise GiveUp( "Expected error 'fatal: remotes/wombat/v1-maintenance" " - not something we can merge' trying to pull from" " wombat, but got:\n%s" % text)