diff --git a/.github/workflows/appstore-publish.yml b/.github/workflows/appstore-publish.yml index d60a62fb3..32776cefa 100644 --- a/.github/workflows/appstore-publish.yml +++ b/.github/workflows/appstore-publish.yml @@ -73,7 +73,7 @@ jobs: env: CONTENTFUL_GRAPHQL_TOKEN: ${{ secrets.CONTENTFUL_GRAPHQLTOKEN }} run: | - python build/fetch_catalog.py \ + python ci/scripts/fetch_catalog.py \ --channel "${{ steps.resolve_channel.outputs.channel }}" \ --output-dir dist/catalog-source @@ -140,7 +140,7 @@ jobs: elif [[ -n "${{ steps.release_base.outputs.from_ref }}" ]]; then args+=(--from-ref "${{ steps.release_base.outputs.from_ref }}") fi - python build/library_publish.py "${args[@]}" + python ci/scripts/library_publish.py "${args[@]}" - name: Generate changelog if: steps.resolve_channel.outputs.channel == 'release' diff --git a/AGENTS.md b/AGENTS.md index 7ac7c49f3..93175b268 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,7 +54,7 @@ Read in this order: - App metadata: `metadata/maintenance.yaml`, `metadata/archive.yaml` - Shared skills: `skills/` - Template: `metadata/templates/` -- Scripts: `ci/scripts/`, `build/` +- Scripts: `ci/scripts/` - Process docs: `docs/ai-sdlc/` - CI: `.github/workflows/` diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c26ad96e..454b9a101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,14 @@ Project-level changes only: architecture, delivery model, tooling, CI, and relea ### Changed - Moved the opencode session cleanup script from `build/` to `ci/scripts/` and updated `make opencode-clear` to use it. +- Moved `fetch_catalog.py` and `library_publish.py` from `build/` to `ci/scripts/`; the `build/` directory is now removed. ### Removed - Removed the legacy `template/` directory; scaffolds and generated docs now use `metadata/templates/`. - Removed unused `build/update_readme.py`, `build/update_variables.py`, `build/test_apps.py`, and `build/get_apps_latest_version.py`. - Removed obsolete workflows: `build_files`, `pull_quest_test`, `pre_merge`, `release`, `release-dev`, `sync_php_files`, and `get_apps_latest_version`. - Removed `add_apps.json` and its template-scaffold workflow. +- Removed the unused `build/sync_contentful.py`; Contentful sync now uses `libs catalog-push`. ## 2026-09 diff --git a/build/__pycache__/fetch_catalog.cpython-312.pyc b/build/__pycache__/fetch_catalog.cpython-312.pyc deleted file mode 100644 index 579ce58ed..000000000 Binary files a/build/__pycache__/fetch_catalog.cpython-312.pyc and /dev/null differ diff --git a/build/__pycache__/library_publish.cpython-312.pyc b/build/__pycache__/library_publish.cpython-312.pyc deleted file mode 100644 index 9f9dbf455..000000000 Binary files a/build/__pycache__/library_publish.cpython-312.pyc and /dev/null differ diff --git a/build/sync_contentful.py b/build/sync_contentful.py deleted file mode 100644 index 074d0cf64..000000000 --- a/build/sync_contentful.py +++ /dev/null @@ -1,91 +0,0 @@ -import json -import os -from pathlib import Path -from contentful_management import Client -from contentful_management.errors import HTTPError - -# 设置 Contentful API 访问参数 -ACCESS_TOKEN = os.environ['CONTENTFUL_ACCESS_TOKEN'] -SPACE_ID = "ffrhttfighww" - -# 初始化 Contentful 管理客户端 -client = Client(ACCESS_TOKEN) - -def update_contentful(product_name, editions, requirements, production): - try: - # 获取 Contentful 中的 Product entry - entries = client.entries(SPACE_ID, 'master').all({'content_type': 'product', 'fields.key': product_name}) - - if entries: - entry = entries[0] - # 准备 distribution 更新的数据 - distribution = [{"key": edition['dist'], "value": edition['version']} for edition in editions] - entry.fields('en-US')['distribution'] = distribution - - # 准备 requirements 更新的数据 - entry.fields('en-US')['vcpu'] = int(requirements['cpu']) - entry.fields('en-US')['memory'] = int(requirements['memory']) - entry.fields('en-US')['storage'] = int(requirements['disk']) - - entry.fields('en-US')['production'] = bool(production) - - # 保存和发布更新 - entry.save() - entry.publish() - return True - else: - print(f"No entry found for product '{product_name}'.") - return False - except HTTPError as http_error: - print(f"Failed to update entry for product '{product_name}'. HTTPError: {http_error}") - return False - except Exception as e: - print(f"An unexpected error occurred while updating entry for product '{product_name}': {e}") - return False - -# 初始化计数器 -total_updates = 0 -successful_updates = 0 -failed_updates = 0 -failed_products = [] - -# 遍历 apps 文件夹下app_lists下的 variables.json 文件 -apps_path = Path('apps') -app_lists_str = os.getenv('APP_LISTS', '') -app_lists = app_lists_str.split(',') - -for product_name in app_lists: - variables_file = apps_path / product_name / 'variables.json' - try: - with open(variables_file) as file: - data = json.load(file) - editions = data['edition'] - requirements = data['requirements'] - production = data['release'] - - total_updates += 1 - if update_contentful(product_name, editions, requirements,production): - successful_updates += 1 - else: - failed_updates += 1 - failed_products.append(product_name) - except FileNotFoundError: - print(f"File not found: {variables_file}") - failed_updates += 1 - failed_products.append(product_name) - except json.JSONDecodeError as e: - print(f"JSON decode error in file {variables_file}: {e}") - failed_updates += 1 - failed_products.append(product_name) - except Exception as e: - print(f"An unexpected error occurred while processing file {variables_file}: {e}") - failed_updates += 1 - failed_products.append(product_name) - - -# 打印更新报告 -print(f"Total updates attempted: {total_updates}") -print(f"Successful updates: {successful_updates}") -print(f"Failed updates: {failed_updates}") -if failed_updates > 0: - print(f"Failed products: {failed_products}") \ No newline at end of file diff --git a/build/fetch_catalog.py b/ci/scripts/fetch_catalog.py similarity index 100% rename from build/fetch_catalog.py rename to ci/scripts/fetch_catalog.py diff --git a/build/library_publish.py b/ci/scripts/library_publish.py similarity index 99% rename from build/library_publish.py rename to ci/scripts/library_publish.py index 0c1f9b6a9..d2b1f30e8 100644 --- a/build/library_publish.py +++ b/ci/scripts/library_publish.py @@ -14,7 +14,7 @@ from zipfile import ZIP_DEFLATED, ZipFile -ROOT = Path(__file__).resolve().parent.parent +ROOT = Path(__file__).resolve().parents[2] APPS_DIR = ROOT / "apps" PACKAGE_ROOT_NAME = "library" CHANNEL_PACKAGE_NAMES = { diff --git a/cli/README.md b/cli/README.md index cee849810..0d3d5df8c 100644 --- a/cli/README.md +++ b/cli/README.md @@ -118,4 +118,4 @@ Credentials: - resolution order: command flag > explicit `--env-file` > environment variable > default provider file - CI keeps passing secrets as environment variables from GitHub Actions secrets; it does not use `.secrets/` -Run from the repository root or a subdirectory inside it. The CLI now refuses to run outside the repository so it cannot read or write the wrong `apps/` or `metadata/` tree by accident. CLI does not depend on `build/`. +Run from the repository root or a subdirectory inside it. The CLI now refuses to run outside the repository so it cannot read or write the wrong `apps/` or `metadata/` tree by accident. CLI does not depend on the publishing scripts under `ci/scripts/`. diff --git a/docs/appstore-release-spec.md b/docs/appstore-release-spec.md index 09e30ec9a..ae4e99830 100644 --- a/docs/appstore-release-spec.md +++ b/docs/appstore-release-spec.md @@ -563,7 +563,7 @@ artifact/appstore// 2. 解析 channel 3. 检查 R2 apps/ 是否为空 → 空则标记首次发布(--all-apps) 4. 从 Contentful 拉取 catalog 源数据 -5. 运行 library_publish.py 构建所有制品(v2 + legacy),并以仓库 variables.json 统一 product distribution 数据结构 +5. 运行 `ci/scripts/library_publish.py` 构建所有制品(v2 + legacy),并以仓库 variables.json 统一 product distribution 数据结构 6. 上传 v2 制品到新 R2 路径(`channel` 只由目录表达,full 固定入口统一为 `latest.zip`) 7. 上传 legacy 制品到旧 R2 路径(兼容旧消费者) 8. 清除 Cloudflare 缓存 diff --git a/docs/architecture.md b/docs/architecture.md index 34c99a571..be61185d9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -9,8 +9,7 @@ Core layout: - `metadata/archive.yaml`: archived app metadata and external handoff flags - `skills/`: canonical shared skills for multiple agents - `metadata/templates/`: app scaffold, README, and catalog templates -- `ci/scripts/`: local and CI helper scripts -- `build/`: generation and publishing scripts +- `ci/scripts/`: local, CI, and publishing scripts - `docs/`: product, process, and maintainer docs - `.github/workflows/`: CI, release, and maintenance automation diff --git a/docs/devops-spec.md b/docs/devops-spec.md index 8124679e8..628dd4760 100644 --- a/docs/devops-spec.md +++ b/docs/devops-spec.md @@ -315,7 +315,7 @@ Those concerns belong to platform workflows or human process. Recommended order: -1. Normalize existing `build/*.py` inputs and outputs. +1. Normalize existing `ci/scripts/*.py` inputs and outputs. 2. Introduce a thin unified CLI. 3. Update workflows to call the CLI. 4. Add `make` only if maintainers need local shortcuts. diff --git a/docs/test.md b/docs/test.md index 6609cad44..8ac73a586 100644 --- a/docs/test.md +++ b/docs/test.md @@ -4,7 +4,7 @@ This repository uses five test layers: 1. Unit tests: `cli/libs` pure logic. 2. CLI contract tests: command input, JSON output, and exit code. -3. Metadata and template consistency tests: `metadata/`, templates, `build/` pipeline smoke, and repository facts. +3. Metadata and template consistency tests: `metadata/`, templates, publish pipeline smoke, and repository facts. 4. App deploy validation: changed apps only, high cost, not the default local loop. 5. Owner E2E: final human verification. diff --git a/tests/build/test_fetch_catalog.py b/tests/build/test_fetch_catalog.py index 22a820bf3..6f547cf16 100644 --- a/tests/build/test_fetch_catalog.py +++ b/tests/build/test_fetch_catalog.py @@ -4,7 +4,7 @@ from _helpers import REPO_ROOT, load_build_module -fetch_catalog = load_build_module("fetch_catalog_test", REPO_ROOT / "build" / "fetch_catalog.py") +fetch_catalog = load_build_module("fetch_catalog_test", REPO_ROOT / "ci" / "scripts" / "fetch_catalog.py") def test_fetch_catalog_entries_returns_collection_items(monkeypatch): diff --git a/tests/build/test_library_publish.py b/tests/build/test_library_publish.py index 79db585f1..e063517d4 100644 --- a/tests/build/test_library_publish.py +++ b/tests/build/test_library_publish.py @@ -8,7 +8,7 @@ from _helpers import REPO_ROOT, load_build_module -library_publish = load_build_module("library_publish_test", REPO_ROOT / "build" / "library_publish.py") +library_publish = load_build_module("library_publish_test", REPO_ROOT / "ci" / "scripts" / "library_publish.py") def test_hash_content_is_deterministic_and_input_sensitive():