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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
|