Skip to content
  •  
  •  
  •  
85 changes: 0 additions & 85 deletions .github/workflows/pylint-checks.yml

This file was deleted.

117 changes: 112 additions & 5 deletions .github/workflows/quality-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,197 @@
push:
branches:
- master
- open-release/lilac.master
- release/**

jobs:
run_tests:
name: Quality Others
ruff:
name: Ruff
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Get pip cache dir
id: pip-cache-dir
run: echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT

- name: Cache pip dependencies
uses: actions/cache@v5
with:
path: ${{ steps.pip-cache-dir.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('requirements/edx/testing.txt') }}
restore-keys: ${{ runner.os }}-pip-

- name: Install quality requirements
run: pip install -r requirements/edx/testing.txt

- name: Run ruff
run: ruff check --output-format=github .

policy-checks:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Comment on lines +13 to +40
name: Policy & Security Checks
needs: [ruff]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-24.04]
python-version:
- "3.12"
node-version: [20]

steps:
- uses: actions/checkout@v6
with:
fetch-depth: 2

- name: Fetch base branch for comparison
run: git fetch --depth=1 origin ${{ github.base_ref }}

- name: Install Required System Packages
run: sudo apt-get update && sudo apt-get install libxmlsec1-dev

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}

- name: Setup npm
run: npm i -g npm@8.5.x

- name: Get pip cache dir
id: pip-cache-dir
run: |
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT

- name: Cache pip dependencies
id: cache-dependencies
uses: actions/cache@v5
with:
path: ${{ steps.pip-cache-dir.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('requirements/edx/testing.txt') }}
restore-keys: ${{ runner.os }}-pip-

- name: Install Required Python Dependencies
env:
PIP_SRC: ${{ runner.temp }}
run: |
make test-requirements

- name: Install npm
env:
PIP_SRC: ${{ runner.temp }}
run: npm ci

- name: Install python packages
env:
PIP_SRC: ${{ runner.temp }}
run: |
pip install -e .

- name: Run Quality Tests
- name: Run Policy Checks
env:
PIP_SRC: ${{ runner.temp }}
TARGET_BRANCH: ${{ github.base_ref }}
run: |
ruff check --output-format=github .
make xsslint
make pii_check
make check_keywords

- name: Save Job Artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: Build-Artifacts
path: |
**/reports/**/*
test_root/log/**/*.log
*.log
overwrite: true

