def does_project_need_update(self, project): executer = ShellExecuter(verbose=self.server.context.settings.Ion.as_bool("verbose")) project_name = self.fix_name(project.name) repository_path = join(self.base_dir, project_name) is_repo_created = self.is_repository_created(repository_path) if not is_repo_created: self.log("The repository at %s needs to be created." % repository_path) return True self.log("Verifying if the repository at %s needs to be updated" % repository_path) executer.execute("git remote update", repository_path) result = executer.execute("git rev-parse origin/%s %s" % (project.branch, project.branch), repository_path) commits = result.run_log.split() return len(commits) != 2 or commits[0]!=commits[1]
def get_last_commit(self, repository_path): commit_number = None author = None committer = None command = "git show -s --pretty=format:'%H||%an||%ae||%ai||%cn||%ce||%ci||%s'" executer = ShellExecuter() result = executer.execute(command, repository_path) if result.exit_code != 0: raise ValueError("unable to determine last commit. Error: %s" % result.run_log) commit_number, author_name, author_email, author_date, committer_name, committer_email, committer_date, subject = result.run_log.split("||") author_date = self.convert_to_date(author_date) committer_date = self.convert_to_date(committer_date) return { 'commit_number': commit_number, 'author': "%s <%s>" % (author_name, author_email), 'author_date': author_date, 'committer': "%s <%s>" % (committer_name, committer_email), 'committer_date': committer_date, 'subject': subject }
def create_or_update(self, project): executer = ShellExecuter(verbose=self.server.context.settings.Ion.as_bool("verbose")) project_name = self.fix_name(project.name) repository_path = join(self.base_dir, project_name) is_repo_created = self.is_repository_created(repository_path) if not is_repo_created and exists(repository_path): raise ValueError("The specified directory(%s) is not empty and is not a git repository") if not is_repo_created: if not exists(self.base_dir): try: os.mkdir(self.base_dir) except: raise ValueError("Could not create folder %s" % self.base_dir) self.log("Directory successfully created.") self.log("Retrieving scm data for project %s in repository %s (creating new repository - clone)" % (project_name, project.scm_repository)) result = executer.execute("git clone %s %s --recursive --branch %s" % (project.scm_repository, project_name, project.branch), self.base_dir) if result.exit_code == 0: self.log("SCM Data retrieved successfully") else: self.log("Error retrieving SCM Data: %s" % result.run_log) last_commit = self.get_last_commit(repository_path) return ScmResult(result.exit_code == 0 and ScmResult.Created or ScmResult.Failed, repository_path, last_commit, result.run_log) else: self.log("Retrieving scm data for project %s in repository %s (updating repository - pull)" % (project_name, project.scm_repository)) result = executer.execute("git branch | grep %s" % project.branch, repository_path) if project.branch.lower() in result.run_log.lower(): result = executer.execute("git checkout %s" % project.branch.lower(), repository_path) else: result = executer.execute("git checkout -b %s" % project.branch.lower(), repository_path) result = executer.execute("git reset --hard", repository_path) result = executer.execute("git clean -df", repository_path) result = executer.execute("git pull origin %s" % project.branch, repository_path) result = executer.execute("git submodule update --init --recursive", repository_path) if result.exit_code == 0: self.log("SCM Data retrieved successfully") else: self.log("Error retrieving SCM Data: %s" % result.run_log) self.log("Retrieving last commit data for project %s in repository %s" % (project_name, project.scm_repository)) last_commit = self.get_last_commit(repository_path) self.log("Data retrieved.") return ScmResult(result.exit_code == 0 and ScmResult.Updated or ScmResult.Failed, repository_path, last_commit, result.run_log)
class BuildService(Service): Unknown = "Unknown" Success = "Successful" Failure = "Failed" def __init__(self, server): self.server = server self.base_path = server.build_dir self.executer = ShellExecuter(verbose=self.server.context.settings.Ion.as_bool("verbose")) def start_execute(self, executer): ctx = self.server.context ctx.current_command = executer.command ctx.current_process = executer ctx.current_start_time = time.time() ctx.current_project = self.current_project ctx.current_log = None def execute_beat(self, executer): ctx = self.server.context ctx.current_command = executer.command ctx.current_log = executer.result.log def finish_execute(self, executer): ctx = self.server.context ctx.current_command = None ctx.current_start_time = None ctx.current_project = None ctx.current_log = None def build_project(self, project_id): ctx = self.server.context self.connect() try: store = self.store log = ["Build started at %s" % datetime.now()] status = BuildService.Failure scm_status = ScmResult.Failed project = store.query(Project).get(project_id) self.current_project = project self.server.publish('on_before_build', {"server":self.server, "project":project}) ctx.projects_being_built.append(project_id) last_build_number = store.query(Build.number).filter(Build.project==project).order_by(desc(Build.id)).first() last_build_number = last_build_number and last_build_number[0] or 0 build_date = datetime.now() build_scm_status = scm_status build_log = "" scm_service = GitService(self.server) scm_creation_result = scm_service.create_or_update(project) build_scm_status = scm_creation_result.status store.commit() if scm_creation_result.status == ScmResult.Failed: log.append(scm_creation_result.log) status = BuildService.Failure else: log.append("Downloaded code from %s (%s)" % (project.scm_repository, scm_creation_result.status)) self.executer.start_execute = self.start_execute self.executer.finish_execute = self.finish_execute self.executer.execute_beat = self.execute_beat execute_result = self.executer.execute(project.build_script, scm_creation_result.repository_path, timeout=ctx.settings.Skink.as_int("build_timeout")) self.executer.start_execute = None self.executer.finish_execute = None self.executer.execute_beat = None log.append("Executed %s" % project.build_script) log.append("Exit Code: %s" % execute_result.exit_code) log.append("Run Log:") log.append(execute_result.run_log) status = execute_result.exit_code == 0 and BuildService.Success or BuildService.Failure log.append("Build finished at %s" % datetime.now()) build = Build(last_build_number + 1, build_date, status, build_scm_status, "\n".join(log), force_unicode(scm_creation_result.last_commit["commit_number"]), force_unicode(scm_creation_result.last_commit["author"]), force_unicode(scm_creation_result.last_commit["committer"]), force_unicode(scm_creation_result.last_commit["subject"]), scm_creation_result.last_commit["author_date"], scm_creation_result.last_commit["committer_date"], project) store.add(build) store.commit() ctx.projects_being_built.remove(project_id) if (build.status == BuildService.Success): self.server.publish('on_before_build_successful', {"server":self.server, "project":project, "build":build}) if (build.status == BuildService.Success): self.server.publish('on_build_successful', {"server":self.server, "project":project, "build":build}) self.process_pipelines_for(project) else: self.server.publish('on_build_failed', {"server":self.server, "project":project, "build":build}) return build finally: self.disconnect() def process_pipelines_for(self, project): pipelines = self.store.query(Pipeline) \ .filter(PipelineItem.project_id == project.id) \ .filter(PipelineItem.pipeline_id == Pipeline.id) \ .all() for pipeline in pipelines: pipeline_items = pipeline.items for index, pipeline_item in enumerate(pipeline_items): if index == len(pipeline_items) - 1: continue if pipeline_item.project_id == project.id: self.log("Adding project %d to the queue because it's in the same pipeline as project %s" % (pipeline_items[index+1].project.id, pipeline_item.project.name)) self.server.context.build_queue.append(pipeline_items[index+1].project_id)