Commit 88e0b0f3 authored by Brennen Bearnes's avatar Brennen Bearnes
Browse files

roll settings commands into a single wrapper using click

This is still a little clunky and repetitive, code-wise, but a nicer
interface.

The `settings` script now has 3 subcommands:

    diff    Show differences between instance and settings.yaml
    update  Update settings on instance to match local settings.yaml.
    view    Show all instance settings.

Additionally, it takes parameters for instance URL and token, which can
also be specified by environment variables.

Background:

  - https://click.palletsprojects.com/en/8.0.x/
  - https://pypi.org/project/click/
parent 37849f82
...@@ -21,13 +21,16 @@ Usage ...@@ -21,13 +21,16 @@ Usage
View current instance settings: View current instance settings:
```sh ```sh
./view-settings ./settings view
``` ```
Apply instance settings from `settings.yaml`: Show differences between instance settings and what's specified explicitly in
the local `settings.yaml`:
Update instance settings from `settings.yaml`:
```sh ```sh
./apply-settings ./settings update
``` ```
Apply project settings (at the moment, this disables wikis and issue tracking Apply project settings (at the moment, this disables wikis and issue tracking
......
#!/usr/bin/env python3
"""
apply-settings - apply settings from settings.yaml to GitLab instance
"""
import copy
import json
import os
import gitlab
import requests
import sys
import yaml
import gitlab_settings
from gitlab_settings.util import confirm
from gitlab_settings.util import diffsettings
from gitlab_settings.util import get_token
token = get_token()
url = 'https://gitlab.wikimedia.org/api/v4/application/settings'
headers = {
'User-Agent': 'gitlab-settings/0.0.1',
'PRIVATE-TOKEN': token
}
# Get a baseline list of settings from API for diffing:
r = requests.get(url, headers=headers)
r.raise_for_status()
original_instance_settings = r.json()
# Get the settings we want to apply from YAML file in the repo:
with open('settings.yaml') as f:
local_settings = yaml.safe_load(f)
print()
print("Difference between local settings file and instance settings:")
desired_settings = copy.deepcopy(original_instance_settings)
desired_settings.update(local_settings)
diffsettings(original_instance_settings, desired_settings)
print()
if not confirm('Does the diff look good?'):
print("Exiting without changes.")
exit()
if not confirm('Did you log these changes in #wikimedia-releng?'):
print("Exiting without changes.")
exit()
# Do some type juggling so we pass strings instead of booleans to the API:
for x, y in local_settings.items():
if y == True:
local_settings[x] = 'true'
elif y == False:
local_settings[x] = 'false'
try:
r = requests.put(url, headers=headers, json=local_settings)
r.raise_for_status()
new_instance_settings = r.json()
except:
print(r.text)
exit()
# Display diff of applied settings:
print()
print("Changed settings: ")
diffsettings(original_instance_settings, new_instance_settings)
import difflib import difflib
import sys
import json
import getpass import getpass
import json
import os
import sys
def get_token(): def get_token():
if os.environ.get('GITLAB_TOKEN'):
return os.environ.get('GITLAB_TOKEN')
return getpass.getpass('GitLab token with api scope: ').strip() return getpass.getpass('GitLab token with api scope: ').strip()
def confirm(question="Continue?", default=False): def confirm(question="Continue?", default=False):
...@@ -45,9 +48,12 @@ def confirm(question="Continue?", default=False): ...@@ -45,9 +48,12 @@ def confirm(question="Continue?", default=False):
return result return result
def diffsettings(old, new): def diffsettings(old, new):
output = ''
d = difflib.Differ() d = difflib.Differ()
old_lines = json.dumps(old, indent=4).splitlines() old_lines = json.dumps(old, indent=4).splitlines()
new_lines = json.dumps(new, indent=4).splitlines() new_lines = json.dumps(new, indent=4).splitlines()
for thing in d.compare(old_lines, new_lines): for thing in d.compare(old_lines, new_lines):
if thing.startswith('-') or thing.startswith('+') or thing.startswith('?'): if thing.startswith('-') or thing.startswith('+') or thing.startswith('?'):
print(thing) output += thing
return output
#!/usr/bin/env python3
"""
settings - compare settings.yaml to Wikimedia GitLab instance settings
"""
import copy
import os
import json
import sys
import click
import gitlab
import requests
import yaml
import gitlab_settings
from gitlab_settings.util import confirm
from gitlab_settings.util import diffsettings
# The following uses the pattern described here:
# https://click.palletsprojects.com/en/5.x/commands/#nested-handling-and-contexts
@click.group()
@click.option(
'--instance',
default='https://gitlab.wikimedia.org',
help='Instance to configure.'
)
@click.option(
'--token',
prompt=True,
help='GitLab access token with API scope. '
'Better idea: Set GITLAB_TOKEN in environment.'
)
@click.pass_context
def cli(ctx, instance, token):
ctx.obj['instance'] = instance
ctx.obj['url'] = ctx.obj['instance'] + '/api/v4/application/settings'
ctx.obj['token'] = token
ctx.obj['headers'] = {
'User-Agent': 'gitlab-settings/0.0.1',
'PRIVATE-TOKEN': ctx.obj['token']
}
@click.command()
@click.pass_context
def view(ctx):
"""Get a baseline list of settings from API."""
try:
req = requests.get(ctx.obj['url'], headers=ctx.obj['headers'])
req.raise_for_status()
except:
click.echo(req.text)
sys.exit()
original_instance_settings = req.json()
click.echo(json.dumps(original_instance_settings, indent=4))
@click.command()
@click.pass_context
def diff(ctx):
"""Show differences between instance and settings in local settings.yaml."""
# Get a baseline list of settings from API for diffing:
req = requests.get(ctx.obj['url'], headers=ctx.obj['headers'])
req.raise_for_status()
original_instance_settings = req.json()
# Get the settings we want to apply from YAML file in the repo:
with open('settings.yaml') as f:
local_settings = yaml.safe_load(f)
click.echo("Difference between local settings file and instance settings:")
desired_settings = copy.deepcopy(original_instance_settings)
desired_settings.update(local_settings)
click.echo(diffsettings(original_instance_settings, desired_settings))
@click.command()
@click.pass_context
def update(ctx):
"""Update settings on instance to match local settings.yaml."""
try:
req = requests.get(ctx.obj['url'], headers=ctx.obj['headers'])
req.raise_for_status()
except:
click.echo(req.text)
sys.exit()
original_instance_settings = req.json()
# Get the settings we want to apply from YAML file in the repo:
with open('settings.yaml') as f:
local_settings = yaml.safe_load(f)
click.echo()
click.echo("Difference between local settings file and instance settings:")
desired_settings = copy.deepcopy(original_instance_settings)
desired_settings.update(local_settings)
click.echo(diffsettings(original_instance_settings, desired_settings))
click.echo()
if not confirm('Does the diff look good?'):
click.echo("Exiting without changes.")
sys.exit()
if not confirm('Did you log these changes in #wikimedia-releng?'):
click.echo("Exiting without changes.")
sys.exit()
# Do some type juggling so we pass strings instead of booleans to the API:
for x, y in local_settings.items():
if y is True:
local_settings[x] = 'true'
elif y is False:
local_settings[x] = 'false'
try:
req = requests.put(ctx.obj['url'], headers=ctx.obj['headers'], json=local_settings)
req.raise_for_status()
new_instance_settings = req.json()
except:
click.echo(req.text)
sys.exit()
# Display diff of applied settings:
click.echo()
click.echo("Changed settings: ")
click.echo(diffsettings(original_instance_settings, new_instance_settings))
cli.add_command(view)
cli.add_command(diff)
cli.add_command(update)
if __name__ == '__main__':
cli(obj={}, auto_envvar_prefix='GITLAB')
#!/usr/bin/env python3
"""
view-settings - view current settings for GitLab instance
"""
import copy
import difflib
import json
import os
import requests
import sys
import yaml
from gitlab_settings.util import get_token
token = get_token()
url = 'https://gitlab.wikimedia.org/api/v4/application/settings'
headers = {
'User-Agent': 'gitlab-settings/0.0.1',
'PRIVATE-TOKEN': token
}
# Get a baseline list of settings from API for diffing:
r = requests.get(url, headers=headers)
r.raise_for_status()
original_instance_settings = r.json()
print(json.dumps(original_instance_settings, indent=4))
Supports Markdown
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