Updater
This commit is contained in:
134
.idea/.idea.BABA_YAGA/.idea/workspace.xml
generated
Normal file
134
.idea/.idea.BABA_YAGA/.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d308d1cb-09fc-4331-ba20-00f7b43d1576" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="EmbeddingIndexingInfo">
|
||||
<option name="cachedIndexableFilesCount" value="2" />
|
||||
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="McpProjectServerCommands">
|
||||
<commands />
|
||||
<urls />
|
||||
</component>
|
||||
<component name="ProjectColorInfo"><![CDATA[{
|
||||
"associatedIndex": 0
|
||||
}]]></component>
|
||||
<component name="ProjectId" id="3EntV1tfxFOvIa4cn84mOGJGhnc" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"RunOnceActivity.MCP Project settings loaded": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true",
|
||||
"git-widget-placeholder": "main",
|
||||
"junie.onboarding.icon.badge.shown": "true",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"to.speed.mode.migration.done": "true",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RunManager" selected="Attach to Unity Editor.Attach to Unity Editor">
|
||||
<configuration name="Start Unity" type="RunUnityExe" factoryName="Unity Executable">
|
||||
<option name="EXE_PATH" value="C:\Program Files\Unity\Hub\Editor\6000.3.10f1\Editor\Unity.exe" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-projectPath D:\Learning_Progress\Projects\BABA_YAGA -debugCodeOptimization" />
|
||||
<option name="WORKING_DIRECTORY" value="D:\Learning_Progress\Projects\BABA_YAGA" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="ENV_FILE_PATHS" value="" />
|
||||
<option name="REDIRECT_INPUT_PATH" value="" />
|
||||
<option name="MIXED_MODE_DEBUG" value="0" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Unit Tests (batch mode)" type="RunUnityExe" factoryName="Unity Executable">
|
||||
<option name="EXE_PATH" value="C:\Program Files\Unity\Hub\Editor\6000.3.10f1\Editor\Unity.exe" />
|
||||
<option name="PROGRAM_PARAMETERS" value="-runTests -batchmode -projectPath D:\Learning_Progress\Projects\BABA_YAGA -testResults Logs/results.xml -logFile Logs/Editor.log -testPlatform EditMode -debugCodeOptimization" />
|
||||
<option name="WORKING_DIRECTORY" value="D:\Learning_Progress\Projects\BABA_YAGA" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="ENV_FILE_PATHS" value="" />
|
||||
<option name="REDIRECT_INPUT_PATH" value="" />
|
||||
<option name="MIXED_MODE_DEBUG" value="0" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Attach to Unity Editor" type="UNITY_DEBUG_RUN_CONFIGURATION" factoryName="Unity Debug" show_console_on_std_err="false" show_console_on_std_out="false" port="50000" address="localhost" useMixedMode="false">
|
||||
<option name="allowRunningInParallel" value="false" />
|
||||
<option name="listenPortForConnections" value="false" />
|
||||
<option name="pid" />
|
||||
<option name="projectPathOnTarget" />
|
||||
<option name="runtimes">
|
||||
<list />
|
||||
</option>
|
||||
<option name="selectedOptions">
|
||||
<list />
|
||||
</option>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Attach to" type="UnityDevicePlayer" factoryName="UnityAttachToDevicePlayer">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="d308d1cb-09fc-4331-ba20-00f7b43d1576" name="Changes" comment="" />
|
||||
<created>1780826181670</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1780826181670</updated>
|
||||
<workItem from="1780826183468" duration="3073000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="UnityProjectConfiguration" hasMinimizedUI="true" />
|
||||
<component name="UnityProjectDiscoverer">
|
||||
<option name="hasUnityReference" value="true" />
|
||||
<option name="unityProject" value="true" />
|
||||
<option name="unityProjectFolder" value="true" />
|
||||
</component>
|
||||
<component name="UnityUnitTestConfiguration" currentTestLauncher="Both" />
|
||||
<component name="VcsManagerConfiguration">
|
||||
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
|
||||
<properties exception="System.OperationCanceledException" breakIfHandledByOtherCode="false" displayValue="System.OperationCanceledException" />
|
||||
<option name="timeStamp" value="1" />
|
||||
</breakpoint>
|
||||
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
|
||||
<properties exception="System.Threading.Tasks.TaskCanceledException" breakIfHandledByOtherCode="false" displayValue="System.Threading.Tasks.TaskCanceledException" />
|
||||
<option name="timeStamp" value="2" />
|
||||
</breakpoint>
|
||||
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
|
||||
<properties exception="System.Threading.ThreadAbortException" breakIfHandledByOtherCode="false" displayValue="System.Threading.ThreadAbortException" />
|
||||
<option name="timeStamp" value="3" />
|
||||
</breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
||||
5
BABA_YAGA_Updater/.env.example
Normal file
5
BABA_YAGA_Updater/.env.example
Normal file
@@ -0,0 +1,5 @@
|
||||
SPREADSHEET_ID=your_spreadsheet_id_here
|
||||
SHEET_RANGE=Sheet1!A2:E
|
||||
CREDENTIALS_FILE=credentials.json
|
||||
TOKEN_FILE=token.json
|
||||
README_PATH=../README.md
|
||||
10
BABA_YAGA_Updater/.gitignore
vendored
Normal file
10
BABA_YAGA_Updater/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
.env
|
||||
credentials.json
|
||||
token.json
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
.venv/
|
||||
venv/
|
||||
ENV/
|
||||
env/
|
||||
21
BABA_YAGA_Updater/config/settings.py
Normal file
21
BABA_YAGA_Updater/config/settings.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load .env file if it exists
|
||||
load_dotenv()
|
||||
|
||||
class Settings:
|
||||
# Google Sheets Configuration
|
||||
SPREADSHEET_ID = os.getenv("SPREADSHEET_ID", "")
|
||||
SHEET_RANGE = os.getenv("SHEET_RANGE", "Sheet1!A2:E") # Default range
|
||||
CREDENTIALS_FILE = os.getenv("CREDENTIALS_FILE", "credentials.json")
|
||||
TOKEN_FILE = os.getenv("TOKEN_FILE", "token.json")
|
||||
|
||||
# README Configuration
|
||||
README_PATH = os.getenv("README_PATH", "../README.md")
|
||||
|
||||
# Section Markers
|
||||
START_MARKER = "<!-- START_UPDATES -->"
|
||||
END_MARKER = "<!-- END_UPDATES -->"
|
||||
|
||||
settings = Settings()
|
||||
12
BABA_YAGA_Updater/core/models.py
Normal file
12
BABA_YAGA_Updater/core/models.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
class Task(BaseModel):
|
||||
category: str
|
||||
task_name: str
|
||||
status: str
|
||||
progress: str # e.g., "75%" or "In Progress"
|
||||
notes: Optional[str] = ""
|
||||
|
||||
class ProgressReport(BaseModel):
|
||||
tasks: list[Task]
|
||||
38
BABA_YAGA_Updater/main.py
Normal file
38
BABA_YAGA_Updater/main.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import sys
|
||||
from services.gsheet_client import GSheetClient
|
||||
from mappers.sheet_mapper import SheetMapper
|
||||
from mappers.markdown_builder import MarkdownBuilder
|
||||
from services.readme_editor import ReadmeEditor
|
||||
|
||||
def main():
|
||||
try:
|
||||
print("🚀 Starting README update from Google Sheets...")
|
||||
|
||||
# 1. Fetch data from Google Sheets
|
||||
client = GSheetClient()
|
||||
raw_rows = client.fetch_data()
|
||||
|
||||
if not raw_rows:
|
||||
print("⚠️ No data found in the spreadsheet or error occurred.")
|
||||
return
|
||||
|
||||
# 2. Map raw rows to Core Models
|
||||
report = SheetMapper.map_rows_to_report(raw_rows)
|
||||
print(f"✅ Parsed {len(report.tasks)} tasks.")
|
||||
|
||||
# 3. Build Markdown content
|
||||
markdown_content = MarkdownBuilder.build_table(report)
|
||||
|
||||
# 4. Update README.md
|
||||
editor = ReadmeEditor()
|
||||
if editor.update_section(markdown_content):
|
||||
print("🎉 README.md successfully updated!")
|
||||
else:
|
||||
print("❌ Failed to update README.md.")
|
||||
|
||||
except Exception as e:
|
||||
print(f"💥 An unexpected error occurred: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
24
BABA_YAGA_Updater/mappers/markdown_builder.py
Normal file
24
BABA_YAGA_Updater/mappers/markdown_builder.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from core.models import ProgressReport
|
||||
|
||||
class MarkdownBuilder:
|
||||
@staticmethod
|
||||
def build_table(report: ProgressReport) -> str:
|
||||
if not report.tasks:
|
||||
return "_No tasks updated._"
|
||||
|
||||
header = "| Category | Task | Status | Progress | Notes |\n"
|
||||
separator = "| :--- | :--- | :--- | :--- | :--- |\n"
|
||||
rows = []
|
||||
|
||||
for task in report.tasks:
|
||||
# Format status with some icons if possible, or just plain text
|
||||
status_text = task.status
|
||||
if "done" in status_text.lower() or "complete" in status_text.lower():
|
||||
status_text = f"✅ {status_text}"
|
||||
elif "progress" in status_text.lower():
|
||||
status_text = f"🔄 {status_text}"
|
||||
|
||||
row = f"| {task.category} | {task.task_name} | {status_text} | {task.progress} | {task.notes} |"
|
||||
rows.append(row)
|
||||
|
||||
return header + separator + "\n".join(rows)
|
||||
20
BABA_YAGA_Updater/mappers/sheet_mapper.py
Normal file
20
BABA_YAGA_Updater/mappers/sheet_mapper.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from core.models import Task, ProgressReport
|
||||
|
||||
class SheetMapper:
|
||||
@staticmethod
|
||||
def map_rows_to_report(rows: list[list]) -> ProgressReport:
|
||||
tasks = []
|
||||
for row in rows:
|
||||
# Ensure the row has enough columns, fill missing with empty strings
|
||||
padded_row = row + [""] * (5 - len(row))
|
||||
|
||||
task = Task(
|
||||
category=padded_row[0],
|
||||
task_name=padded_row[1],
|
||||
status=padded_row[2],
|
||||
progress=padded_row[3],
|
||||
notes=padded_row[4]
|
||||
)
|
||||
tasks.append(task)
|
||||
|
||||
return ProgressReport(tasks=tasks)
|
||||
5
BABA_YAGA_Updater/requirements.txt
Normal file
5
BABA_YAGA_Updater/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
google-api-python-client
|
||||
google-auth-httplib2
|
||||
google-auth-oauthlib
|
||||
python-dotenv
|
||||
pydantic
|
||||
52
BABA_YAGA_Updater/services/gsheet_client.py
Normal file
52
BABA_YAGA_Updater/services/gsheet_client.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import os
|
||||
from google.auth.transport.requests import Request
|
||||
from google.oauth2.credentials import Credentials
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.errors import HttpError
|
||||
from config.settings import settings
|
||||
|
||||
class GSheetClient:
|
||||
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']
|
||||
|
||||
def __init__(self):
|
||||
self.creds = self._authenticate()
|
||||
|
||||
def _authenticate(self):
|
||||
creds = None
|
||||
# The file token.json stores the user's access and refresh tokens
|
||||
if os.path.exists(settings.TOKEN_FILE):
|
||||
creds = Credentials.from_authorized_user_file(settings.TOKEN_FILE, self.SCOPES)
|
||||
|
||||
# If there are no (valid) credentials available, let the user log in.
|
||||
if not creds or not creds.valid:
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
if not os.path.exists(settings.CREDENTIALS_FILE):
|
||||
raise FileNotFoundError(f"Credentials file not found at {settings.CREDENTIALS_FILE}. Please download it from Google Cloud Console.")
|
||||
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
settings.CREDENTIALS_FILE, self.SCOPES)
|
||||
creds = flow.run_local_server(port=0)
|
||||
|
||||
# Save the credentials for the next run
|
||||
with open(settings.TOKEN_FILE, 'w') as token:
|
||||
token.write(creds.to_json())
|
||||
|
||||
return creds
|
||||
|
||||
def fetch_data(self):
|
||||
try:
|
||||
service = build('sheets', 'v4', credentials=self.creds)
|
||||
sheet = service.spreadsheets()
|
||||
result = sheet.values().get(
|
||||
spreadsheetId=settings.SPREADSHEET_ID,
|
||||
range=settings.SHEET_RANGE
|
||||
).execute()
|
||||
|
||||
return result.get('values', [])
|
||||
|
||||
except HttpError as err:
|
||||
print(f"An error occurred: {err}")
|
||||
return []
|
||||
30
BABA_YAGA_Updater/services/readme_editor.py
Normal file
30
BABA_YAGA_Updater/services/readme_editor.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import re
|
||||
from config.settings import settings
|
||||
|
||||
class ReadmeEditor:
|
||||
def __init__(self, file_path: str = None):
|
||||
self.file_path = file_path or settings.README_PATH
|
||||
|
||||
def update_section(self, new_content: str):
|
||||
with open(self.file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Regex to find content between markers
|
||||
pattern = re.compile(
|
||||
f"({re.escape(settings.START_MARKER)})(.*?)({re.escape(settings.END_MARKER)})",
|
||||
re.DOTALL
|
||||
)
|
||||
|
||||
if not pattern.search(content):
|
||||
print(f"Markers {settings.START_MARKER} and {settings.END_MARKER} not found in {self.file_path}")
|
||||
return False
|
||||
|
||||
updated_content = pattern.sub(
|
||||
f"\\1\n\n{new_content}\n\n\\3",
|
||||
content
|
||||
)
|
||||
|
||||
with open(self.file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(updated_content)
|
||||
|
||||
return True
|
||||
@@ -385,6 +385,9 @@ Khi Trapper để xổng mất con mồi, mê cung sẽ hiến tế sự ổn đ
|
||||
|
||||
## 🚀 Lộ trình Phát triển (Roadmap)
|
||||
|
||||
<!-- START_UPDATES -->
|
||||
<!-- END_UPDATES -->
|
||||
|
||||
- [x] **Phase 1: Foundation**
|
||||
- [x] Player State Machine (Idle, Move, Run, Jump).
|
||||
- [x] Maze Generation (Multi-algorithm).
|
||||
|
||||
Reference in New Issue
Block a user