Esempio n. 1
0
    def update_central_repos(self):
        logger = logging.getLogger(__name__)

        # TODO: the first time we clone, ssh might want to verify the server an we might need to manually accept it.
        # TODO: How can we automate this?
        self.shas = {}
        first = True  # only return branches of the first repository
        for repo in self.config['repos']:
            logger.debug("Repo url {}".format(repo['url']))
            if repo['type'] != 'git':
                raise Exception("Unsupported repository {}".format(
                    repo['type']))

            repo_local_name = self.get_repo_local_name(repo)

            logger.debug("Local repo dir {}".format(repo_local_name))
            # TODO have a root directory for each project that is under the server root
            # TODO allow the user to supply a local directory
            local_repo_path = os.path.join(self.server['repositories'],
                                           repo_local_name)
            logger.debug("Local repo path {}".format(local_repo_path))

            if not os.path.exists(local_repo_path):
                logger.debug("clone repo for the first time")
                if 'credentials' in repo:
                    os.environ[
                        'GIT_SSH_COMMAND'] = "ssh -i  " + repo['credentials']
                cmd_list = [git, 'clone', repo['url'], repo_local_name]
                logger.debug(' '.join(cmd_list))
                with cwd(self.server['repositories']):
                    code, out = _system(cmd_list)
                # get current sha ?? In which branch?
                if first:
                    old_branches = {}
            else:
                logger.debug("update repository")
                if first:
                    old_branches = self.get_branches(local_repo_path)
                cmd_list = [git, 'pull']
                with cwd(local_repo_path):
                    code, out = _system(cmd_list)
            if first:
                new_branches = self.get_branches(local_repo_path)
                first = False
            else:
                branches = self.get_branches(local_repo_path)
                self.shas[repo['name']] = branches[repo['branch']]
            #logger.debug(yaml.dump(new_branches))

        self.old_branches = old_branches
        self.new_branches = new_branches
        return
Esempio n. 2
0
    def test_repos(self, tmpdir):
        temp_dir = str(tmpdir)
        print(temp_dir)
        self.setup_repos(temp_dir, {}, 2)

        _system("python check.py --server {} --config {} {}".format(
            self.server_file, self.config_file, debug))
        assert os.path.exists(os.path.join(self.repositories, 'repo0'))
        assert os.listdir(os.path.join(self.repositories,
                                       'repo0/')) == ['.git']
        assert not os.path.exists(os.path.join(self.workdir, '1', 'repo0/'))

        assert os.path.exists(os.path.join(self.repositories, 'repo1'))
        assert os.listdir(os.path.join(self.repositories,
                                       'repo1/')) == ['.git']
        assert not os.path.exists(os.path.join(self.workdir, '1', 'repo1/'))

        # update the repository
        with cwd(self.client[0]):
            with open('README.txt', 'w') as fh:
                fh.write("first line\n")
            _system("git add .")
            _system("git commit -m 'first' --author 'Foo Bar <*****@*****.**>'")
            _system("git push")

        with cwd(self.client[1]):
            with open('selftest.py', 'w') as fh:
                fh.write("assert True\n")
            _system("git add .")
            _system(
                "git commit -m 'start with test' --author 'Zee No <*****@*****.**>'"
            )
            _system("git push")

        _system("python check.py --server {} --config {} {}".format(
            self.server_file, self.config_file, debug))
        assert os.listdir(os.path.join(self.repositories,
                                       'repo0/')) == ['README.txt', '.git']
        assert os.path.exists(os.path.join(self.workdir, '1', 'repo0/'))
        assert os.listdir(os.path.join(self.workdir, '1',
                                       'repo0/')) == ['README.txt', '.git']

        assert os.listdir(os.path.join(self.repositories,
                                       'repo1/')) == ['selftest.py', '.git']
        assert os.path.exists(os.path.join(self.workdir, '1', 'repo1/'))
        assert os.listdir(os.path.join(self.workdir, '1',
                                       'repo1/')) == ['selftest.py', '.git']
