Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: setup pre-commit #234

Merged
merged 9 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions .azure-pipelines/scripts/combine-coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
It is up to pipeline authors to avoid name collisions when deviating from the recommended format.
"""

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os
import re
Expand All @@ -20,12 +18,12 @@ def main():
"""Main program entry point."""
source_directory = sys.argv[1]

if '/ansible_collections/' in os.getcwd():
if "/ansible_collections/" in os.getcwd():
output_path = "tests/output"
else:
output_path = "test/results"

destination_directory = os.path.join(output_path, 'coverage')
destination_directory = os.path.join(output_path, "coverage")

if not os.path.exists(destination_directory):
os.makedirs(destination_directory)
Expand All @@ -34,27 +32,27 @@ def main():
count = 0

for name in os.listdir(source_directory):
match = re.search('^Coverage (?P<attempt>[0-9]+) (?P<label>.+)$', name)
label = match.group('label')
attempt = int(match.group('attempt'))
match = re.search("^Coverage (?P<attempt>[0-9]+) (?P<label>.+)$", name)
label = match.group("label")
attempt = int(match.group("attempt"))
jobs[label] = max(attempt, jobs.get(label, 0))

for label, attempt in jobs.items():
name = 'Coverage {attempt} {label}'.format(label=label, attempt=attempt)
name = f"Coverage {attempt} {label}"
source = os.path.join(source_directory, name)
source_files = os.listdir(source)

for source_file in source_files:
source_path = os.path.join(source, source_file)
destination_path = os.path.join(destination_directory, source_file + '.' + label)
print('"%s" -> "%s"' % (source_path, destination_path))
destination_path = os.path.join(destination_directory, source_file + "." + label)
print(f'"{source_path}" -> "{destination_path}"')
shutil.copyfile(source_path, destination_path)
count += 1

print('Coverage file count: %d' % count)
print('##vso[task.setVariable variable=coverageFileCount]%d' % count)
print('##vso[task.setVariable variable=outputPath]%s' % output_path)
print("Coverage file count: %d" % count)
print("##vso[task.setVariable variable=coverageFileCount]%d" % count)
print("##vso[task.setVariable variable=outputPath]%s" % output_path)


if __name__ == '__main__':
if __name__ == "__main__":
main()
10 changes: 4 additions & 6 deletions .azure-pipelines/scripts/time-command.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#!/usr/bin/env python
"""Prepends a relative timestamp to each input line from stdin and writes it to stdout."""

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import sys
import time
Expand All @@ -12,14 +10,14 @@ def main():
"""Main program entry point."""
start = time.time()

sys.stdin.reconfigure(errors='surrogateescape')
sys.stdout.reconfigure(errors='surrogateescape')
sys.stdin.reconfigure(errors="surrogateescape")
sys.stdout.reconfigure(errors="surrogateescape")

for line in sys.stdin:
seconds = time.time() - start
sys.stdout.write('%02d:%02d %s' % (seconds // 60, seconds % 60, line))
sys.stdout.write("%02d:%02d %s" % (seconds // 60, seconds % 60, line))
sys.stdout.flush()


if __name__ == '__main__':
if __name__ == "__main__":
main()
23 changes: 23 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Lint

on:
push:
branches: [main]
pull_request:

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup python
uses: actions/setup-python@v4
with:
python-version: 3.x

- name: Install dependencies
run: pip install pre-commit

- name: Run pre-commit
run: pre-commit run --all-files --show-diff-on-failure
Comment on lines +19 to +23
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jooola FYI there's an official action for this. Actually, a pair of actions: https://pre-commit.ci/lite#example-using-pre-commit-action.

Besides, it's possible to enable the hosted service for this repo and then, it shouldn't be necessary to have a duplicate GHA workflow.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the links, I didn't know pre-commit.ci was working on a new GitHub action. I remember the old one being deprecated in favor of the pre-commit.ci service.

For our use case I think this is just fine, and once the new GitHub action is out of beta we might reconsider this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use pre-commit.ci? Using GHA seems like a waste in this case, especially since the GHA resources are shared across the entire org.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no experience with pre-commit.ci, I implemented something that has been working for me for ages. But I am happy to start using it to reduce the GHA resources usage.

With that said, I recently stumbled on https://results.pre-commit.ci/run/github/244995547/1688396810.pSqkyRKhQqGD40pGmTdY1Q and I haven't figured out how to solve this issue yet.

I will take some time once I am done with the current PRs I am working on.

11 changes: 11 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
stages:
- lint
- sanity
- integration

Expand All @@ -8,6 +9,16 @@ variables:
default:
image: python:$PYTHON_VERSION

pre-commit:
stage: lint

image: python:3.11-alpine
before_script:
- apk add build-base git
- pip install pre-commit
script:
- pre-commit run --all-files --show-diff-on-failure

sanity:
stage: sanity
allow_failure: true
Expand Down
43 changes: 43 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-symlinks
- id: destroyed-symlinks

- id: check-json
- id: check-yaml
- id: check-toml

- id: check-merge-conflict
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
files: \.(md|ya?ml)$
exclude: ^changelogs/changelog.yaml$

- repo: https://github.com/asottile/pyupgrade
rev: v3.7.0
hooks:
- id: pyupgrade
args: [--py37-plus]

- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort

- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
10 changes: 3 additions & 7 deletions plugins/doc_fragments/hcloud.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <[email protected]>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function

__metaclass__ = type


class ModuleDocFragment(object):
DOCUMENTATION = '''
class ModuleDocFragment:
DOCUMENTATION = """
options:
api_token:
description:
Expand All @@ -26,4 +22,4 @@ class ModuleDocFragment(object):
- name: Documentation for Hetzner Cloud API
description: Complete reference for the Hetzner Cloud API.
link: https://docs.hetzner.cloud/
'''
"""
70 changes: 36 additions & 34 deletions plugins/inventory/hcloud.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# Copyright (c) 2019 Hetzner Cloud GmbH <[email protected]>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)

__metaclass__ = type

DOCUMENTATION = r'''
DOCUMENTATION = r"""
name: hcloud
author:
- Lukas Kaemmerling (@lkaemmerling)
Expand Down Expand Up @@ -84,7 +81,7 @@
type: list
elements: str
required: false
'''
"""

