UNCLASSIFIED

Commit 0fef87c4 authored by Joshua Eason's avatar Joshua Eason
Browse files

Initial release

parent 9f045a6a
*.pyc
\ No newline at end of file
stages:
- scan projects
scan projects:
stage: scan projects
image: registry1.dsop.io/ironbank/opensource/python/python36:latest
variables:
MODE: "check"
before_script:
- dnf install -y git
- pip install -r requirements.txt
script:
- python template.py --gitlab-url=${GITLAB_URL} --gitlab-token=${IRONBANK_TOOLS_TOKEN} --template-project=${TEMPLATE_PROJECT} --mode ${MODE}
when: manual
timeout: 12h
# only:
# variables:
# - $MODE == 'fix' || $MODE == 'check'
\ No newline at end of file
# project-template
# Overview
Python utility for ensuring that projects maintain the same settings, configurations, files, etc. Designed to be used in conjuction with built-in GitLab project templates.
Python utility for ensuring that projects maintain the same settings, configurations, files, etc. Designed to be used in conjuction with built-in GitLab project templates.
\ No newline at end of file
# Usage
This utility is written in Python 3 and can be executed via the following:
`python3 template.py --gitlab-url="https://repo1.dsop.io" --gitlab-token="mytoken" --template-project=1979 `
## Arguments
Argument | Description | Default
--- | --- | ---
gitlab-url | The URL of Gitlab | None
gitlab-token | The access token used when communcating with the Gitlab instance | None
template-project | The project within Gitlab to use as the template | None
## Requirements
The base application requires the following Python 3 modules to be installed:
- `requests`
- `getopt`
- `sys`
- `logging`
Additional Python 3 modules may be necessary based on which modules are enabled within this project.
# Modules
You may view the necessary documentation on each the following modules by cicking on it's name:
- [file_templates](docs/file_templates.md)
- [branches](docs/branches.md)
- [badges](docs/badges.md)
\ No newline at end of file
# badges
This module identifies all project badges applied to `template-project` and can parse the required URL's to fit a specified pattern. For example, linking directly to the project on Registry1 based on the Gitlab project name. This module can identify any misconfigurations and/or fix based on your choosing.
## Requirements
Badges that do not need URL modifications, for example linking to a pre-defined URL that doesn't change with each project, then you need not do anything.
However, if the badge requires that the URL be modified in any way, you will be required to modify the existing code as necessary to make things work. No attempt was made to make this a generic effort.
Python 3 modules:
- `json`
- `urllib.parse`
- `re`
## Notes
None
\ No newline at end of file
# branches
This module identifies all existing branches inside `template-project` and their properties such as protected status and rules. It then checks this against the target project and can identify/correct any findings.
## Requirements
None
Python 3 modules:
- `json`
## Notes
None
\ No newline at end of file
# file_templates
## Overview
This module identifies files inside the `template-project` and ensures they exist in the target project. If they do not, this module can identify and/or correct.
## Requirements
This module requires that you configure the list of `fileTemplates` in the `file_templates.py` file located in the `modules` directory. This ensures the application knows which files inside the `template-project` to look for.
Python 3 modules:
- `json`
- `urllib.parse`
- `git`
- `tempfile`
- `shutil`
- `os`
- `re`
- `base64`
## Notes
If a template is missing and the module has been called using the `fix` method, the application will only push the correct files to `master` branch. No other branches are impacted. To do this, the application first ensures that `master` branch is unprotected. It does not attempt to re-protect the branch. Thus, subsequent modules such as the `branches` module may identify that branches have been set incorrectly and attempt to rectify the issue.
\ No newline at end of file
import requests
import logging
import json
import urllib.parse
import re
link_ibfe = "https://ironbank.dsop.io/ironbank/repomap/"
link_registry1 = "https://registry1.dsop.io/harbor/projects/3/repositories/"
image_ibfe = "https://img.shields.io/badge/Website-Iron%20Bank-informational"
image_registry1 = "https://img.shields.io/badge/Website-Registry1-informational"
##### Supporting methods
def __getBadges(url, token, id):
url = url + "/api/v4/projects/" + str(id) + "/badges"
HEADER = {
'private_token': token
}
page = 1
PARAMS = {
'per_page': 100,
'page': page
}
badges = []
response = requests.get(url, params = PARAMS, headers = HEADER)
if response.status_code != 200:
logging.critical("Failed to list badges: " + str(response.status_code) + " " + response.reason)
else:
while response.json():
PARAMS = {
'private_token': token,
'per_page': 100,
'page': page
}
response = requests.get(url, params = PARAMS, headers = HEADER)
for i in response.json():
badges.append(i)
page += 1
return badges
def __getProjectNamespace(url, token, id):
url = url + "/api/v4/projects/" + str(id)
HEADER = {
'private_token': token
}
response = requests.get(url, headers = HEADER)
if response.status_code == 200:
return response.json()['path_with_namespace']
else:
logging.critical("Failed to retrieve project namespace: " + str(response.status_code) + " " + response.reason)
return ''
def __createBadge(url, token, id, badge, project):
url = url + "/api/v4/projects/" + str(id) + "/badges"
HEADER = {
'private_token': token
}
PARAMS = {
'name': badge['name'],
'link_url': '',
'image_url': ''
}
if badge['name'] == 'ibfe':
PARAMS['link_url'] = link_ibfe + project
PARAMS['link_url'] = re.search("(.*)/", PARAMS['link_url']).group(1)
PARAMS['image_url'] = image_ibfe
elif badge['name'] == 'registry1':
PARAMS['link_url'] = link_registry1 + project.replace("/", "%2F")
PARAMS['image_url'] = image_registry1
else:
PARAMS['link_url'] = badge['link_url']
PARAMS['image_url'] = badge['image_url']
response = requests.post(url, params = PARAMS, headers = HEADER)
if response.status_code != 201:
logging.critical("Failed to create badge: " + str(response.status_code) + " " + response.reason)
def __fixBadge(url, token, id, badge, project):
url = url + "/api/v4/projects/" + str(id) + "/badges/" + str(badge['id'])
HEADER = {
'private_token': token
}
PARAMS = {
'link_url': '',
'image_url': ''
}
if badge['name'] == 'ibfe':
PARAMS['link_url'] = link_ibfe + project
PARAMS['link_url'] = re.search("(.*)/", PARAMS['link_url']).group(1)
PARAMS['image_url'] = image_ibfe
elif badge['name'] == 'registry1':
PARAMS['link_url'] = link_registry1 + project.replace("/", "%2F")
PARAMS['image_url'] = image_registry1
else:
PARAMS['link_url'] = badge['link_url']
PARAMS['image_url'] = badge['image_url']
response = requests.put(url, params = PARAMS, headers = HEADER)
if response.status_code != 200:
logging.critical("Failed to create badge: " + str(response.status_code) + " " + response.reason)
##### Check methods
def check(url, token, tid, pid):
# Get badges
tbadges = __getBadges(url, token, tid)
pbadges = __getBadges(url, token, pid)
project = __getProjectNamespace(url, token, pid)
project = project.replace("dsop/", "")
# Compare template project with project
missing = checkMissing(tbadges, pbadges)
misconfigured = checkMisconfigured(tbadges, pbadges, project)
return {
'project': project,
'missing': missing,
'misconfigured': misconfigured
}
def checkMissing(tbadges, pbadges):
notFound = []
for a in tbadges:
missing = True
if a['kind'] == 'project':
for b in pbadges:
if a['name'] == b['name'] and b['kind'] == 'project':
missing = False
if missing == True and a['kind'] == 'project':
notFound.append(a)
if len(notFound) > 0:
logging.warning("Badges missing!")
return notFound
def checkMisconfigured(tbadges, pbadges, project):
ibfe_link_url = link_ibfe + project
ibfe_link_url = re.search("(.*)/", ibfe_link_url).group(1)
registry1_link_url = link_registry1 + project.replace("/", "%2F")
misconfigured = []
for a in tbadges:
miss = False
if a['kind'] == 'project':
for b in pbadges:
if a['name'] == b['name'] and b['kind'] == 'project':
if b['name'] == "ibfe":
if b['link_url'] != ibfe_link_url or b['image_url'] != image_ibfe:
miss = True
elif b['name'] == "registry1":
if b['link_url'] != registry1_link_url or b['image_url'] != image_registry1:
miss = True
else:
miss = False
if miss == True:
misconfigured.append(b)
if len(misconfigured) > 0:
logging.warning("Badges misconfigured!")
return misconfigured
##### Fix methods
def fix(url, token, tid, pid):
fixes = check(url, token, tid, pid)
if len(fixes['missing']) > 0:
fixMissing(url, token, pid, fixes['missing'], fixes['project'])
if len(fixes['misconfigured']) > 0:
fixMisconfigured(url, token, pid, fixes['misconfigured'], fixes['project'])
def fixMissing(url, token, id, missing, project):
for i in missing:
logging.debug("Creating badge: " + i['name'])
__createBadge(url, token, id, i, project)
def fixMisconfigured(url, token, id, misconfigured, project):
for i in misconfigured:
logging.debug("Fixing protected branch: " + i['name'])
__fixBadge(url, token, id, i, project)
\ No newline at end of file
import requests
import logging
import json
##### Supporting methods
def __getBranches(url, token, id):
url = url + "/api/v4/projects/" + id + "/repository/branches"
HEADER = {
'private_token': token
}
page = 1
PARAMS = {
'per_page': 100,
'page': page
}
branches = []
response = requests.get(url, params = PARAMS, headers = HEADER)
if response.status_code != 200:
logging.critical("Failed to list branches: " + str(response.status_code) + " " + response.reason)
else:
while response.json():
PARAMS = {
'private_token': token,
'per_page': 100,
'page': page
}
response = requests.get(url, params = PARAMS, headers = HEADER)
for i in response.json():
branches.append(i)
page += 1
return branches
def __getProtectedBranches(url, token, id):
url = url + "/api/v4/projects/" + id + "/protected_branches"
HEADER = {
'private_token': token
}
page = 1
PARAMS = {
'per_page': 100,
'page': page
}
branches = []
response = requests.get(url, params = PARAMS, headers = HEADER)
if response.status_code != 200:
logging.critical("Failed to list branches: " + str(response.status_code) + " " + response.reason)
else:
while response.json():
PARAMS = {
'private_token': token,
'per_page': 100,
'page': page
}
response = requests.get(url, params = PARAMS, headers = HEADER)
for i in response.json():
branches.append(i)
page += 1
return branches
def __createBranch(url, token, id, name, ref):
url = url + "/api/v4/projects/" + str(id) + "/repository/branches"
HEADER = {
'private_token': token
}
PARAMS = {
'branch': name,
'ref': ref
}
response = requests.post(url, params = PARAMS, headers = HEADER)
if response.status_code != 201:
logging.critical("Failed to create branch: " + str(response.status_code) + " " + response.reason)
def __createProtectedBranch(url, token, id, access):
url = url + "/api/v4/projects/" + str(id) + "/protected_branches"
HEADER = {
'private_token': token
}
PARAMS = {}
for i in access:
PARAMS[i] = access[i]
# Delete the protected branch first, otherwise this will fail. However, we don't know for sure
# that this is protected so we ignore the response
response = requests.delete(url + "/" + access['name'], headers = HEADER)
response = requests.post(url, params = PARAMS, headers = HEADER)
if response.status_code != 201:
logging.critical("Failed to create protected branch: " + str(response.status_code) + " " + response.reason)
def __listEqual(a, b):
if len(a) != len(b):
return False
else:
for i in a:
match = False
for j in b:
if i == j and a[i] == b[j]:
match = True
if match == False:
return False
return True
##### Check methods
def check(url, token, tid, pid):
# Get template branches and protected branches
tbranches = __getBranches(url, token, str(tid))
tprotected = __getProtectedBranches(url, token, str(tid))
# Get project branches and protected branches
branches = __getBranches(url, token, str(pid))
protected = __getProtectedBranches(url, token, str(pid))
# Compare template project with project
missing = checkMissing(tbranches, branches)
# misconfigured = checkMisconfigured(tbranches, branches)
misprotected = checkProtected(tprotected, protected)
return {
'missing': missing,
# 'misconfigured': misconfigured,
'misprotected': misprotected
}
def checkMissing(tbranches, branches):
notFound = []
for a in tbranches:
found = False
for b in branches:
if a['name'] == b['name']:
found = True
if found == False:
notFound.append(a)
if len(notFound) > 0:
logging.warning("Branches missing!")
return notFound
def checkProtected(tprotected, protected):
misprotectedBranches = []
for a in tprotected:
found = False
for b in protected:
if a['name'] == b['name']:
found = True
if len(a['push_access_levels']) > 0 and len(b['push_access_levels']) > 0:
if __listEqual(a['push_access_levels'][0], b['push_access_levels'][0]) == False:
misprotectedBranches.append(a)
if len(a['merge_access_levels']) > 0 and len(b['merge_access_levels']) > 0:
if __listEqual(a['merge_access_levels'][0], b['merge_access_levels'][0]) == False:
misprotectedBranches.append(a)
# If not specified from CLI, GitLab automatically adds this but doesn't match
# when creating from the UI. Doesn't seem to impact anything, so commenting out.
# elif a['unprotect_access_levels'] != b['unprotect_access_levels']:
# misprotectedBranches.append(a)
if a['code_owner_approval_required'] != b['code_owner_approval_required']:
misprotectedBranches.append(a)
if found == False:
misprotectedBranches.append(a)
if len(misprotectedBranches) > 0:
logging.warning("Protected branches misconfigured!")
return misprotectedBranches
##### Fix methods
def fix(url, token, tid, pid):
fixes = check(url, token, tid, pid)
if len(fixes['missing']) > 0:
fixMissing(url, token, pid, fixes['missing'])
if len(fixes['misprotected']) > 0:
fixProtected(url, token, pid, fixes['misprotected'])
def fixMissing(url, token, id, missing):
for i in missing:
logging.debug("Creating branch: " + i['name'])
__createBranch(url, token, id, i['name'], 'master')
def fixProtected(url, token, id, misprotected):
for i in misprotected:
logging.debug("Fixing protected branch: " + i['name'])
access = {}
access['name'] = i['name']
if 'push_access_levels' in i.keys():
if len(i['push_access_levels']) > 0:
access['push_access_level'] = i['push_access_levels'][0]['access_level']
if 'merge_access_levels' in i.keys():
if len(i['merge_access_levels']) > 0:
access['merge_access_level'] = i['merge_access_levels'][0]['access_level']
if 'unprotect_access_levels' in i.keys():
if len(i['unprotect_access_levels']) > 0:
access['unprotect_access_level'] = i['unprotect_access_levels'][0]['access_level']
if 'code_owner_approval_required' in i.keys():
access['code_owner_approval_required'] = i['code_owner_approval_required']
if 'allowed_to_push' in i.keys():
if len(i['allowed_to_push']) > 0:
access['allowed_to_push'] = i['allowed_to_push'][0]['access_level']
if 'allowed_to_merge' in i.keys():
if len(i['allowed_to_merge']) > 0:
access['allowed_to_merge'] = i['allowed_to_merge'][0]['access_level']
if 'allowed_to_unprotect' in i.keys():
if len(i['allowed_to_unprotect'] > 0):
access['allowed_to_unprotect'] = i['allowed_to_unprotect'][0]['access_level']
__createProtectedBranch(
url,
token,
id,
access
)
\ No newline at end of file
import requests
import logging
import json
import urllib.parse
import git
import tempfile
import shutil
import os
import re
import base64
# List of file templates
# Format: filename, file location (inside repository)
fileTemplates = {
'Access Request' : '.gitlab/issue_templates/Access Request.md',
'Application - Archive' : '.gitlab/issue_templates/Application - Archive.md',
'Application - Initial' : '.gitlab/issue_templates/Application - Initial.md',
'Application - Update' : '.gitlab/issue_templates/Application - Update.md',
'Bug.md' : '.gitlab/issue_templates/Bug.md',
'Feature Request.md' : '.gitlab/issue_templates/Feature Request.md',
'Leadership Question.md' : '.gitlab/issue_templates/Leadership Question.md',
'New Findings.md' : '.gitlab/issue_templates/New Findings.md',
'Onboarding Question.md' : '.gitlab/issue_templates/Onboarding Question.md',
'Pipeline Failure.md' : '.gitlab/issue_templates/Pipeline Failure.md',
'CODEOWNERS' : '.gitlab/CODEOWNERS'
}
##### Supporting methods
def __getTemplate(url, token, id, file):
file = urllib.parse.quote(file)
file = file.replace("/", "%2F")
url = url + "/api/v4/projects/" + str(id) + "/repository/files/" + file
HEADER = {
'private_token': token
}
PARAMS = {
'ref': 'master'
}
response = requests.get(url, params = PARAMS, headers = HEADER)
if response.status_code == 200:
return response.json()
elif response.status_code == 404 or response.status_code == 403:
return None
else:
logging.critical("Failed to get file: " + str(response.status_code) + " " + response.reason)
def __getProjectURL(url, token, id):
url = url + "/api/v4/projects/" + str(id)
HEADER = {
'private_token': token
}
PARAMS = {
'ref': 'master'
}
response = requests.get(url, params = PARAMS, headers = HEADER)
if response.status_code == 200:
return response.json()['http_url_to_repo']
else:
return ''
def __unprotectBranch(url, token, id):
url = url + "/api/v4/projects/" + str(id) + "/protected_branches"
HEADER = {
'private_token': token
}
# Delete the protected branch first, otherwise this will fail. However, we don't know for sure
# that this is protected so we ignore the response
response = requests.delete(url + "/master", headers = HEADER)
##### Check methods
def check(url, token, tid, pid):
# Location of locally stored filed templates
correct = {}
incorrect = []
for i in fileTemplates:
template = __getTemplate(url, token, tid, fileTemplates[i])
file = __getTemplate(url, token, pid, fileTemplates[i])
if template == None:
print(template)
logging.critical("Template file missing from template project: " + fileTemplates[i])
elif file == None:
incorrect.append(i)
correct[i] = template
elif template['content'] != file['content']:
incorrect.append(i)
correct[i] = template
if len(incorrect) > 0:
logging.warning("File templates incorrect!")
return {
'correct' : correct,
'incorrect': incorrect
}
##### Fix methods
def fix(url, token, tid, pid):
data = check(url, token, tid, pid)
__unprotectBranch(url, token, pid)
repoUrl = __getProjectURL(url, token, pid)
tempDir = tempfile.mkdtemp()
try:
repo = git.Repo.clone_from(repoUrl, tempDir)
repo.git.checkout('master')
except:
logging.critical("Unable to checkout master branch!")
else:
for i in data['incorrect']:
temp = re.search("^(.*)\/", fileTemplates[i])
try:
os.makedirs(tempDir + "/" + temp.group(1), exist_ok = True)
except:
logging.critical("Could not create file template directory: " + tempDir + "/" + temp.group(1))
content = base64.b64decode(data['correct'][i]['content'])
content = content.decode('utf-8')
with open(tempDir + "/" + fileTemplates[i], "w") as tfile:
print(content, file=tfile, end='')
tfile.close()
repo.index.add(tempDir + "/" + fileTemplates[i])
if repo.is_dirty(untracked_files=True):
try:
repo.index.commit('Project template: file templates')
repo.remotes.origin.push('-o ci.skip')
except:
logging.critical("Could not commit/push to project repository!")
shutil.rmtree(tempDir)
\ No newline at end of file
import requests
import logging
import json
##### Supporting methods
def __getProject(url, token, id):
url = url + "/api/v4/projects/" + id
HEADER = {
'private_token': token
}
page = 1
PARAMS = {
'per_page': 100,
'page': page
}
project = {}
response = requests.get(url, params = PARAMS, headers = HEADER)
if response.status_code != 200:
logging.critical("Failed to get project: " + str(response.status_code) + " " + response.reason)
else:
project = response.json()
return project
def __setDefaultBranch(url, token, id, branch):
url = url + "/api/v4/projects/" + str(id)
HEADER = {
'private_token': token
}
PARAMS = {
'default_branch': branch,
}
response = requests.put(url, params = PARAMS, headers = HEADER)
if response.status_code != 200:
logging.critical("Failed to set default branch: " + str(response.status_code) + " " + response.reason)
##### Check methods
def check(url, token, tid, pid):
# Get project settings
tsettings = __getProject(url, token, str(tid))
psettings = __getProject(url, token, str(pid))
default_branch = checkDefaultBranch(tsettings, psettings)
if default_branch != '':
logging.warning("Default branch incorrect!")
return {
'default_branch': default_branch
}
def checkDefaultBranch(tsettings, psettings):
if tsettings['default_branch'] != psettings['default_branch']:
return tsettings['default_branch']
else:
return ''
##### Fix methods
def fix(url, token, tid, pid):
fixes = check(url, token, tid, pid)
if fixes['default_branch'] != '':
fixDefaultBranch(url, token, pid, fixes['default_branch'])
def fixDefaultBranch(url, token, id, branch):
logging.debug("Setting default branch: " + branch)
__setDefaultBranch(url, token, id, branch)
\ No newline at end of file
requests
gitpython
\ No newline at end of file
import requests
import getopt
import sys
import logging
from modules import projects
from modules import branches
from modules import file_templates
from modules import badges
logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S')
########## Get list of projects
def getProjects(url, token, id):
url = url + "/api/v4/groups/" + str(id) + "/projects"
HEADER = {
'private_token': token
}
page = 1
PARAMS = {
'per_page': 100,
'page': page,
'include_subgroups': 'true'
}
projects = []
while True:
PARAMS['page'] = page
response = requests.get(url, params = PARAMS, headers = HEADER)
for i in response.json():
projects.append(i)
if len(response.json()) == 0:
break
page += 1
return projects
########## Main function
def main(argv):
# Process command-line arguments
gitlab_url = ""
gitlab_token = ""
projectTemplate = ""
targetGroup = ""
mode = ""
ignoreProjects = []
runModules = []
allModules = [
'projects',
'file_templates',
'branches',
'badges'
]
usage = []
usage.append("template.py <args>")
usage.append("Argument Description")
usage.append(" --gitlab-url The URL to the GitLab instance.")
usage.append(" --gitlab-token The GitLab access token to use.")
usage.append(" --template-project The GitLab project to be used as a template.")
usage.append(" --target-group The GitLab group to target and apply templates to all subprojects.")
usage.append(" --mode [check/fix] Execute in either check mode or fix mode.")
usage.append(" --ignore-projects Comma separated list of project ID's to skip when checking/fixing projects.")
usage.append(" --run-modules Comma separated list of modules to execute. Specify all to execute all modules.")
try:
opts, args = getopt.getopt(argv,"h",["gitlab-url=","gitlab-token=","template-project=","mode=","ignore-projects=","run-modules=","target-group="])
except getopt.GetoptError:
for i in usage:
print(i)
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print(usage)
sys.exit()
elif opt in ("--gitlab-url"):
gitlab_url = arg
elif opt in ("--gitlab-token"):
gitlab_token = arg
elif opt in ("--template-project"):
projectTemplate = arg
elif opt in ("--mode"):
if arg == 'check' or arg =='fix':
mode = arg
else:
logging.critical("Invalid mode specified!")
sys.exit(1)
elif opt in ("--ignore-projects"):
temp = arg.split(",")
ignoreProjects = temp
elif opt in ("--run-modules"):
if arg == 'all':
runModules = allModules
else:
temp = arg.split(",")
runModules = temp
elif opt in ("--target-group"):
targetGroup = arg
root = logging.getLogger()
root.setLevel(logging.INFO)
ignoreProjects.append(projectTemplate)
logging.info("Skipping projects with ID: " + ", ".join(ignoreProjects))
logging.info("Executing modules: " + ", ".join(runModules))
logging.info("Getting list of projects...")
projectList = getProjects(gitlab_url, gitlab_token, int(targetGroup))
logging.info("Number of projects: " + str(len(projectList)))
count = 1
for i in projectList:
if str(i['id']) in ignoreProjects:
logging.info("Skipping project with ID " + str(i['id']) + " because it was specified in the --ignore-projects parameter.")
else:
logging.info("[" + str(count) + "/" + str(len(projectList)) + "] " + i['path_with_namespace'])
if mode == 'check':
if 'projects' in runModules:
projects.check(gitlab_url, gitlab_token, projectTemplate, i['id'])
if 'file_templates' in runModules:
file_templates.check(gitlab_url, gitlab_token, projectTemplate, i['id'])
if 'branches' in runModules:
branches.check(gitlab_url, gitlab_token, projectTemplate, i['id'])
if 'badges' in runModules:
badges.check(gitlab_url, gitlab_token, projectTemplate, i['id'])
elif mode == 'fix':
if 'projects' in runModules:
projects.fix(gitlab_url, gitlab_token, projectTemplate, i['id'])
if 'file_templates' in runModules:
# file_templates must be first because we unprotect the branch, because of this
# the branches module will always identify the branches as misconfigured.
file_templates.fix(gitlab_url, gitlab_token, projectTemplate, i['id'])
if 'branches' in runModules:
branches.fix(gitlab_url, gitlab_token, projectTemplate, i['id'])
if 'badges' in runModules:
badges.fix(gitlab_url, gitlab_token, projectTemplate, i['id'])
else:
logging.critical("Unsupported mode of operation!")
count += 1
if __name__ == "__main__":
main(sys.argv[1:])
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment