diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 4df1905c..f24e999a 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,92 +1,27 @@ -########################### -########################### -## Linter GitHub Actions ## -########################### -########################### +name: Lint -name: Lint Code Base - -# -# Documentation: -# https://help.github.com/en/articles/workflow-syntax-for-github-actions -# - -############################# -# Start the job on all push # -############################# on: push: branches: [master] pull_request: - branches-ignore: [master] - + branches: [master] -############### -# Set the Job # -############### jobs: - build: - name: Lint Code Base - # Set the agent to run on + ruff: + name: Ruff runs-on: ubuntu-latest - - ################## - # Load all steps # - ################### steps: - ########################## - # Checkout the code base # - ########################## - - name: Checkout Code - uses: actions/checkout@v4 - with: - # Full git history is needed to get a proper list of changed files within `super-linter` - fetch-depth: 0 + - name: Checkout Code + uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' - - name: Install Required packages - run: | - sudo apt-get update -qq - sudo apt-get install -y python3-venv python3-virtualenv libvirt-dev libldap2-dev libsasl2-dev python3-lxml zlib1g-dev libxslt1-dev pkg-config gcc libssl-dev - - - name: Create & Activate VENV - run: | - python3 -m venv venv - echo "$GITHUB_WORKSPACE/venv/bin" >> "$GITHUB_PATH" - - - name: Install dependencies - run: | - pip3 install --upgrade pip setuptools wheel - if [ -f dev/requirements.txt ]; then pip3 install -r dev/requirements.txt; else pip3 install -r conf/requirements.txt; fi - ################################ - # Run Linter against code base # - ################################ - - name: Lint Code Base - uses: docker://github/super-linter:latest - env: - FILTER_REGEX_EXCLUDE: .*(static|scss|venv|locale|templates)/.* - DEFAULT_BRANCH: master - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VALIDATE_ALL_CODEBASE: false - VALIDATE_MARKDOWN: false - VALIDATE_HTML: false - VALIDATE_JSCPD: false - VALIDATE_ANSIBLE: false - VALIDATE_CLOJURE: false - VALIDATE_COFFEE: false - VALIDATE_DART: false - VALIDATE_GO: false - VALIDATE_JSX: false - VALIDATE_KOTLIN: false - VALIDATE_POWERSHELL: false - VALIDATE_PERL: false - VALIDATE_PHP: false - VALIDATE_RAKU: false - VALIDATE_RUBY: false - VALIDATE_TSX: false - VALIDATE_TERRAFORM: false + # Same ruff version as dev/requirements.txt + - name: Install Ruff + run: pip install "$(grep '^ruff==' dev/requirements.txt)" + - name: Run Ruff + run: ruff check --output-format=github . diff --git a/accounts/test_utils.py b/accounts/test_utils.py index 124035d4..3af58b69 100644 --- a/accounts/test_utils.py +++ b/accounts/test_utils.py @@ -1,6 +1,5 @@ import base64 import struct -from unittest.mock import patch from django.contrib.auth import get_user_model from django.core import mail diff --git a/accounts/views.py b/accounts/views.py index eb4d2af3..152a726b 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -20,7 +20,7 @@ from accounts.apps import admin_password_path from instances.models import Instance from accounts.forms import EmailOTPForm, ProfileForm, UserSSHKeyForm -from accounts.models import * +from accounts.models import User, UserAttributes, UserInstance, UserSSHKey from . import forms from .utils import get_user_totp_device, send_email_with_otp diff --git a/admin/migrations/0003_create_group_technicians.py b/admin/migrations/0003_create_group_technicians.py index d5b1cae8..81684428 100644 --- a/admin/migrations/0003_create_group_technicians.py +++ b/admin/migrations/0003_create_group_technicians.py @@ -1,4 +1,4 @@ -from django.db import models, migrations +from django.db import migrations def apply_migration(apps, schema_editor): Group = apps.get_model('auth', 'Group') diff --git a/appsettings/middleware.py b/appsettings/middleware.py index 737477de..b65de620 100644 --- a/appsettings/middleware.py +++ b/appsettings/middleware.py @@ -1,4 +1,4 @@ -from .settings import app_settings, get_settings +from .settings import get_settings class AppSettingsMiddleware(object): diff --git a/appsettings/migrations/0007_auto_20220905_0918.py b/appsettings/migrations/0007_auto_20220905_0918.py index 229e1cbf..75060ea3 100644 --- a/appsettings/migrations/0007_auto_20220905_0918.py +++ b/appsettings/migrations/0007_auto_20220905_0918.py @@ -1,7 +1,6 @@ # Generated by Django 3.2.13 on 2022-06-30 07:17 from django.db import migrations -from django.utils.translation import gettext_lazy as _ def update_default_settings(apps, schema_editor): setting = apps.get_model("appsettings", "AppSettings") diff --git a/appsettings/test_appsettings.py b/appsettings/test_appsettings.py index a0cd3db6..5709ba56 100644 --- a/appsettings/test_appsettings.py +++ b/appsettings/test_appsettings.py @@ -1,4 +1,4 @@ -from django.test import Client, TestCase +from django.test import TestCase from django.urls import reverse from appsettings.models import AppSettings diff --git a/appsettings/tests.py b/appsettings/tests.py index 7ce503c2..49290204 100644 --- a/appsettings/tests.py +++ b/appsettings/tests.py @@ -1,3 +1,2 @@ -from django.test import TestCase # Create your tests here. diff --git a/appsettings/views.py b/appsettings/views.py index 3b7ff6e4..e79f926c 100644 --- a/appsettings/views.py +++ b/appsettings/views.py @@ -3,7 +3,6 @@ import os import sass from admin.decorators import superuser_only from django.contrib import messages -from django.contrib.auth.decorators import login_required from django.http import HttpResponseRedirect from django.shortcuts import render from django.utils.translation import gettext_noop as _ diff --git a/computes/views.py b/computes/views.py index 2b328652..d7951302 100644 --- a/computes/views.py +++ b/computes/views.py @@ -8,10 +8,6 @@ from django.utils import timezone from instances.models import Instance from libvirt import libvirtError from vrtManager.connection import ( - CONN_SOCKET, - CONN_SSH, - CONN_TCP, - CONN_TLS, connection_manager, wvmConnect, ) diff --git a/console/models.py b/console/models.py index 71a83623..35e0d648 100644 --- a/console/models.py +++ b/console/models.py @@ -1,3 +1,2 @@ -from django.db import models # Create your models here. diff --git a/datasource/test_datasource.py b/datasource/test_datasource.py index cbaf19fa..f5354489 100644 --- a/datasource/test_datasource.py +++ b/datasource/test_datasource.py @@ -1,11 +1,10 @@ import json -from unittest.mock import MagicMock, patch from django.test import RequestFactory, TestCase from django.urls import reverse from computes.models import Compute -from datasource.views import get_client_ip, get_hostname_by_ip, os_index, os_metadata_json, os_userdata +from datasource.views import get_client_ip, get_hostname_by_ip class DataSourceTestCase(TestCase): diff --git a/datasource/tests.py b/datasource/tests.py index 7ce503c2..49290204 100644 --- a/datasource/tests.py +++ b/datasource/tests.py @@ -1,3 +1,2 @@ -from django.test import TestCase # Create your tests here. diff --git a/instances/api/viewsets.py b/instances/api/viewsets.py index cbe92ff9..ce23e375 100644 --- a/instances/api/viewsets.py +++ b/instances/api/viewsets.py @@ -290,7 +290,7 @@ class CreateInstanceViewSet(viewsets.ViewSet): volume_list.append(volume) with utils.libvirt_compute_lock(compute): - ret = conn.create_instance( + conn.create_instance( name=serializer.validated_data["name"], memory=serializer.validated_data["memory"], vcpu=serializer.validated_data["vcpu"], diff --git a/instances/test_disk_isolation.py b/instances/test_disk_isolation.py index 2d0044ad..0bf5657f 100644 --- a/instances/test_disk_isolation.py +++ b/instances/test_disk_isolation.py @@ -4,7 +4,7 @@ disk and media mutation views must be superuser-only (matching the UI, where the Disk tab is only rendered for superusers), and even for superusers the views must not act on volumes or option values taken blindly from the client. """ -from unittest.mock import MagicMock, patch +from unittest.mock import patch from django.contrib.auth import get_user_model from django.test import TestCase diff --git a/instances/test_security_mutations.py b/instances/test_security_mutations.py index d9f20954..7196cafd 100644 --- a/instances/test_security_mutations.py +++ b/instances/test_security_mutations.py @@ -271,7 +271,7 @@ class InstanceSecurityMutationsTestCase(TestCase): with patch("instances.utils.connection_manager.host_is_up", return_value=True), \ patch("instances.utils.wvmInstances") as mock_instances_cls, \ - patch("instances.utils.wvmInstance") as mock_instance_cls, \ + patch("instances.utils.wvmInstance"), \ patch("instances.utils.transaction.atomic"), \ patch("instances.utils.Instance") as mock_instance_model: diff --git a/instances/tests.py b/instances/tests.py index dd759562..e5f66703 100644 --- a/instances/tests.py +++ b/instances/tests.py @@ -10,7 +10,6 @@ from django.contrib.auth.models import Permission from django.http.response import Http404 from django.shortcuts import reverse from django.test import TestCase -from instances.views import instance from libvirt import VIR_DOMAIN_UNDEFINE_NVRAM from vrtManager.create import wvmCreate from vrtManager.util import randomUUID diff --git a/interfaces/api/viewsets.py b/interfaces/api/viewsets.py index 53a67f5e..8d8189f5 100644 --- a/interfaces/api/viewsets.py +++ b/interfaces/api/viewsets.py @@ -1,7 +1,7 @@ from admin.permissions import IsSuperUser from django.shortcuts import get_object_or_404 from computes.models import Compute -from rest_framework import status, viewsets +from rest_framework import viewsets from rest_framework.response import Response from vrtManager.interface import wvmInterfaces, wvmInterface diff --git a/interfaces/tests.py b/interfaces/tests.py index 7ce503c2..49290204 100644 --- a/interfaces/tests.py +++ b/interfaces/tests.py @@ -1,3 +1,2 @@ -from django.test import TestCase # Create your tests here. diff --git a/logs/tests.py b/logs/tests.py index 7ce503c2..49290204 100644 --- a/logs/tests.py +++ b/logs/tests.py @@ -1,3 +1,2 @@ -from django.test import TestCase # Create your tests here. diff --git a/networks/tests.py b/networks/tests.py index 7ce503c2..49290204 100644 --- a/networks/tests.py +++ b/networks/tests.py @@ -1,3 +1,2 @@ -from django.test import TestCase # Create your tests here. diff --git a/nwfilters/models.py b/nwfilters/models.py index 71a83623..35e0d648 100644 --- a/nwfilters/models.py +++ b/nwfilters/models.py @@ -1,3 +1,2 @@ -from django.db import models # Create your models here. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..486d282b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[tool.ruff] +target-version = "py310" +extend-exclude = ["static"] + +[tool.ruff.lint] +# Syntax errors and pyflakes; widen the rule set step by step. +select = ["E9", "F"] + +[tool.ruff.lint.per-file-ignores] +# Settings overlay: re-exports the base settings by design. +"webvirtcloud/settings-dev.py" = ["F403", "F405"] diff --git a/storages/api/viewsets.py b/storages/api/viewsets.py index b90e5e78..f55f1d48 100644 --- a/storages/api/viewsets.py +++ b/storages/api/viewsets.py @@ -3,7 +3,7 @@ from appsettings.settings import app_settings from computes.models import Compute from django.shortcuts import get_object_or_404 from drf_spectacular.utils import extend_schema, inline_serializer -from rest_framework import serializers, status, viewsets +from rest_framework import serializers, viewsets from rest_framework.decorators import action from rest_framework.response import Response from vrtManager.storage import wvmStorage, wvmStorages diff --git a/storages/views.py b/storages/views.py index 7d031ab9..88d125d2 100644 --- a/storages/views.py +++ b/storages/views.py @@ -290,8 +290,6 @@ def create_volume(request, compute_id, pool): compute.hostname, compute.login, compute.password, compute.type, pool ) - storages = conn.get_storages() - form = CreateVolumeForm(request.POST or None) if form.is_valid(): data = form.cleaned_data diff --git a/virtsecrets/models.py b/virtsecrets/models.py index 71a83623..35e0d648 100644 --- a/virtsecrets/models.py +++ b/virtsecrets/models.py @@ -1,3 +1,2 @@ -from django.db import models # Create your models here. diff --git a/virtsecrets/tests.py b/virtsecrets/tests.py index 7ce503c2..49290204 100644 --- a/virtsecrets/tests.py +++ b/virtsecrets/tests.py @@ -1,3 +1,2 @@ -from django.test import TestCase # Create your tests here. diff --git a/vrtManager/test_rwlock.py b/vrtManager/test_rwlock.py index 1fbcf308..51ec744d 100644 --- a/vrtManager/test_rwlock.py +++ b/vrtManager/test_rwlock.py @@ -128,7 +128,6 @@ class TestReadWriteLock(unittest.TestCase): def test_writer_blocks_subsequent_readers(self): """Pending writers take priority and should block subsequent new readers.""" order = [] - lock_held_event = threading.Event() writer_ready_event = threading.Event() # Step 1: Initial reader holds read lock diff --git a/vrtManager/test_util.py b/vrtManager/test_util.py index dced762a..13abd6a6 100644 --- a/vrtManager/test_util.py +++ b/vrtManager/test_util.py @@ -1,4 +1,3 @@ -import re import unittest from django.conf import settings diff --git a/vrtManager/test_xml_safety.py b/vrtManager/test_xml_safety.py index 4dca4cf9..df0bab7d 100644 --- a/vrtManager/test_xml_safety.py +++ b/vrtManager/test_xml_safety.py @@ -290,7 +290,6 @@ class TestPersistentDiskEditing(unittest.TestCase): ) def test_running_bus_change_preserves_disk_and_pending_domain_configuration(self): - from lxml import etree self.assertTrue(self.domain.isActive()) live_before = self.domain.XMLDesc(0) self.edit(bus="sata") diff --git a/vrtManager/util.py b/vrtManager/util.py index 81cb3d55..7ec27f80 100644 --- a/vrtManager/util.py +++ b/vrtManager/util.py @@ -6,7 +6,7 @@ import string import libvirt import lxml.etree as etree -from django.conf import UserSettingsHolder, settings +from django.conf import settings def is_kvm_available(xml):