EXAMPLES = r"""
# Minimal example. `HCLOUD_TOKEN` is exposed in environment.
Expand Down Expand Up @@ -118,27 +115,30 @@
"""

import os
from ipaddress import IPv6Network

from ansible.errors import AnsibleError
from ansible.module_utils._text import to_native
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.release import __version__
from ipaddress import IPv6Network

try:
from hcloud import hcloud
from hcloud import APIException
from hcloud import APIException, hcloud

HAS_HCLOUD = True
except ImportError:
HAS_HCLOUD = False


class InventoryModule(BaseInventoryPlugin, Constructable):
NAME = 'hetzner.hcloud.hcloud'
NAME = "hetzner.hcloud.hcloud"

def _configure_hcloud_client(self):
self.token_env = self.get_option("token_env")
self.templar.available_variables = self._vars
self.api_token = self.templar.template(self.get_option("token"), fail_on_undefined=False) or os.getenv(self.token_env)
self.api_token = self.templar.template(self.get_option("token"), fail_on_undefined=False) or os.getenv(
self.token_env
)
if self.api_token is None:
raise AnsibleError(
"Please specify a token, via the option token, via environment variable HCLOUD_TOKEN "
Expand All @@ -147,10 +147,12 @@ def _configure_hcloud_client(self):

self.endpoint = os.getenv("HCLOUD_ENDPOINT") or "https://api.hetzner.cloud/v1"

self.client = hcloud.Client(token=self.api_token,
api_endpoint=self.endpoint,
application_name="ansible-inventory",
application_version=__version__)
self.client = hcloud.Client(
token=self.api_token,
api_endpoint=self.endpoint,
application_name="ansible-inventory",
application_version=__version__,
)

def _test_hcloud_token(self):
try:
Expand All @@ -168,14 +170,15 @@ def _get_servers(self):

def _filter_servers(self):
if self.get_option("network"):
network = self.templar.template(self.get_option("network"), fail_on_undefined=False) or self.get_option("network")
network = self.templar.template(self.get_option("network"), fail_on_undefined=False) or self.get_option(
"network"
)
try:
self.network = self.client.networks.get_by_name(network)
if self.network is None:
self.network = self.client.networks.get_by_id(network)
except APIException:
raise AnsibleError(
"The given network is not found.")
raise AnsibleError("The given network is not found.")

tmp = []
for server in self.servers:
Expand Down Expand Up @@ -225,16 +228,17 @@ def _set_server_attributes(self, server):

if server.public_net.ipv6:
self.inventory.set_variable(server.name, "ipv6_network", to_native(server.public_net.ipv6.network))
self.inventory.set_variable(server.name, "ipv6_network_mask", to_native(server.public_net.ipv6.network_mask))
self.inventory.set_variable(server.name, "ipv6", to_native(self._first_ipv6_address(server.public_net.ipv6.ip)))
self.inventory.set_variable(
server.name, "ipv6_network_mask", to_native(server.public_net.ipv6.network_mask)
)
self.inventory.set_variable(
server.name, "ipv6", to_native(self._first_ipv6_address(server.public_net.ipv6.ip))
)

self.inventory.set_variable(
server.name,
"private_networks",
[
{"name": n.network.name, "id": n.network.id, "ip": n.ip}
for n in server.private_net
],
[{"name": n.network.name, "id": n.network.id, "ip": n.ip} for n in server.private_net],
)

if self.get_option("network"):
Expand Down Expand Up @@ -306,21 +310,17 @@ def _get_server_ansible_host(self, server):
return to_native(server_private_network.ip)

else:
raise AnsibleError(
"You can only connect via private IPv4 if you specify a network")
raise AnsibleError("You can only connect via private IPv4 if you specify a network")

def _first_ipv6_address(self, network):
return next(IPv6Network(network).hosts())

def verify_file(self, path):
"""Return the possibly of a file being consumable by this plugin."""
return (
super(InventoryModule, self).verify_file(path) and
path.endswith(("hcloud.yaml", "hcloud.yml"))
)
return super().verify_file(path) and path.endswith(("hcloud.yaml", "hcloud.yml"))

def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path, cache)
super().parse(inventory, loader, path, cache)

