feat: GAS 자동 배포 스크립트 작성 및 커밋/PR 시 원격 배포 하드 룰 추가 (2026-06-13)
주요 변경 사항: - tools/deploy_gas.py 추가: * clasp를 사용하여 로컬의 8개 .gs 스크립트 파일과 appsscript.json을 원격 Apps Script 프로젝트에 강제 푸시(clasp push -f)하는 자동화 스크립트 작성 - AGENTS.md 수정: * 3. 하드 룰 섹션에 커밋, 푸쉬, PR 작업 시 반드시 로컬 .gs 파일을 원격 프로젝트에 업로드하고 사용자가 스프레드시트 상의 스크립트(runDataFeed 등)를 직접 실행해 검증하도록 가이드하는 하드 룰 명시 - 검증 결과: python tools/deploy_gas.py 원격 배포(9개 파일 push) 정상 검증 완료 Co-Authored-By: Antigravity AI <noreply@google.com>
This commit is contained in:
@@ -55,6 +55,7 @@
|
||||
- 데이터 흐름은 단방향(Data -> Feature -> Decision -> Execution -> Report) 아키텍처 경계를 유지하며, renderer가 core 계산을 호출하는 역참조를 금지한다.
|
||||
- D+2 영업일 기준 현금을 즉시방어 자산으로 간주하고, 목표 예산 5억 원을 기준으로 포지션 사이징 및 리스크 버킷을 제어한다.
|
||||
- 매주 주말 리밸런싱(rebalance_required=true) 및 매월 1일/11일/21일 중간점검(mid_check_required=true) 운영 cadence를 준수한다.
|
||||
- 커밋, 푸쉬, PR 작업 시 반드시 로컬의 .gs 파일을 Google Apps Script 원격 프로젝트에 업로드(python tools/deploy_gas.py 실행)하고, 사용자에게 스프레드시트 상의 스크립트 실행(예: runDataFeed)을 통한 검증을 유도 및 가이드해야 한다.
|
||||
|
||||
## 4. 보고 규칙
|
||||
- 모든 숫자에는 반드시 provenance(출처)를 남기며, 출처가 유효하지 않거나 없는 숫자는 보고서 표기를 전면 배제(DATA_MISSING 처리)한다.
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import os
|
||||
import shutil
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
# Resolve project root dynamically relative to this script's directory (tools/)
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
DEPLOY_DIR = ROOT / "Temp" / "gas_deploy"
|
||||
|
||||
GAS_FILES = [
|
||||
"gas_data_feed.gs",
|
||||
"gas_data_collect.gs",
|
||||
"gas_lib.gs",
|
||||
"gas_harness_rows.gs",
|
||||
"gas_report.gs",
|
||||
"gas_event_calendar.gs",
|
||||
"gas_apex_alpha_watch.gs",
|
||||
"gas_apex_runtime_core.gs"
|
||||
]
|
||||
|
||||
def main():
|
||||
print(f"Preparing deployment directory: {DEPLOY_DIR}")
|
||||
if DEPLOY_DIR.exists():
|
||||
shutil.rmtree(DEPLOY_DIR)
|
||||
DEPLOY_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 1. Copy appsscript.json manifest
|
||||
manifest_src = ROOT / "src" / "gas_adapter_parts" / "appsscript.json"
|
||||
if manifest_src.exists():
|
||||
shutil.copy(manifest_src, DEPLOY_DIR / "appsscript.json")
|
||||
print(f"Copied appsscript.json from {manifest_src}")
|
||||
else:
|
||||
# Create default manifest
|
||||
manifest = {
|
||||
"timeZone": "Asia/Seoul",
|
||||
"dependencies": {},
|
||||
"exceptionLogging": "STACKDRIVER",
|
||||
"runtimeVersion": "V8"
|
||||
}
|
||||
with open(DEPLOY_DIR / "appsscript.json", "w", encoding="utf-8") as f:
|
||||
json.dump(manifest, f, ensure_ascii=False, indent=2)
|
||||
print("Created default appsscript.json")
|
||||
|
||||
# 2. Copy GAS files from ROOT to DEPLOY_DIR
|
||||
copied_count = 0
|
||||
for gf in GAS_FILES:
|
||||
src = ROOT / gf
|
||||
if src.exists():
|
||||
shutil.copy(src, DEPLOY_DIR / gf)
|
||||
print(f"Copied {gf}")
|
||||
copied_count += 1
|
||||
else:
|
||||
print(f"WARNING: Source file not found: {gf}")
|
||||
|
||||
# 3. Create/Overwrite .clasp.json with DEPLOY_DIR as rootDir
|
||||
clasp_cfg = {
|
||||
"scriptId": "1xfeBAeeknmnBtSvrIqWXO_2hc3ByeriLUOSuOOB4YxLLHhN3zdnL7tVh",
|
||||
"rootDir": str(DEPLOY_DIR.relative_to(ROOT))
|
||||
}
|
||||
with open(ROOT / ".clasp.json", "w", encoding="utf-8") as f:
|
||||
json.dump(clasp_cfg, f, ensure_ascii=False, indent=2)
|
||||
print(f"Updated .clasp.json with rootDir={clasp_cfg['rootDir']}")
|
||||
|
||||
# 4. Run clasp push with shell=True for Windows compatibility
|
||||
print("Running npx @google/clasp push -f ...")
|
||||
env = dict(os.environ)
|
||||
res = subprocess.run(
|
||||
["npx", "@google/clasp", "push", "-f"],
|
||||
cwd=str(ROOT),
|
||||
env=env,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace"
|
||||
)
|
||||
print(f"Return code: {res.returncode}")
|
||||
print("STDOUT:")
|
||||
print(res.stdout)
|
||||
print("STDERR:")
|
||||
print(res.stderr)
|
||||
|
||||
if res.returncode == 0:
|
||||
print("GAS deploy completed successfully!")
|
||||
else:
|
||||
print("GAS deploy failed!")
|
||||
exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user