Esempio n. 3
0
    def test_run_tests(self, tmpdir):
        temp_dir = str(tmpdir)
        print(temp_dir)
        self.setup_repos(temp_dir,
                         {'steps': ["cli: python repo0/selftest.py"]}, 1)

        # update the repository
        with cwd(self.client[0]):
            with open('selftest.py', 'w') as fh:
                fh.write("exit(13)\n")
            _system("git add .")
            _system("git commit -m 'first' --author 'Foo Bar <*****@*****.**>'")
            _system("git push")
        code, out = capture2(
            "python check.py --server {} --config {} {}".format(
                self.server_file, self.config_file, debug),
            shell=True)
        print(out)
        assert code == 1, "One test failure repored"
        #assert out == "" # TODO: this will fail if --debug is on, but also becaues there is some output from the git commands.
        assert os.listdir(os.path.join(self.repositories,
                                       'repo0/')) == ['selftest.py', '.git']
        assert os.path.exists(os.path.join(self.workdir, '1', 'repo0/'))
        assert os.listdir(os.path.join(self.workdir, '1',
                                       'repo0/')) == ['selftest.py', '.git']

        with cwd(self.client[0]):
            with open('selftest.py', 'w') as fh:
                fh.write("exit(0)\n")
            _system("git add .")
            _system("git commit -m 'second' --author 'Foo Bar <*****@*****.**>'")
            _system("git push")
        code, out = capture2(
            "python check.py --server {} --config {} {}".format(
                self.server_file, self.config_file, debug),
            shell=True)
        print(out)
        assert code == 0, "test sucess repored: "
        #assert out == "" # TODO: this will fail if --debug is on, but also becaues there is some output from the git commands.
        assert os.listdir(os.path.join(self.repositories,
                                       'repo0/')) == ['selftest.py', '.git']
        assert os.path.exists(os.path.join(self.workdir, '2', 'repo0/'))
        assert os.listdir(os.path.join(self.workdir, '2',
                                       'repo0/')) == ['selftest.py', '.git']
Esempio n. 4
0
 def get_branches(self, path):
     branches = {}
     with cwd(path):
         _system([git, 'pack-refs', '--all'])
         if os.path.exists('.git/packed-refs'):
             # It seems the file does not exist if the repository is empty
             with open('.git/packed-refs') as fh:
                 for line in fh:
                     if re.search(r'\A#', line):
                         continue
                     m = re.search(r'\A(\S+)\s+refs/remotes/origin/(.*)',
                                   line)
                     if m:
                         branches[m.group(2)] = m.group(1)
     return branches
Esempio n. 5
0
    def clone_repositories(self):
        logger = logging.getLogger(__name__)

        logger.debug("Clone the repositories")
        for repo in self.config['repos']:
            repo_name = repo['name']
            repo_local_name = self.get_repo_local_name(repo)
            code, out = _system([
                git, 'clone',
                os.path.join(self.server['repositories'], repo_local_name),
                repo_local_name
            ])
            if code != 0:
                raise Exception("Could not clone repo")
            with cwd(repo_local_name):
                logger.debug("Check out the given sha")
                code, out = _system([git, 'checkout', self.shas[repo_name]])
                if code != 0:
                    raise Exception(
                        "Could not checkout sha1 {} in repository {}".format(
                            sha1, repo_local_name))
Esempio n. 6
0
    def build(self):
        logger = logging.getLogger(__name__)
        build_number = self.get_next_build_number()
        logger.debug("Build number: {}".format(build_number))
        # TODO store the build in some queue and also allow the parallel execution of jobs on agents

        # update_local_repositories()
        build_parent_directory = os.path.join(self.server['workdir'],
                                              str(build_number))
        logger.debug("Build parent dir: {}".format(build_parent_directory))
        os.mkdir(build_parent_directory)

        bg = self.add_build_logger(build_parent_directory)
        logger.debug("Starting Build {} in directory: {}".format(
            build_number, build_parent_directory))

        results = {'status': 'success'}
        if 'matrix' in self.config:
            results['matrix'] = {}
            subbuild = 0
            for case in self.config['matrix']:
                subbuild += 1
                logger.debug("On agent '{}' schedule exe: '{}'".format(
                    case['agent'], case['exe']))
                if case['agent'] not in self.server['agents']:
                    results['status'] = 'failure'
                    results['matrix'][subbuild] = {
                        'agent': case['agent'],
                        'error': "Agent is not available.",
                    }
                    continue

                if case['agent'] == 'master':
                    # TODO use the limit to run in parallel
                    build_directory = os.path.join(build_parent_directory,
                                                   str(subbuild))
                    os.mkdir(build_directory)
                    with cwd(build_directory):
                        self.clone_repositories()
                        code, out = _system(case['exe'])
                        results['matrix'][subbuild] = {
                            'exit': code,
                            'agent': case['agent'],
                            'exe': case['exe'],
                            'out': out,
                        }
                        if code != 0:
                            results['status'] = 'failure'
                else:
                    pass
                    results['status'] = 'failure'
                    # TODO
                    # ssh host
                    # scp our code, the configuration files (that are appropriate to that machine)
                    # clone the directories
                    # run the build
        else:
            build_directory = build_parent_directory
            with cwd(build_directory):
                self.clone_repositories()
                if 'steps' in self.config:
                    results['steps'] = []
                    logger.debug("Run the steps defined in the configuration")
                    for step in self.config['steps']:
                        logger.debug(step)
                        m = re.search(r'\Acli:\s*(.*)', step)
                        cmd = m.group(1)
                        logger.debug(cmd)
                        code, out = _system(cmd)
                        results['steps'].append({
                            'exit': code,
                            'agent': 'master',
                            'out': out,
                            'step': step,
                        })
                        if code != 0:
                            results['status'] = 'failure'
                            break

        with open(os.path.join(self.server['db'],
                               str(build_number) + '.json'), "w") as fh:
            #json.dump(results, fh)
            json.dump(results,
                      fh,
                      sort_keys=True,
                      indent=4,
                      separators=(',', ': '),
                      ensure_ascii=False)

        logger.removeHandler(bg)
        return build_number