run-pylint:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
needs: [ruff]
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- module-name: lms-1
path: "lms/djangoapps/badges/ lms/djangoapps/branding/ lms/djangoapps/bulk_email/ lms/djangoapps/bulk_enroll/ lms/djangoapps/bulk_user_retirement/ lms/djangoapps/ccx/ lms/djangoapps/certificates/ lms/djangoapps/commerce/ lms/djangoapps/course_api/ lms/djangoapps/course_blocks/ lms/djangoapps/course_home_api/ lms/djangoapps/course_wiki/ lms/djangoapps/coursewarehistoryextended/ lms/djangoapps/debug/ lms/djangoapps/courseware/ lms/djangoapps/course_goals/ lms/djangoapps/rss_proxy/"
- module-name: lms-2
path: "lms/djangoapps/gating/ lms/djangoapps/grades/ lms/djangoapps/instructor/ lms/djangoapps/instructor_analytics/ lms/djangoapps/discussion/ lms/djangoapps/edxnotes/ lms/djangoapps/experiments/ lms/djangoapps/instructor_task/ lms/djangoapps/learner_dashboard/ lms/djangoapps/learner_home/ lms/djangoapps/lms_initialization/ lms/djangoapps/lms_xblock/ lms/djangoapps/lti_provider/ lms/djangoapps/mailing/ lms/djangoapps/mobile_api/ lms/djangoapps/monitoring/ lms/djangoapps/ora_staff_grader/ lms/djangoapps/program_enrollments/ lms/djangoapps/rss_proxy lms/djangoapps/static_template_view/ lms/djangoapps/staticbook/ lms/djangoapps/support/ lms/djangoapps/survey/ lms/djangoapps/teams/ lms/djangoapps/tests/ lms/djangoapps/user_tours/ lms/djangoapps/verify_student/ lms/djangoapps/mfe_config_api/ lms/envs/ lms/lib/ lms/tests.py"
- module-name: openedx-1
path: "openedx/core/types/ openedx/core/djangoapps/ace_common/ openedx/core/djangoapps/agreements/ openedx/core/djangoapps/api_admin/ openedx/core/djangoapps/auth_exchange/ openedx/core/djangoapps/bookmarks/ openedx/core/djangoapps/cache_toolbox/ openedx/core/djangoapps/catalog/ openedx/core/djangoapps/ccxcon/ openedx/core/djangoapps/commerce/ openedx/core/djangoapps/common_initialization/ openedx/core/djangoapps/common_views/ openedx/core/djangoapps/config_model_utils/ openedx/core/djangoapps/content/ openedx/core/djangoapps/content_libraries/ openedx/core/djangoapps/content_staging/ openedx/core/djangoapps/contentserver/ openedx/core/djangoapps/cookie_metadata/ openedx/core/djangoapps/cors_csrf/ openedx/core/djangoapps/course_apps/ openedx/core/djangoapps/course_date_signals/ openedx/core/djangoapps/course_groups/ openedx/core/djangoapps/courseware_api/ openedx/core/djangoapps/crawlers/ openedx/core/djangoapps/credentials/ openedx/core/djangoapps/credit/ openedx/core/djangoapps/dark_lang/ openedx/core/djangoapps/debug/ openedx/core/djangoapps/discussions/ openedx/core/djangoapps/django_comment_common/ openedx/core/djangoapps/embargo/ openedx/core/djangoapps/enrollments/ openedx/core/djangoapps/external_user_ids/ openedx/core/djangoapps/zendesk_proxy/ openedx/core/djangolib/ openedx/core/lib/ openedx/core/djangoapps/course_live/"
- module-name: openedx-2
path: "openedx/core/djangoapps/geoinfo/ openedx/core/djangoapps/header_control/ openedx/core/djangoapps/heartbeat/ openedx/core/djangoapps/lang_pref/ openedx/core/djangoapps/models/ openedx/core/djangoapps/monkey_patch/ openedx/core/djangoapps/oauth_dispatch/ openedx/core/djangoapps/olx_rest_api/ openedx/core/djangoapps/password_policy/ openedx/core/djangoapps/plugin_api/ openedx/core/djangoapps/plugins/ openedx/core/djangoapps/profile_images/ openedx/core/djangoapps/programs/ openedx/core/djangoapps/safe_sessions/ openedx/core/djangoapps/schedules/ openedx/core/djangoapps/service_status/ openedx/core/djangoapps/session_inactivity_timeout/ openedx/core/djangoapps/signals/ openedx/core/djangoapps/site_configuration/ openedx/core/djangoapps/system_wide_roles/ openedx/core/djangoapps/theming/ openedx/core/djangoapps/user_api/ openedx/core/djangoapps/user_authn/ openedx/core/djangoapps/util/ openedx/core/djangoapps/verified_track_content/ openedx/core/djangoapps/video_config/ openedx/core/djangoapps/video_pipeline/ openedx/core/djangoapps/waffle_utils/ openedx/core/djangoapps/xblock/ openedx/core/djangoapps/xmodule_django/ openedx/core/tests/ openedx/features/ openedx/testing/ openedx/tests/ openedx/envs/ openedx/core/djangoapps/notifications/ openedx/core/djangoapps/staticfiles/ openedx/core/djangoapps/content_tagging/ openedx/core/djangoapps/authz/"
- module-name: common
path: "common"
- module-name: cms
path: "cms"
- module-name: xmodule
path: "xmodule"

name: pylint ${{ matrix.module-name }}
steps:
- name: Check out repo
uses: actions/checkout@v6

- name: Install required system packages
run: sudo apt-get update && sudo apt-get install libxmlsec1-dev

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Get pip cache dir
id: pip-cache-dir
run: |
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT

- name: Cache pip dependencies
id: cache-dependencies
uses: actions/cache@v5
with:
path: ${{ steps.pip-cache-dir.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('requirements/edx/development.txt') }}
restore-keys: ${{ runner.os }}-pip-

- name: Install required Python dependencies
run: |
# dev-requirements is needed because the linter will otherwise
# trip over some dev-only things like django-debug-toolbar
# (import debug_toolbar) that aren't in testing.txt.
make dev-requirements
# After all requirements are installed, check that they're consistent with each other
pip check

- name: Run quality tests
run: |
pylint ${{ matrix.path }}

