def test_triggers_webhooks(self): # Jobs trigger any relevant webhooks when they're enabled. self.useFixture(FeatureFixture({'code.git.webhooks.enabled': 'on'})) repository = self.factory.makeGitRepository() self.factory.makeGitRefs( repository, paths=['refs/heads/master', 'refs/tags/1.0']) hook = self.factory.makeWebhook( target=repository, event_types=['git:push:0.1']) job = GitRefScanJob.create(repository) paths = ('refs/heads/master', 'refs/tags/2.0') self.useFixture(GitHostingFixture(refs=self.makeFakeRefs(paths))) with dbuser('branchscanner'): JobRunner([job]).runAll() delivery = hook.deliveries.one() sha1 = lambda s: hashlib.sha1(s).hexdigest() self.assertThat( delivery, MatchesStructure( event_type=Equals('git:push:0.1'), payload=MatchesDict({ 'git_repository': Equals('/' + repository.unique_name), 'git_repository_path': Equals(repository.unique_name), 'ref_changes': Equals({ 'refs/tags/1.0': { 'old': {'commit_sha1': sha1('refs/tags/1.0')}, 'new': None}, 'refs/tags/2.0': { 'old': None, 'new': {'commit_sha1': sha1('refs/tags/2.0')}}, })}))) with dbuser(config.IWebhookDeliveryJobSource.dbuser): self.assertEqual( "<WebhookDeliveryJob for webhook %d on %r>" % ( hook.id, hook.target), repr(delivery))
def test_local(self): [ref] = self.factory.makeGitRefs() hosting_fixture = self.useFixture(GitHostingFixture(blob=b"foo")) self.assertEqual(b"foo", ref.getBlob("dir/file")) self.assertEqual([((ref.repository.getInternalPath(), "dir/file"), { "rev": ref.path })], hosting_fixture.getBlob.calls)
def createExampleGitMerge(self): """Create an example Git-based merge scenario. The actual diff work is done in turnip, and we have no turnip fixture as yet, so for the moment we just install a fake hosting client that will return a plausible-looking diff. """ bmp = self.factory.makeBranchMergeProposalForGit() source_sha1 = bmp.source_git_ref.commit_sha1 target_sha1 = bmp.target_git_ref.commit_sha1 patch = dedent("""\ diff --git a/foo b/foo index %s..%s 100644 --- a/foo +++ b/foo @@ -1,2 +1,7 @@ +<<<<<<< foo c +======= +d +>>>>>>> foo a +b """) % (target_sha1[:7], source_sha1[:7]) self.hosting_fixture = self.useFixture(GitHostingFixture(merge_diff={ "patch": patch, "conflicts": ["foo"], })) return bmp, source_sha1, target_sha1, patch
def test_git_to_git_import(self): # The repository page for a git-to-git-imported repository contains # a summary of the import details. self.useFixture(GitHostingFixture()) code_import = self.factory.makeCodeImport( rcs_type=RevisionControlSystems.GIT, target_rcs_type=TargetRevisionControlSystems.GIT) self.assertImportDetailsDisplayed( code_import, 'git-import-details', 'This repository is an import of the Git repository')
def test_logs_bad_ref_info(self): repository = self.factory.makeGitRepository() job = GitRefScanJob.create(repository) self.useFixture(GitHostingFixture(refs={"refs/heads/master": {}})) expected_message = ( 'Unconvertible ref refs/heads/master {}: ' 'ref info does not contain "object" key') with self.expectedLog(expected_message): with dbuser("branchscanner"): JobRunner([job]).runAll() self.assertEqual([], list(repository.refs))
def test_git_to_git_import_same_details(self): self.useFixture(GitHostingFixture()) code_import = self.factory.makeProductCodeImport( git_repo_url='git://git.example.com/fooix.git', target_rcs_type=TargetRevisionControlSystems.GIT) unique_name = code_import.target.unique_name user = login_celebrity('vcs_imports') code_import.updateFromData( {'review_status': CodeImportReviewStatus.FAILING}, user) transaction.commit() self.assertSameDetailsEmail( 'git://git.example.com/fooix.git', unique_name)
def test_run(self): # Running a job to reclaim space sends a request to the hosting # service. hosting_fixture = self.useFixture(GitHostingFixture()) name = "/~owner/+git/gone" path = "1" job = ReclaimGitRepositorySpaceJob.create(name, path) self.makeJobReady(job) [job] = list(ReclaimGitRepositorySpaceJob.iterReady()) with dbuser("branchscanner"): JobRunner([job]).runAll() self.assertEqual([(path,)], hosting_fixture.delete.extract_args())
def setUp(self): super(TestGitRefGetCommits, self).setUp() [self.ref] = self.factory.makeGitRefs() self.authors = [self.factory.makePerson() for _ in range(2)] with admin_logged_in(): self.author_emails = [ author.preferredemail.email for author in self.authors ] self.dates = [ datetime(2015, 1, 1, 0, 0, 0, tzinfo=pytz.UTC), datetime(2015, 1, 2, 0, 0, 0, tzinfo=pytz.UTC), ] self.sha1_tip = unicode(hashlib.sha1("tip").hexdigest()) self.sha1_root = unicode(hashlib.sha1("root").hexdigest()) self.log = [ { "sha1": self.sha1_tip, "message": "tip", "author": { "name": self.authors[0].display_name, "email": self.author_emails[0], "time": int(seconds_since_epoch(self.dates[1])), }, "committer": { "name": self.authors[1].display_name, "email": self.author_emails[1], "time": int(seconds_since_epoch(self.dates[1])), }, "parents": [self.sha1_root], "tree": unicode(hashlib.sha1("").hexdigest()), }, { "sha1": self.sha1_root, "message": "root", "author": { "name": self.authors[1].display_name, "email": self.author_emails[1], "time": int(seconds_since_epoch(self.dates[0])), }, "committer": { "name": self.authors[0].display_name, "email": self.author_emails[0], "time": int(seconds_since_epoch(self.dates[0])), }, "parents": [], "tree": unicode(hashlib.sha1("").hexdigest()), }, ] self.hosting_fixture = self.useFixture(GitHostingFixture(log=self.log))
def test_run(self): # Ensure the job scans the repository. repository = self.factory.makeGitRepository() job = GitRefScanJob.create(repository) paths = ("refs/heads/master", "refs/tags/1.0") author = repository.owner author_date_start = datetime(2015, 1, 1, tzinfo=pytz.UTC) author_date_gen = time_counter(author_date_start, timedelta(days=1)) self.useFixture(GitHostingFixture( refs=self.makeFakeRefs(paths), commits=self.makeFakeCommits(author, author_date_gen, paths))) with dbuser("branchscanner"): JobRunner([job]).runAll() self.assertRefsMatch(repository.refs, repository, paths) self.assertEqual("refs/heads/master", repository.default_branch)
def test_skips_code_import(self): self.useFixture(GitHostingFixture()) person = self.factory.makePerson() team = self.factory.makeTeam(members=[person]) code_imports = [ self.factory.makeCodeImport(registrant=person, target_rcs_type=target_rcs_type, owner=team) for target_rcs_type in (TargetRevisionControlSystems.BZR, TargetRevisionControlSystems.GIT) ] person_id = person.id account_id = person.account.id script = self.makeScript([six.ensure_str(person.name)]) with dbuser('launchpad'): self.runScript(script) self.assertRemoved(account_id, person_id) self.assertEqual(person, code_imports[0].registrant) self.assertEqual(person, code_imports[1].registrant)
def test_merge_detection_triggers_webhooks(self): self.useFixture(FeatureFixture( {BRANCH_MERGE_PROPOSAL_WEBHOOKS_FEATURE_FLAG: 'on'})) repository = self.factory.makeGitRepository() target, source = self.factory.makeGitRefs( repository, paths=['refs/heads/target', 'refs/heads/source']) bmp = self.factory.makeBranchMergeProposalForGit( target_ref=target, source_ref=source) hook = self.factory.makeWebhook( target=repository, event_types=['merge-proposal:0.1']) new_refs = { target.path: {'object': { 'sha1': '0' * 40, 'type': 'commit', }}, source.path: {'object': { 'sha1': source.commit_sha1, 'type': 'commit', }}, } new_merges = {source.commit_sha1: '0' * 40} self.useFixture(GitHostingFixture(refs=new_refs, merges=new_merges)) job = GitRefScanJob.create(repository) with dbuser('branchscanner'): JobRunner([job]).runAll() delivery = hook.deliveries.one() self.assertThat( delivery, MatchesStructure( event_type=Equals('merge-proposal:0.1'), payload=MatchesDict({ 'merge_proposal': Equals( canonical_url(bmp, force_local_path=True)), 'action': Equals('modified'), 'old': ContainsDict( {'queue_status': Equals('Work in progress')}), 'new': ContainsDict({'queue_status': Equals('Merged')}), }))) with dbuser(config.IWebhookDeliveryJobSource.dbuser): self.assertEqual( "<WebhookDeliveryJob for webhook %d on %r>" % ( hook.id, hook.target), repr(delivery))
def makeTargetGitServer(self): """Set up a target Git server that can receive imports.""" self.target_store = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, self.target_store) self.target_git_server = GitServer(self.target_store, use_server=True) self.target_git_server.start_server() self.addCleanup(self.target_git_server.stop_server) config_name = self.getUniqueString() config_fixture = self.useFixture( ConfigFixture(config_name, self.layer.config_fixture.instance_name)) setting_lines = [ "[codehosting]", "git_browse_root: %s" % self.target_git_server.get_url(""), "", "[launchpad]", "internal_macaroon_secret_key: some-secret", ] config_fixture.add_section("\n" + "\n".join(setting_lines)) self.useFixture(ConfigUseFixture(config_name)) self.useFixture(GitHostingFixture())
def test_local_by_url(self): # It's possible (though not encouraged) to retrieve files from # self-hosted repositories by URL. [ref] = self.factory.makeGitRefs() hosting_fixture = self.useFixture(GitHostingFixture(blob=b"foo")) https_ref = self.factory.makeGitRefRemote( repository_url=ref.repository.git_https_url, path=ref.path) anon_ref = self.factory.makeGitRefRemote(repository_url=urlutils.join( config.codehosting.git_anon_root, ref.repository.shortened_path), path=ref.path) self.assertEqual(b"foo", https_ref.getBlob("dir/file")) self.assertEqual(b"foo", anon_ref.getBlob("dir/file")) internal_path = ref.repository.getInternalPath() expected_calls = [ ((internal_path, "dir/file"), { "rev": ref.path }), ((internal_path, "dir/file"), { "rev": ref.path }), ] self.assertEqual(expected_calls, hosting_fixture.getBlob.calls)
def test_run(self): # The job requests builds and records the result. distroseries, processors = self.makeSeriesAndProcessors( ["avr2001", "sparc64", "x32"]) [git_ref] = self.factory.makeGitRefs() snap = self.factory.makeSnap( git_ref=git_ref, distroseries=distroseries, processors=processors) expected_date_created = get_transaction_timestamp(IStore(snap)) job = SnapRequestBuildsJob.create( snap, snap.registrant, distroseries.main_archive, PackagePublishingPocket.RELEASE, {"core": "stable"}) snapcraft_yaml = dedent("""\ architectures: - build-on: avr2001 - build-on: x32 """) self.useFixture(GitHostingFixture(blob=snapcraft_yaml)) with dbuser(config.ISnapRequestBuildsJobSource.dbuser): JobRunner([job]).runAll() now = get_transaction_timestamp(IStore(snap)) self.assertEmailQueueLength(0) self.assertThat(job, MatchesStructure( job=MatchesStructure.byEquality(status=JobStatus.COMPLETED), date_created=Equals(expected_date_created), date_finished=MatchesAll( GreaterThan(expected_date_created), LessThan(now)), error_message=Is(None), builds=AfterPreprocessing(set, MatchesSetwise(*[ MatchesStructure( build_request=MatchesStructure.byEquality(id=job.job.id), requester=Equals(snap.registrant), snap=Equals(snap), archive=Equals(distroseries.main_archive), distro_arch_series=Equals(distroseries[arch]), pocket=Equals(PackagePublishingPocket.RELEASE), channels=Equals({"core": "stable"})) for arch in ("avr2001", "x32")]))))
def test_run_failed(self): # A failed run sets the job status to FAILED and records the error # message. # The job requests builds and records the result. distroseries, processors = self.makeSeriesAndProcessors( ["avr2001", "sparc64", "x32"]) [git_ref] = self.factory.makeGitRefs() snap = self.factory.makeSnap( git_ref=git_ref, distroseries=distroseries, processors=processors) expected_date_created = get_transaction_timestamp(IStore(snap)) job = SnapRequestBuildsJob.create( snap, snap.registrant, distroseries.main_archive, PackagePublishingPocket.RELEASE, {"core": "stable"}) self.useFixture(GitHostingFixture()).getBlob.failure = ( CannotParseSnapcraftYaml("Nonsense on stilts")) with dbuser(config.ISnapRequestBuildsJobSource.dbuser): JobRunner([job]).runAll() now = get_transaction_timestamp(IStore(snap)) [notification] = self.assertEmailQueueLength(1) self.assertThat(dict(notification), ContainsDict({ "From": Equals(config.canonical.noreply_from_address), "To": Equals(format_address_for_person(snap.registrant)), "Subject": Equals( "Launchpad error while requesting builds of %s" % snap.name), })) self.assertEqual( "Launchpad encountered an error during the following operation: " "requesting builds of %s. Nonsense on stilts" % snap.name, notification.get_payload(decode=True)) self.assertThat(job, MatchesStructure( job=MatchesStructure.byEquality(status=JobStatus.FAILED), date_created=Equals(expected_date_created), date_finished=MatchesAll( GreaterThan(expected_date_created), LessThan(now)), error_message=Equals("Nonsense on stilts"), builds=AfterPreprocessing(set, MatchesSetwise())))
def test_git_to_git_import(self): # Test the email for a new git-to-git import. self.useFixture(GitHostingFixture()) eric = self.factory.makePerson(name='eric') fooix = self.factory.makeProduct(name='fooix') # Eric needs to be logged in for the mail to be sent. login_person(eric) self.factory.makeProductCodeImport( git_repo_url='git://git.example.com/fooix.git', branch_name=u'master', product=fooix, registrant=eric, target_rcs_type=TargetRevisionControlSystems.GIT) transaction.commit() msg = message_from_string(stub.test_emails[0][2]) self.assertEqual('code-import', msg['X-Launchpad-Notification-Type']) self.assertEqual('~eric/fooix/+git/master', msg['X-Launchpad-Branch']) self.assertEqual( 'A new git code import has been requested ' 'by Eric:\n' ' http://code.launchpad.dev/~eric/fooix/+git/master\n' 'from\n' ' git://git.example.com/fooix.git\n' '\n' '-- \nYou are getting this email because you are a member of the ' 'vcs-imports team.\n', msg.get_payload(decode=True))
def test_git_ref_links_to_snaps(self): self.useFixture(GitHostingFixture()) [ref] = self.factory.makeGitRefs() self.assertSnapsLink(ref, "2 snap packages", git_ref=ref)
def setUp(self): super(TestHasSnapsMenu, self).setUp() if self.needs_git_hosting_fixture: self.useFixture(GitHostingFixture())