Esempio n. 7
0
    def setup_repos(self, temp_dir, user_config, count):
        remote_repos = os.path.join(temp_dir, 'remote_repos')  # bare repos
        client_dir = os.path.join(temp_dir, 'client')  # workspace of users
        root = os.path.join(temp_dir, 'server')
        self.server_file = os.path.join(root, 'server.yml')
        self.config_file = os.path.join(
            root, 'config.yml')  # this might be in a repository
        self.repositories = os.path.join(
            root, 'repositories')  # here is where we'll clone repos
        self.db = os.path.join(root, 'db')  # here is where we'll clone repos
        self.workdir = os.path.join(root, 'workdir')

        self.repo = []
        self.client = []
        for i in range(count):
            self.repo.append(os.path.join(remote_repos, 'repo' + str(i)))
            self.client.append(os.path.join(client_dir, 'repo' + str(i)))
        os.mkdir(remote_repos)
        os.mkdir(client_dir)
        os.mkdir(root)
        os.mkdir(self.repositories)
        os.mkdir(self.workdir)
        os.mkdir(self.db)
        # create config files
        server_config = {
            'repositories': self.repositories,
            'db': self.db,
            'workdir': self.workdir,
            'agents': {
                'master': {
                    'limit': 1
                }
            }
        }
        with open(self.server_file, 'w') as fh:
            fh.write(
                yaml.dump(server_config,
                          explicit_start=True,
                          default_flow_style=False))

        # in a subdirectory crete a git repository
        for i in range(count):
            os.mkdir(self.repo[i])
            with cwd(self.repo[i]):
                _system("git init --bare")
            with cwd(client_dir):
                _system("git clone " + self.repo[i])

        user_config['repos'] = []
        for i in range(count):
            user_config['repos'].append({
                'name': 'repo' + str(i),
                'branch': 'master',
                'type': 'git',
                'url': self.repo[i],
            })

        with open(self.config_file, 'w') as fh:
            fh.write(
                yaml.dump(user_config,
                          explicit_start=True,
                          default_flow_style=False))
Esempio n. 8
0
    def test_repo(self, tmpdir):
        temp_dir = str(tmpdir)
        print(temp_dir)
        self.setup_repos(temp_dir, {}, 1)

        _system("python check.py --server {} --config {} {}".format(
            self.server_file, self.config_file, debug))
        assert os.path.exists(os.path.join(self.repositories, 'repo0'))
        assert os.listdir(os.path.join(self.repositories,
                                       'repo0/')) == ['.git']
        assert not os.path.exists(os.path.join(self.workdir, '1', 'repo0/'))

        # update the repository
        with cwd(self.client[0]):
            with open('README.txt', 'w') as fh:
                fh.write("first line\n")
            _system("git add .")
            _system("git commit -m 'first' --author 'Foo Bar <*****@*****.**>'")
            _system("git push")
        _system("python check.py --server {} --config {} {}".format(
            self.server_file, self.config_file, debug))
        assert os.listdir(os.path.join(self.repositories,
                                       'repo0/')) == ['README.txt', '.git']
        assert os.path.exists(os.path.join(self.workdir, '1', 'repo0/'))
        assert os.listdir(os.path.join(self.workdir, '1',
                                       'repo0/')) == ['README.txt', '.git']
        # check if the sha change was noticed git rev-parse HEAD

        # create a branch, see if the new branch is noticed
        with cwd(self.client[0]):
            with open('TODO', 'w') as fh:
                fh.write("Some TODO text\n")
            _system("git checkout -b todo")
            _system("git add .")
            _system(
                "git commit -m 'add test' --author 'Foo Bar <*****@*****.**>'")
            _system("git push --set-upstream origin todo")

            _system("git checkout master")
            with open('MASTER', 'w') as fh:
                fh.write("Some MASTER text\n")
            _system("git add .")
            _system(
                "git commit -m 'add master' --author 'Foo Bar <*****@*****.**>'")
            _system("git push")
        code, out = capture2(
            "python check.py --server {} --config {} {}".format(
                self.server_file, self.config_file, debug),
            shell=True)
        print(out)
        assert code == 0

        # first workdir did not change
        assert os.path.exists(os.path.join(self.workdir, '1', 'repo0/'))
        assert os.listdir(os.path.join(self.workdir, '1',
                                       'repo0/')) == ['README.txt', '.git']

        # second workdir has the new file as well
        assert os.path.exists(os.path.join(self.workdir, '2', 'repo0/'))
        assert os.listdir(os.path.join(
            self.workdir, '2', 'repo0/')) == ['MASTER', 'README.txt', '.git']

        # second workdir has the new file as well
        assert os.path.exists(os.path.join(self.workdir, '3', 'repo0/'))
        assert os.listdir(os.path.join(
            self.workdir, '3', 'repo0/')) == ['TODO', 'README.txt', '.git']