# This job aggregates test results. It's the required check for branch protection.
# https://github.com/marketplace/actions/alls-green#why
Comment on lines 41 to +187
# https://github.com/orgs/community/discussions/33579
success:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
name: Quality checks successful
if: always()
needs:
- ruff
- policy-checks
- run-pylint
runs-on: ubuntu-24.04
steps:
- name: Decide whether the needed jobs succeeded or failed
# uses: re-actors/alls-green@v1.2.1
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
jobs: ${{ toJSON(needs) }}

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
12 changes: 6 additions & 6 deletions cms/djangoapps/api/v1/serializers/course_runs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CourseRunScheduleSerializer(serializers.Serializer): # lint-amnesty, pyli
enrollment_end = serializers.DateTimeField(allow_null=True, required=False)


class CourseRunTeamSerializer(serializers.Serializer): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
class CourseRunTeamSerializer(serializers.Serializer): # pylint: disable=abstract-method, missing-class-docstring
def to_internal_value(self, data):
"""Overriding this to support deserialization, for write operations."""
for member in data:
Expand All @@ -61,7 +61,7 @@ def get_attribute(self, instance):
return instance


class CourseRunTeamSerializerMixin(serializers.Serializer): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
class CourseRunTeamSerializerMixin(serializers.Serializer): # pylint: disable=abstract-method, missing-class-docstring
team = CourseRunTeamSerializer(required=False)

def update_team(self, instance, team): # lint-amnesty, pylint: disable=missing-function-docstring
Expand Down Expand Up @@ -100,7 +100,7 @@ def to_internal_value(self, data):
return data == 'self_paced'


class CourseRunImageSerializer(serializers.Serializer): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
class CourseRunImageSerializer(serializers.Serializer): # pylint: disable=abstract-method, missing-class-docstring
# We set an empty default to prevent the parent serializer from attempting
# to save this value to the Course object.
card_image = CourseRunImageField(source='course_image', default=empty)
Expand All @@ -121,7 +121,7 @@ class CourseRunSerializerCommonFieldsMixin(serializers.Serializer): # lint-amne
choices=((False, 'instructor_paced'), (True, 'self_paced'),))


class CourseRunSerializer(CourseRunSerializerCommonFieldsMixin, CourseRunTeamSerializerMixin, serializers.Serializer): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
class CourseRunSerializer(CourseRunSerializerCommonFieldsMixin, CourseRunTeamSerializerMixin, serializers.Serializer): # pylint: disable=abstract-method, missing-class-docstring
id = serializers.CharField(read_only=True)
title = serializers.CharField(source='display_name')
images = CourseRunImageSerializer(source='*', required=False)
Expand Down Expand Up @@ -155,7 +155,7 @@ def create(self, validated_data):
return instance


class CourseRunRerunSerializer(CourseRunSerializerCommonFieldsMixin, CourseRunTeamSerializerMixin, # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
class CourseRunRerunSerializer(CourseRunSerializerCommonFieldsMixin, CourseRunTeamSerializerMixin, # pylint: disable=abstract-method, missing-class-docstring
serializers.Serializer):
title = serializers.CharField(source='display_name', required=False)
number = serializers.CharField(source='id.course', required=False)
Expand Down Expand Up @@ -200,7 +200,7 @@ def update(self, instance, validated_data):
return course_run


class CourseCloneSerializer(serializers.Serializer): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
class CourseCloneSerializer(serializers.Serializer): # pylint: disable=abstract-method, missing-class-docstring
source_course_id = serializers.CharField()
destination_course_id = serializers.CharField()

Expand Down
4 changes: 2 additions & 2 deletions cms/djangoapps/api/v1/tests/test_views/test_course_runs.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ def test_rerun(self, pacing_type, expected_self_paced_value, number):
user = UserFactory()
role = 'instructor'
run = '3T2017'
url = reverse('api:v1:course_run-rerun', kwargs={'pk': str(original_course_run.id)}) # lint-amnesty, pylint: disable=no-member
url = reverse('api:v1:course_run-rerun', kwargs={'pk': str(original_course_run.id)}) # pylint: disable=no-member
data = {
'run': run,
'schedule': {
Expand Down Expand Up @@ -383,7 +383,7 @@ def test_rerun(self, pacing_type, expected_self_paced_value, number):
self.assert_course_access_role_count(course_run, 1)
course_orgs = get_course_organizations(course_run_key)
self.assertEqual(len(course_orgs), 1) # noqa: PT009
self.assertEqual(course_orgs[0]['short_name'], original_course_run.id.org) # lint-amnesty, pylint: disable=no-member # noqa: PT009
self.assertEqual(course_orgs[0]['short_name'], original_course_run.id.org) # pylint: disable=no-member # noqa: PT009

def test_rerun_duplicate_run(self):
course_run = ToyCourseFactory()
Expand Down
Loading
Loading