def test_workon_feature_branch_success(self, mock_create_labbooks,
                                           snapshot):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        b1 = bm.create_branch("tester1")
        bm.workon_branch(bm.workspace_branch)

        assert bm.active_branch == 'gm.workspace-default'

        q = f"""
        mutation makeFeatureBranch {{
            workonExperimentalBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                branchName: "{b1}"
            }}) {{            
                labbook{{
                    name
                    description
                    availableBranchNames
                    activeBranchName
                }}
            }}
        }}
        """
        r = client.execute(q)
        assert 'errors' not in r
        r['data']['workonExperimentalBranch']['labbook'][
            'activeBranchName'] == 'gm.workspace-default.tester1'
        snapshot.assert_match(r)

        assert bm.active_branch == 'gm.workspace-default.tester1'
        assert lb.is_repo_clean
    def test_create_feature_branch_bad_name_fail(self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        bad_branch_names = [
            '', '_', 'Über-bad', 'xxx-xxx' * 40, 'cats_99', 'bad-', '-',
            '-bad', 'bad--bad', 'bad---bad--bad-bad', 'Nope', 'Nope99',
            'Nope-99', 'N&PE', 'n*ope', 'no;way', 'no:way',
            '<nope>-not-a-branch', 'Robert") DROP TABLE Students; --',
            "no way not a branch", ''.join(chr(x) for x in range(0, 78)),
            ''.join(chr(x) for x in range(0, 255)),
            chr(0) * 10,
            chr(0) * 10000
        ]

        for bad_name in bad_branch_names:
            q = f"""
            mutation makeFeatureBranch {{
                createExperimentalBranch(input: {{
                    owner: "{UT_USERNAME}",
                    labbookName: "{UT_LBNAME}",
                    branchName: "{bad_name}"
                }}) {{
                    newBranchName
                }}
            }}
            """
            r = client.execute(q)
            pprint.pprint(r)
            assert 'errors' in r
            assert bm.active_branch == bm.workspace_branch
            assert lb.is_repo_clean
 def helper_resolve_active_branch(self, labbook):
     active_branch_name = BranchManager(
         labbook=labbook, username=get_logged_in_username()).active_branch
     return LabbookRef(
         id=f"{self.owner}&{self.name}&None&{active_branch_name}",
         owner=self.owner,
         name=self.name,
         prefix=None,
         ref_name=active_branch_name)
    def test_merge_into_workspace_from_simple_success(self,
                                                      mock_create_labbooks,
                                                      snapshot):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        og_hash = lb.git.commit_hash
        b1 = bm.create_branch("test-branch")
        lb.makedir('code/sillydir1', create_activity_record=True)
        lb.makedir('code/sillydir2', create_activity_record=True)
        branch_hash = lb.git.commit_hash

        assert og_hash != branch_hash

        bm.workon_branch(bm.workspace_branch)
        assert lb.git.log(
        )[1]['commit'] == og_hash  # There is 1 extra commit due to sweep
        assert not os.path.exists(os.path.join(lb.root_dir, 'code/sillydir1'))

        merge_q = f"""
        mutation x {{
            mergeFromBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                otherBranchName: "{b1}"                
            }}) {{                
                labbook{{
                    name
                    description
                    availableBranchNames
                    activeBranchName
                }}
            }}
        }}
        """
        r = client.execute(merge_q)
        assert 'errors' not in r
        r['data']['mergeFromBranch']['labbook'][
            'activeBranchName'] == 'gm.workspace-default'
        snapshot.assert_match(r)

        assert lb.active_branch == bm.workspace_branch
        assert os.path.exists(os.path.join(lb.root_dir, 'code/sillydir1'))
        assert lb.is_repo_clean
    def test_conflicted_merge_from_force_success(self, mock_create_labbooks,
                                                 snapshot):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        with open('/tmp/s1.txt', 'w') as s1:
            s1.write('original-file\ndata')
        FileOperations.insert_file(lb, section='code', src_file=s1.name)
        bm = BranchManager(lb, username=UT_USERNAME)

        nb = bm.create_branch('new-branch')
        with open('/tmp/s1.txt', 'w') as s1:
            s1.write('branch-conflict-data')
        FileOperations.insert_file(lb, section='code', src_file=s1.name)

        bm.workon_branch(bm.workspace_branch)
        with open('/tmp/s1.txt', 'w') as s1:
            s1.write('mainline-conflict-data')
        FileOperations.insert_file(lb, section='code', src_file=s1.name)

        merge_q = f"""
        mutation x {{
            mergeFromBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                otherBranchName: "{nb}",
                force: true            
            }}) {{                         
                labbook{{
                    name
                    description
                    availableBranchNames
                    activeBranchName
                }}
            }}
        }}
        """
        r = client.execute(merge_q)
        assert 'errors' not in r
        snapshot.assert_match(r)
        r['data']['mergeFromBranch']['labbook'][
            'activeBranchName'] == 'gm.workspace-default'
    def test_query_mergeable_branches_from_feature_branch(
            self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        b1 = bm.create_branch("tester1")
        bm.workon_branch(bm.workspace_branch)
        b2 = bm.create_branch("tester2")

        q = f"""
        {{
            labbook(name: "{UT_LBNAME}", owner: "{UT_USERNAME}") {{
                mergeableBranchNames
                workspaceBranchName
            }}
        }}
        """
        r = client.execute(q)
        pprint.pprint(r)
        assert 'errors' not in r
        assert len(r['data']['labbook']['mergeableBranchNames']) == 1
        assert r['data']['labbook']['mergeableBranchNames'] == [
            bm.workspace_branch
        ]
        assert r['data']['labbook'][
            'workspaceBranchName'] == bm.workspace_branch
    def test_delete_feature_branch_fail(self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        b1 = bm.create_branch("tester1")

        q = f"""
        mutation makeFeatureBranch {{
            deleteExperimentalBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                branchName: "{b1}"
            }}) {{
                success
            }}
        }}
        """
        r = client.execute(q)
        pprint.pprint(r)
        # Cannot delete branch when it's the currently active branch
        assert 'errors' in r
        assert bm.active_branch == b1
        assert lb.is_repo_clean
    def test_create_feature_branch_success_update_description(
            self, mock_create_labbooks, snapshot):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        b1 = bm.create_branch("tester1")
        bm.workon_branch(bm.workspace_branch)

        q = f"""
        mutation makeFeatureBranch {{
            createExperimentalBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                branchName: "valid-branch-name-working1"
                description: "Updated description"
            }}) {{
                labbook{{
                    name
                    description
                    availableBranchNames
                    activeBranchName
                }}
            }}
        }}
        """
        r = client.execute(q)
        assert 'errors' not in r
        r['data']['createExperimentalBranch']['labbook'][
            'activeBranchName'] == 'gm.workspace-default.valid-branch-name-working1'
        r['data']['createExperimentalBranch']['labbook'][
            'description'] == "Updated description"
        snapshot.assert_match(r)

        assert bm.active_branch == 'gm.workspace-default.valid-branch-name-working1'
        assert lb.is_repo_clean

        # Make sure activity record was created when description was changed
        log_data = lb.git.log()
        assert "_GTM_ACTIVITY_START_**\nmsg:Updated description of LabBook" in log_data[
            0]['message']
    def test_create_feature_branch_from_feature_branch_fail(
            self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        b1 = bm.create_branch("tester1")

        q = f"""
        mutation makeFeatureBranch {{
            createExperimentalBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                branchName: "valid-branch-name"
            }}) {{
                newBranchName
            }}
        }}
        """
        r = client.execute(q)
        pprint.pprint(r)
        assert 'errors' in r
        assert bm.active_branch == b1
        assert lb.is_repo_clean
    def test_reflect_deleted_files_on_merge_in(self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        with open('/tmp/s1.txt', 'w') as s1:
            s1.write('original-file\ndata')
        FileOperations.insert_file(lb, section='code', src_file=s1.name)
        bm = BranchManager(lb, username=UT_USERNAME)

        nb = bm.create_branch('new-branch')
        assert os.path.exists(os.path.join(lb.root_dir, 'code', 's1.txt'))
        lb.delete_file('code', 's1.txt')
        assert lb.is_repo_clean
        assert not os.path.exists(os.path.join(lb.root_dir, 'code', 's1.txt'))

        bm.workon_branch(bm.workspace_branch)
        assert os.path.exists(os.path.join(lb.root_dir, 'code', 's1.txt'))

        merge_q = f"""
        mutation x {{
            mergeFromBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                otherBranchName: "{nb}",
                force: false            
            }}) {{
                labbook{{
                    name
                    description
                    availableBranchNames
                    activeBranchName
                }}
            }}
        }}
        """
        r = client.execute(merge_q)
        assert 'errors' not in r
        r['data']['mergeFromBranch']['labbook'][
            'activeBranchName'] == 'gm.workspace-default'
        assert not os.path.exists(os.path.join(lb.root_dir, 'code', 's1.txt'))
    def test_workon_feature_branch_bad_name_fail(self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        b1 = bm.create_branch("tester1")
        bm.workon_branch(bm.workspace_branch)

        q = f"""
        mutation makeFeatureBranch {{
            workonExperimentalBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                branchName: "{b1.replace('gm', '')}"
            }}) {{
                currentBranchName
            }}
        }}
        """
        r = client.execute(q)
        pprint.pprint(r)
        # Cannot delete branch when it's the currently active branch
        assert 'errors' in r
        assert bm.active_branch == bm.workspace_branch
        assert lb.is_repo_clean
    def test_available_branches(self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)

        q = f"""
        {{
            labbook(name: "{UT_LBNAME}", owner: "{UT_USERNAME}") {{
                availableBranchNames
            }}
        }}
        """
        r = client.execute(q)
        pprint.pprint(r)
        assert 'errors' not in r
        assert r['data']['labbook']['availableBranchNames'] == bm.branches
    def test_active_branch_name(self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)

        q = f"""
        {{
            labbook(name: "{UT_LBNAME}", owner: "{UT_USERNAME}") {{
                activeBranchName
                workspaceBranchName
            }}
        }}
        """
        r = client.execute(q)
        assert 'errors' not in r
        assert r['data']['labbook']['activeBranchName'] == bm.active_branch
        assert r['data']['labbook'][
            'workspaceBranchName'] == bm.workspace_branch
    def test_merge_into_feature_from_workspace_simple_success(
            self, mock_create_labbooks, snapshot):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        og_hash = lb.git.commit_hash
        b1 = bm.create_branch("test-branch")
        bm.workon_branch(bm.workspace_branch)
        assert lb.active_branch == bm.workspace_branch
        og2_hash = lb.git.commit_hash
        #assert lb.git.commit_hash == og_hash      <---- I don't understand why this isn't the case...

        lb.makedir('code/main-branch-dir1', create_activity_record=True)
        lb.makedir('code/main-branch-dir2', create_activity_record=True)
        next_main_hash = lb.git.commit_hash
        assert og_hash != next_main_hash

        bm.workon_branch(b1)
        assert not os.path.exists(
            os.path.join(lb.root_dir, 'code/main-branch-dir1'))

        merge_q = f"""
        mutation x {{
            mergeFromBranch(input: {{
                owner: "{UT_USERNAME}",
                labbookName: "{UT_LBNAME}",
                otherBranchName: "{bm.workspace_branch}"                
            }}) {{
                labbook{{
                    name
                    description
                    availableBranchNames
                    activeBranchName
                }}
            }}
        }}
        """
        r = client.execute(merge_q)
        assert 'errors' not in r
        r['data']['mergeFromBranch']['labbook'][
            'activeBranchName'] == 'gm.workspace-default.test-branch'
        snapshot.assert_match(r)

        assert lb.active_branch == b1
        assert os.path.exists(
            os.path.join(lb.root_dir, 'code/main-branch-dir1'))
        assert lb.is_repo_clean
    def test_query_mergeable_branches_from_main(self, mock_create_labbooks):
        lb, client = mock_create_labbooks[0], mock_create_labbooks[1]
        bm = BranchManager(lb, username=UT_USERNAME)
        b1 = bm.create_branch("tester1")
        bm.workon_branch(bm.workspace_branch)
        b2 = bm.create_branch("tester2")
        bm.workon_branch(bm.workspace_branch)
        assert bm.active_branch == bm.workspace_branch

        q = f"""
        {{
            labbook(name: "{UT_LBNAME}", owner: "{UT_USERNAME}") {{
                mergeableBranchNames
            }}
        }}
        """
        r = client.execute(q)
        pprint.pprint(r)
        assert 'errors' not in r
        assert len(r['data']['labbook']['mergeableBranchNames']) == 2
        assert set(r['data']['labbook']['mergeableBranchNames']).issubset(
            set([b1, b2]))
 def resolve_mergeable_branch_names(self, info):
     return info.context.labbook_loader.load(
         f"{get_logged_in_username()}&{self.owner}&{self.name}").then(
             lambda labbook: BranchManager(labbook=labbook,
                                           username=get_logged_in_username(
                                           )).mergeable_branches)