Many python-automation scripts can be seperated into steps. This library supports this seperation.
Project description
task_in_steps
Many python-automation scripts can be seperated into steps.
This library supports this seperation. You can define steps
with classes. The steps are indepodent as they can implement
can_skip
which checks if the step can be skipped.
Example
class Config:
def __init__(self):
self.parser = argparse.ArgumentParser()
self.parser.add_argument('--projectname', help='Name of the new project', required=True)
self.parser.add_argument('--domain', help='Top-Level-Domain (without review.)', required=True)
self.parser.add_argument('--template', help='A link to a GitHub-Repo, used as template', required=True)
self.parser.add_argument('--username', help='LDAP Username', required=True)
self.parser.add_argument('--password', help='LDAP Password (optional)', required=False)
self.gerrit_port = 29418
def load_args(self):
args = self.parser.parse_args()
self.project_name = args.projectname
self.template_src = args.template
self.gerrit_user = args.username
self.password = args.password
self.domain = args.domain
self.gerrit_host = 'review.' + args.domain
self.gerrit_url = f'http://{self.gerrit_host}'
return self
if __name__ == "__main__":
config = Config().load_args()
run_steps(config, [
CertificateOnThisMachine(),
UploadSshKey(),
ProjectFromTemplate(),
CreateGerritProject(),
ConfigureGerritGitHooks(),
ConfigureGitPushToGerrit(),
CreateJenkinsPipelines(),
TriggerTemplateInit(),
SendInitialCommit()
])
### The steps:
class CertificateOnThisMachine(Step):
name = "SSH certificate on this machine"
def __init__(self):
home = os.path.expanduser('~')
self.ssh_path = home + '/.ssh'
def can_skip(self, config):
return os.path.isfile(self.ssh_path + '/id_rsa.pub')
def run(self, config):
print('no ssh-certificate: generating one')
os.system(f'ssh-keygen -t rsa -N '' -f {self.ssh_path}')
return True
class UploadSshKey(Step):
name = "Upload your SSH-Key"
def can_skip(self, config):
ssh_command = f'ssh -p {config.gerrit_port} {config.gerrit_user}@{config.gerrit_host} gerrit version'
res = subprocess.run(ssh_command.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode
return res == 0
def run(self, config):
home = os.path.expanduser('~')
ssh_path = home + '/.ssh'
print()
print('You did not upload your SSH-Key.')
print()
print(f'1. Go to: http://{config.gerrit_host}/settings/#SSHKeys')
print( '2. Paste this in, click "Add Key" and run again:')
with open(f'{ssh_path}/id_rsa.pub', 'r') as file:
print(file.read())
return False
class ProjectFromTemplate(Step):
name = "Create project from template"
def can_skip(self, config):
return os.path.isdir(f'./{config.project_name}')
def run(self, config):
os.system(f'git clone {config.template_src} {config.project_name}')
os.chdir(f'./{config.project_name}')
os.system(f'rm .git -rf')
os.system(f'git init')
os.chdir('..')
return True
class CreateGerritProject(Step):
name = 'Create Gerrit project'
def can_skip(self, config):
command = f'ssh -p {config.gerrit_port} {config.gerrit_user}@{config.gerrit_host} gerrit ls-projects'
existing_projects = subprocess.check_output(command, shell=True).decode().strip().split('\n')
return config.project_name in existing_projects
def run(self, config):
os.chdir(f'./{config.project_name}')
os.system(f'ssh -p {config.gerrit_port} {config.gerrit_user}@{config.gerrit_host} gerrit create-project {config.project_name}')
os.chdir('..')
return True
class ConfigureGerritGitHooks(Step):
name = 'Installing Gerrit Git-Hooks'
def can_skip(self, config):
path = f'./{config.project_name}/.git/hooks/commit-msg'
if not os.path.isfile(path):
return False
with open(path, 'r') as file:
content = file.read()
return 'Change-Id:' in content
def run(self, config):
os.chdir(f'./{config.project_name}')
os.system(f'scp -p -P {config.gerrit_port} {config.gerrit_user}@{config.gerrit_host}:hooks/commit-msg ".git/hooks/"')
os.chdir('..')
return True
class ConfigureGitPushToGerrit(Step):
name = 'Configure "git push" to Gerrit'
def can_skip(self, config):
path = f'./{config.project_name}/.git/config'
if not os.path.isfile(path):
return False
with open(path, 'r') as file:
content = file.read()
return 'push = refs/heads/master:refs/for/master' in content
def run(self, config):
path = f'./{config.project_name}/.git/config'
git_config = f'''
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = ssh://{config.gerrit_user}@{config.gerrit_host}:{config.gerrit_port}/{config.project_name}
fetch = +refs/heads/master:refs/remotes/origin/master
push = refs/heads/master:refs/for/master
[branch "master"]
remote = origin
merge = refs/heads/master
'''
with open(path, 'w') as f:
f.write(git_config)
return True
class CreateJenkinsPipelines(Step):
name = 'Creating Jenkins-Pipelines'
def can_skip(self, config):
job1 = config.project_name + '-code'
job2 = config.project_name + '-deploy'
server = self._get_server(config)
jobs = [job['name'] for job in server.get_all_jobs()]
return job1 in jobs and job2 in jobs
def run(self, config):
self._create_pipeline(config.project_name, 'code', config)
self._create_pipeline(config.project_name, 'deploy', config)
return True
def _get_server(self, config):
if hasattr(self, 'server'):
return self.server
url = f'http://ci.{config.domain}'
password = config.password
if not password:
print(f'Enter credentials for "{url}"')
print(f'User: {config.gerrit_user}')
password = getpass()
self.server = Jenkins(
url,
username=config.gerrit_user,
password=password)
return self.server
def _create_pipeline(self, project_name, pipeline_type, config):
content = pkg_resources.resource_string('generate_gerrit_jenkins_project', f'jobs/{pipeline_type}.config.xml').decode()
content = content.replace('helloworld', project_name)
try:
self._get_server(config).create_job(project_name + '-' + pipeline_type, content)
except JenkinsException as e:
print(e)
raise
class TriggerTemplateInit(Step):
name = 'Trigger Template Init'
def can_skip(self, config):
return not os.path.isfile(f'./{config.project_name}/init_template.py')
def run(self, config):
stdout, stderr, has_error = exec(f'python3 init_template.py', cwd=f'./{config.project_name}')
if not has_error:
exec(f'rm init_template.py', cwd=f'./{config.project_name}')
return not has_error
class SendInitialCommit(Step):
name = 'Send initial commit to gerrit'
def can_skip(self, config):
stdout, stderr, has_error = exec('git log', cwd=f'./{config.project_name}')
return not has_error # git log returns error if there are not commits. Skip=True if no error returned
def run(self, config):
stdout, stderr, has_error1 = exec('git add .', cwd=f'./{config.project_name}')
print(stdout, stderr)
stdout, stderr, has_error2 = exec('git commit -aminit', cwd=f'./{config.project_name}')
print(stdout, stderr)
stdout, stderr, has_error3 = exec('git push origin master', cwd=f'./{config.project_name}')
print(stdout, stderr)
return True
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
task_in_steps-0.0.1.tar.gz
(10.7 kB
view details)
Built Distribution
File details
Details for the file task_in_steps-0.0.1.tar.gz
.
File metadata
- Download URL: task_in_steps-0.0.1.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.5.0 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2993ad537587383d622efc42c5d4971cf246e7181d6d3bdcabb81a6498b38c80 |
|
MD5 | 3d200a5420830478851f174a1290a1f3 |
|
BLAKE2b-256 | 043febfb9bee85ee6da6774606e3212ea30675563b956ad36005c9118245f549 |
File details
Details for the file task_in_steps-0.0.1-py3-none-any.whl
.
File metadata
- Download URL: task_in_steps-0.0.1-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.5.0 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c0df603b3e4cc53ff78dabbd081249d75b80288ef7ecbbcb94a30008f69fbb6a |
|
MD5 | 7933ec4deeddd1b0f7a0059d6fa62aa1 |
|
BLAKE2b-256 | e4104981b1a3d917f5e3f2ba7f4862670c07109fd8788a4479e7dc71eb389771 |