Esempio n. 9
0
    def test_run_matrix(self, tmpdir):
        temp_dir = str(tmpdir)
        print(temp_dir)
        self.setup_repos(
            temp_dir, {
                'matrix': [
                    {
                        'agent': 'master',
                        'exe': 'python repo0/code.py Foo',
                    },
                    {
                        'agent': 'master',
                        'exe': 'python repo0/code.py',
                    },
                    {
                        'agent': 'master',
                        'exe': 'python repo0/code.py Bar',
                    },
                    {
                        'agent': 'master',
                        'exe': 'python repo0/code.py crash',
                    },
                ]
            }, 1)

        # update the repository
        with cwd(self.client[0]):
            with open('code.py', 'w') as fh:
                fh.write("""
import sys
if len(sys.argv) < 2:
    exit("Missing parameter")
print("hello " + sys.argv[1])
if sys.argv[1] == "crash":
    v = 0
    print(42/v)
""")

            _system("git add .")
            _system("git commit -m 'first' --author 'Foo Bar <*****@*****.**>'")
            _system("git push")
        code, out = capture2(
            "python check.py --server {} --config {} {}".format(
                self.server_file, self.config_file, debug),
            shell=True)
        print(out)
        assert code == 1, "some tests failed in the matrix"
        #assert out == "" # TODO: this will fail if --debug is on, but also becaues there is some output from the git commands.
        assert os.listdir(os.path.join(self.repositories,
                                       'repo0/')) == ['code.py', '.git']
        assert os.path.exists(os.path.join(self.workdir, '1/1', 'repo0/'))
        assert os.listdir(os.path.join(self.workdir, '1/1',
                                       'repo0/')) == ['code.py', '.git']
        assert os.path.exists(os.path.join(self.workdir, '1/2', 'repo0/'))
        assert os.listdir(os.path.join(self.workdir, '1/2',
                                       'repo0/')) == ['code.py', '.git']
        results_file = os.path.join(self.db, '1.json')
        assert os.path.exists(results_file)
        with open(results_file) as fh:
            results = json.load(fh)
        last = results['matrix'].pop('4')
        assert results == {
            'status': 'failure',
            'matrix': {
                '1': {
                    'exit': 0,
                    'agent': 'master',
                    'exe': 'python repo0/code.py Foo',
                    'out': 'hello Foo\n'
                },
                '2': {
                    'exit': 1,
                    'agent': 'master',
                    'exe': 'python repo0/code.py',
                    'out': 'Missing parameter\n'
                },
                '3': {
                    'exit': 0,
                    'agent': 'master',
                    'exe': 'python repo0/code.py Bar',
                    'out': 'hello Bar\n'
                },
            },
        }
        out_of_last = last.pop('out')
        assert last == {
            'exit': 1,
            'agent': 'master',
            'exe': 'python repo0/code.py crash',
        }
        # Then end of the error message has changed so we don't test the specifics
        # In Python 2: integer division or modulo by zero
        # In Python 3: division by zero
        assert 'hello crash\nTraceback (most recent call last):\n  File "repo0/code.py", line 8, in <module>\n    print(42/v)\nZeroDivisionError:' in out_of_last