From ee61dce99140e18fda25270512d94b90d2e37503 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:17:34 +0000 Subject: [PATCH 1/4] Initial plan From f39f3bf8494b3a56274f13e6b552718c5c7f4964 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:26:14 +0000 Subject: [PATCH 2/4] Migrate to Python 3.12 and add GitHub Actions workflows Co-authored-by: superzer0 <1933570+superzer0@users.noreply.github.com> --- .github/workflows/build-artifacts.yml | 119 ++++++++++++++++++ .github/workflows/ci.yml | 59 +++++++++ .github/workflows/codeql-analysis.yml | 22 +++- README.md | 19 ++- requirements.txt | 1 + tests/config_parser/config_parser_tests.py | 12 +- .../leader_board_service_tests.py | 10 +- 7 files changed, 220 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/build-artifacts.yml create mode 100644 .github/workflows/ci.yml create mode 100644 requirements.txt diff --git a/.github/workflows/build-artifacts.yml b/.github/workflows/build-artifacts.yml new file mode 100644 index 0000000..a3c5cb5 --- /dev/null +++ b/.github/workflows/build-artifacts.yml @@ -0,0 +1,119 @@ +name: Build Release Artifacts + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + version: + description: 'Version for the release' + required: true + default: 'latest' + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.12'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pyinstaller + + - name: Run tests + run: | + python -m unittest discover tests -v + + - name: Build executable (Linux/macOS) + if: runner.os != 'Windows' + run: | + pyinstaller --onefile --add-data "configuration:configuration" --add-data "resources:resources" --name "space-raid-${{ runner.os }}" __init__.py + + - name: Build executable (Windows) + if: runner.os == 'Windows' + run: | + pyinstaller --onefile --add-data "configuration;configuration" --add-data "resources;resources" --name "space-raid-Windows" __init__.py + + - name: Create portable package (Linux/macOS) + if: runner.os != 'Windows' + run: | + mkdir -p space-raid-portable-${{ runner.os }} + cp -r configuration space-raid-portable-${{ runner.os }}/ + cp -r resources space-raid-portable-${{ runner.os }}/ + cp -r objects space-raid-portable-${{ runner.os }}/ + cp -r other space-raid-portable-${{ runner.os }}/ + cp __init__.py space-raid-portable-${{ runner.os }}/ + cp requirements.txt space-raid-portable-${{ runner.os }}/ + cp README.md space-raid-portable-${{ runner.os }}/ + cp LICENSE space-raid-portable-${{ runner.os }}/ + echo "#!/bin/bash" > space-raid-portable-${{ runner.os }}/run.sh + echo "python3 __init__.py" >> space-raid-portable-${{ runner.os }}/run.sh + chmod +x space-raid-portable-${{ runner.os }}/run.sh + tar -czf space-raid-portable-${{ runner.os }}.tar.gz space-raid-portable-${{ runner.os }}/ + + - name: Create portable package (Windows) + if: runner.os == 'Windows' + run: | + mkdir space-raid-portable-Windows + xcopy configuration space-raid-portable-Windows\configuration\ /E /I + xcopy resources space-raid-portable-Windows\resources\ /E /I + xcopy objects space-raid-portable-Windows\objects\ /E /I + xcopy other space-raid-portable-Windows\other\ /E /I + copy __init__.py space-raid-portable-Windows\ + copy requirements.txt space-raid-portable-Windows\ + copy README.md space-raid-portable-Windows\ + copy LICENSE space-raid-portable-Windows\ + echo python __init__.py > space-raid-portable-Windows\run.bat + powershell Compress-Archive -Path space-raid-portable-Windows -DestinationPath space-raid-portable-Windows.zip + + - name: Upload executable artifacts + uses: actions/upload-artifact@v3 + with: + name: space-raid-executable-${{ runner.os }} + path: | + dist/space-raid-* + + - name: Upload portable artifacts (Linux/macOS) + if: runner.os != 'Windows' + uses: actions/upload-artifact@v3 + with: + name: space-raid-portable-${{ runner.os }} + path: space-raid-portable-${{ runner.os }}.tar.gz + + - name: Upload portable artifacts (Windows) + if: runner.os == 'Windows' + uses: actions/upload-artifact@v3 + with: + name: space-raid-portable-Windows + path: space-raid-portable-Windows.zip + + release: + needs: build + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + + steps: + - name: Download all artifacts + uses: actions/download-artifact@v3 + + - name: Create Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/v') + with: + files: | + space-raid-*/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a795386 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,59 @@ +name: CI + +on: + push: + branches: [ master, main ] + pull_request: + branches: [ master, main ] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Run tests + run: | + python -m unittest discover tests -v + + - name: Lint with built-in tools + run: | + python -m py_compile __init__.py + find . -name "*.py" -not -path "./other/*" -exec python -m py_compile {} \; + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 + pip install -r requirements.txt + + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --exclude=other/py_text_input.py \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5a58b64..6a6fd29 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,10 @@ name: "CodeQL" on: push: - branches: [ master ] + branches: [ master, main ] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [ master, main ] schedule: - cron: '35 13 * * 6' @@ -38,11 +38,21 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,7 +63,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -67,4 +77,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/README.md b/README.md index 018f48f..8042252 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,17 @@ # Space Raid -River Raid based of Space Raid implementation in Python +River Raid based Space Raid implementation in Python -How to run the game: -Install python 3.4 -Install pygame (pip install pygame) -Run python __init__.py +## Requirements +- Python 3.8+ (tested with Python 3.12) + +## How to run the game: +1. Install Python 3.8 or higher +2. Install dependencies: `pip install -r requirements.txt` +3. Run the game: `python __init__.py` + +## Development +To run tests: +```bash +python -m unittest discover tests -v +``` diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..345781b --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pygame>=2.0.0 \ No newline at end of file diff --git a/tests/config_parser/config_parser_tests.py b/tests/config_parser/config_parser_tests.py index a72f652..70dd943 100644 --- a/tests/config_parser/config_parser_tests.py +++ b/tests/config_parser/config_parser_tests.py @@ -16,10 +16,10 @@ def test_read_from_default_section(self): service = ConfigReader(config_reader) single_value = service.get_config_property('some_value') - self.assertEquals('5', single_value) + self.assertEqual('5', single_value) multi_value = service.get_config_property_value_list('list_of_values') - self.assertEquals(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], multi_value) + self.assertEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], multi_value) def test_read_from_custom_section(self): config_reader = configparser.ConfigParser() @@ -27,10 +27,10 @@ def test_read_from_custom_section(self): service = ConfigReader(config_reader, 'OTHER') single_value = service.get_config_property('some_value') - self.assertEquals('1', single_value) + self.assertEqual('1', single_value) multi_value = service.get_config_property_value_list('list_of_values') - self.assertEquals(['9', '8', '7', '6', '5', '4', '3', '2', '1', '0'], multi_value) + self.assertEqual(['9', '8', '7', '6', '5', '4', '3', '2', '1', '0'], multi_value) def test_read_from_empty_section_section(self): config_reader = configparser.ConfigParser() @@ -38,10 +38,10 @@ def test_read_from_empty_section_section(self): service = ConfigReader(config_reader, 'EMPTY_SECTION') single_value = service.get_config_property('some_value') - self.assertEquals('5', single_value) + self.assertEqual('5', single_value) multi_value = service.get_config_property_value_list('list_of_values') - self.assertEquals(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], multi_value) + self.assertEqual(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], multi_value) def test_property_not_exist(self): config_reader = configparser.ConfigParser() diff --git a/tests/leader_board/leader_board_service_tests.py b/tests/leader_board/leader_board_service_tests.py index 17bc1ae..2923d03 100644 --- a/tests/leader_board/leader_board_service_tests.py +++ b/tests/leader_board/leader_board_service_tests.py @@ -34,7 +34,7 @@ def test_entries_only_added_file_not_saved(self): service.add_entry(self.examplary_data_record) # in memory we have 3 entries - self.assertEquals(len(service.leader_board), 3) + self.assertEqual(len(service.leader_board), 3) # but file should be empty: self.assertTrue(os.stat(self.test_file).st_size == 0) @@ -47,25 +47,25 @@ def test_entries_only_added_file_not_saved(self): with open(self.test_file, 'r') as output_file: expected_content = expected_file.read() output_content = output_file.read() - self.assertEquals(expected_content, output_content) + self.assertEqual(expected_content, output_content) # create new service to see if entries were persisted service = LeaderBoardService(self.test_file) service.load_leader_board() - self.assertEquals(len(service.leader_board), 3) + self.assertEqual(len(service.leader_board), 3) def test_entries_read_happy_path(self): service = LeaderBoardService(self.expected_file) service.load_leader_board() for entry in service.leader_board: - self.assertEquals(self.examplary_data_record.row, entry.row) + self.assertEqual(self.examplary_data_record.row, entry.row) def test_file_not_found_empty_list_returned(self): service = LeaderBoardService(self.expected_file + 'non existing') service.load_leader_board() - self.assertEquals([], service.leader_board) + self.assertEqual([], service.leader_board) if __name__ == '__main__': From 276dc02113771470af7873adda89b222a9041add Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:28:56 +0000 Subject: [PATCH 3/4] Add environment check script and finalize Python 3.12 migration Co-authored-by: superzer0 <1933570+superzer0@users.noreply.github.com> --- check_environment.py | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 check_environment.py diff --git a/check_environment.py b/check_environment.py new file mode 100644 index 0000000..a22c4c6 --- /dev/null +++ b/check_environment.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +""" +Space Raid - Python Version and Environment Check +This script validates that the game is compatible with the current Python version. +""" + +import sys +import pygame + +def main(): + print("=" * 60) + print("🚀 Space Raid - Python Environment Check") + print("=" * 60) + + # Python version check + print(f"✅ Python Version: {sys.version}") + print(f"✅ Python Version Info: {sys.version_info}") + + # Dependencies check + print(f"✅ Pygame Version: {pygame.version.ver}") + print(f"✅ SDL Version: {pygame.version.SDL}") + + # Compatibility check + if sys.version_info >= (3, 8): + print("✅ Python version is compatible (3.8+)") + else: + print("❌ Python version is too old. Please upgrade to Python 3.8+") + return 1 + + # Try importing core game modules + try: + import objects.player + import objects.leaderboards.leaderboard_service + import objects.resources.ResourcesContext + print("✅ All core game modules import successfully") + except ImportError as e: + print(f"❌ Failed to import core modules: {e}") + return 1 + + print("=" * 60) + print("🎮 Space Raid is ready to run!") + print("To start the game: python __init__.py") + print("=" * 60) + return 0 + +if __name__ == '__main__': + sys.exit(main()) \ No newline at end of file From 07f41b6197f3e2a56a25c2c2fd83341a5efd83d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 24 Jul 2025 11:51:31 +0000 Subject: [PATCH 4/4] Fix CI tests by adding missing __init__.py files and updating test discovery pattern Co-authored-by: superzer0 <1933570+superzer0@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- objects/__init__.py | 1 + objects/globals/__init__.py | 1 + objects/leaderboards/__init__.py | 1 + objects/mobs/__init__.py | 1 + objects/mobs/generators/__init__.py | 1 + objects/resources/__init__.py | 1 + objects/resources/i18n/__init__.py | 1 + objects/screens/__init__.py | 1 + objects/ui/__init__.py | 1 + tests/__init__.py | 1 + tests/config_parser/__init__.py | 1 + tests/leader_board/__init__.py | 1 + 13 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 objects/__init__.py create mode 100644 objects/globals/__init__.py create mode 100644 objects/leaderboards/__init__.py create mode 100644 objects/mobs/__init__.py create mode 100644 objects/mobs/generators/__init__.py create mode 100644 objects/resources/__init__.py create mode 100644 objects/resources/i18n/__init__.py create mode 100644 objects/screens/__init__.py create mode 100644 objects/ui/__init__.py create mode 100644 tests/__init__.py create mode 100644 tests/config_parser/__init__.py create mode 100644 tests/leader_board/__init__.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a795386..8238d80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: - name: Run tests run: | - python -m unittest discover tests -v + python -m unittest discover tests -p "*tests.py" -v - name: Lint with built-in tools run: | diff --git a/objects/__init__.py b/objects/__init__.py new file mode 100644 index 0000000..81bd3e7 --- /dev/null +++ b/objects/__init__.py @@ -0,0 +1 @@ +# Objects package initialization \ No newline at end of file diff --git a/objects/globals/__init__.py b/objects/globals/__init__.py new file mode 100644 index 0000000..9fa5e10 --- /dev/null +++ b/objects/globals/__init__.py @@ -0,0 +1 @@ +# Globals package initialization \ No newline at end of file diff --git a/objects/leaderboards/__init__.py b/objects/leaderboards/__init__.py new file mode 100644 index 0000000..6217175 --- /dev/null +++ b/objects/leaderboards/__init__.py @@ -0,0 +1 @@ +# Leaderboards package initialization \ No newline at end of file diff --git a/objects/mobs/__init__.py b/objects/mobs/__init__.py new file mode 100644 index 0000000..dcce15c --- /dev/null +++ b/objects/mobs/__init__.py @@ -0,0 +1 @@ +# Mobs package initialization \ No newline at end of file diff --git a/objects/mobs/generators/__init__.py b/objects/mobs/generators/__init__.py new file mode 100644 index 0000000..edc66ab --- /dev/null +++ b/objects/mobs/generators/__init__.py @@ -0,0 +1 @@ +# Generators package initialization \ No newline at end of file diff --git a/objects/resources/__init__.py b/objects/resources/__init__.py new file mode 100644 index 0000000..bb48491 --- /dev/null +++ b/objects/resources/__init__.py @@ -0,0 +1 @@ +# Resources package initialization \ No newline at end of file diff --git a/objects/resources/i18n/__init__.py b/objects/resources/i18n/__init__.py new file mode 100644 index 0000000..c26bd0d --- /dev/null +++ b/objects/resources/i18n/__init__.py @@ -0,0 +1 @@ +# i18n package initialization \ No newline at end of file diff --git a/objects/screens/__init__.py b/objects/screens/__init__.py new file mode 100644 index 0000000..544ff76 --- /dev/null +++ b/objects/screens/__init__.py @@ -0,0 +1 @@ +# Screens package initialization \ No newline at end of file diff --git a/objects/ui/__init__.py b/objects/ui/__init__.py new file mode 100644 index 0000000..ff98c8b --- /dev/null +++ b/objects/ui/__init__.py @@ -0,0 +1 @@ +# UI package initialization \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..3a12369 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# Tests package initialization \ No newline at end of file diff --git a/tests/config_parser/__init__.py b/tests/config_parser/__init__.py new file mode 100644 index 0000000..89a03a2 --- /dev/null +++ b/tests/config_parser/__init__.py @@ -0,0 +1 @@ +# Config parser tests package initialization \ No newline at end of file diff --git a/tests/leader_board/__init__.py b/tests/leader_board/__init__.py new file mode 100644 index 0000000..6dae29c --- /dev/null +++ b/tests/leader_board/__init__.py @@ -0,0 +1 @@ +# Leader board tests package initialization \ No newline at end of file