if not HAS_HCLOUD:
raise AnsibleError("The Hetzner Cloud dynamic inventory plugin requires hcloud-python.")
Expand All @@ -339,13 +339,15 @@ def parse(self, inventory, loader, path, cache=True):
self._set_server_attributes(server)

# Use constructed if applicable
strict = self.get_option('strict')
strict = self.get_option("strict")

# Composed variables
self._set_composite_vars(self.get_option('compose'), self.inventory.get_host(server.name).get_vars(), server.name, strict=strict)
self._set_composite_vars(
self.get_option("compose"), self.inventory.get_host(server.name).get_vars(), server.name, strict=strict
)

# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
self._add_host_to_composed_groups(self.get_option('groups'), {}, server.name, strict=strict)
self._add_host_to_composed_groups(self.get_option("groups"), {}, server.name, strict=strict)

# Create groups based on variable values and add the corresponding hosts to it
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), {}, server.name, strict=strict)
self._add_host_to_keyed_groups(self.get_option("keyed_groups"), {}, server.name, strict=strict)
6 changes: 1 addition & 5 deletions plugins/module_utils/hcloud.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <[email protected]>

# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)

from __future__ import absolute_import, division, print_function

__metaclass__ = type

from ansible.module_utils.ansible_release import __version__
from ansible.module_utils.basic import env_fallback, missing_required_lib
Expand All @@ -18,7 +14,7 @@
HAS_HCLOUD = False


class Hcloud(object):
class Hcloud:
def __init__(self, module, represent):
self.module = module
self.represent = represent
Expand Down
Loading