You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
5.4 KiB
103 lines
5.4 KiB
# -*- coding: utf-8 -*-
|
|
"""岗位与企业展示字段批次:把运行时 OpenAPI 的展示字段约束与文档模型同步进静态契约
|
|
``docs/openapi-rc.json``。
|
|
|
|
本轮整改(对照整改项 2)后,本批相关字段的约束由**纯文档型注解**在运行时表达
|
|
(如 ``@Schema(types={"string","null"}, maxLength=40)``、``@ArraySchema(maxItems=20, schema=@Schema(types={"string"}, maxLength=40))``),
|
|
因此静态契约与运行时契约可以在**同一 OpenAPI 3.1 表示**下逐项对齐:
|
|
|
|
* ``JobCreateRequest`` / ``JobUpdateRequest``:experience/education(≤40,可空)、
|
|
workLocation(≤255,可空)、benefits(数组、最多 20 项、单项 ≤40、元素为 string)、
|
|
salaryMonths(整数 1—24,可空),以及 salaryMin/salaryMax 的“元/月”说明。
|
|
* ``CompanyCreateRequest`` / ``CompanyUpdateRequest`` / ``CompanyPublicView`` 的 companySize(≤40,可空)。
|
|
* ``CompanyManagedJobItem`` 的展示字段。
|
|
* Map 型岗位响应的**文档模型**:``ApiResponseJobDetailViewDoc`` / ``ApiResponseJobListViewDoc`` /
|
|
``ApiResponseJobPublicViewDoc`` 及其 data(``JobDetailViewDoc``/``JobListViewDoc``/``JobPublicViewDoc``/``JobDocCompanySummary``)。
|
|
这 7 个组件整体从运行时同步,并把 ``GET /jobs``、``POST /jobs``、``PUT /jobs/{jobId}``、``GET /jobs/{jobId}``、
|
|
``GET /jobs/public/{jobId}`` 的 200 响应引用与说明对齐。
|
|
|
|
不新增/删除端点(本批基线 paths=201 / operations=245 不变)。
|
|
|
|
用法:
|
|
python docs/_update_job_company_display_fields_openapi.py [--runtime <runtime-openapi.json>]
|
|
"""
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent
|
|
STATIC = ROOT / "openapi-rc.json"
|
|
DEFAULT_RUNTIME = ROOT / "acceptance" / "batch-display-fields-20261016" / "runtime-openapi.json"
|
|
|
|
DISPLAY_FIELDS = ("experience", "education", "benefits", "salaryMonths", "workLocation")
|
|
SALARY_FIELDS = ("salaryMin", "salaryMax")
|
|
JOB_REQUEST_SCHEMAS = ("JobCreateRequest", "JobUpdateRequest")
|
|
COMPANY_SIZE_SCHEMAS = ("CompanyCreateRequest", "CompanyUpdateRequest", "CompanyPublicView")
|
|
DOC_SCHEMAS = ("JobDocCompanySummary", "JobDetailViewDoc", "JobPublicViewDoc", "JobListViewDoc",
|
|
"ApiResponseJobDetailViewDoc", "ApiResponseJobPublicViewDoc", "ApiResponseJobListViewDoc")
|
|
MAP_RESPONSE_OPS = (("/jobs", "get", "ApiResponseJobListViewDoc"),
|
|
("/jobs", "post", "ApiResponseJobDetailViewDoc"),
|
|
("/jobs/{jobId}", "get", "ApiResponseJobDetailViewDoc"),
|
|
("/jobs/{jobId}", "put", "ApiResponseJobDetailViewDoc"),
|
|
("/jobs/public/{jobId}", "get", "ApiResponseJobPublicViewDoc"))
|
|
|
|
|
|
def patch_display_props(static_schemas, runtime_schemas):
|
|
for name in JOB_REQUEST_SCHEMAS:
|
|
sp = static_schemas[name]["properties"]
|
|
rp = runtime_schemas[name]["properties"]
|
|
benefits = rp['benefits']
|
|
assert benefits.get('x-normalization') == dict(trimItems=True, deduplicate=True, rejectBlankItems=True,
|
|
maxItems=20, itemMaxLength=40), '运行时福利语义错误,拒绝覆盖静态契约'
|
|
assert 'maxItems' not in benefits and 'maxLength' not in benefits.get('items', {}), '拒绝写入原始请求限制'
|
|
for field in DISPLAY_FIELDS + SALARY_FIELDS:
|
|
sp[field] = rp[field]
|
|
for name in COMPANY_SIZE_SCHEMAS:
|
|
static_schemas[name]["properties"]["companySize"] = \
|
|
runtime_schemas[name]["properties"]["companySize"]
|
|
mp = static_schemas["CompanyManagedJobItem"]["properties"]
|
|
rmp = runtime_schemas["CompanyManagedJobItem"]["properties"]
|
|
for field in DISPLAY_FIELDS + SALARY_FIELDS:
|
|
mp[field] = rmp[field]
|
|
|
|
|
|
def patch_doc_schemas(static_schemas, runtime_schemas):
|
|
for name in DOC_SCHEMAS:
|
|
assert name in runtime_schemas, "运行时缺少文档模型 %s" % name
|
|
static_schemas[name] = runtime_schemas[name]
|
|
|
|
|
|
def patch_response_refs(static_paths, runtime_paths):
|
|
for path, method, schema in MAP_RESPONSE_OPS:
|
|
static_resp = static_paths[path][method]["responses"]["200"]
|
|
runtime_resp = runtime_paths[path][method]["responses"]["200"]
|
|
static_resp["description"] = runtime_resp.get("description", static_resp.get("description", "OK"))
|
|
static_resp["content"] = runtime_resp["content"]
|
|
ref = runtime_resp["content"]["*/*"]["schema"].get("$ref", "")
|
|
assert ref.endswith(schema), "%s %s 运行时响应引用异常:%s" % (method.upper(), path, ref)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--runtime", default=str(DEFAULT_RUNTIME))
|
|
args = parser.parse_args()
|
|
|
|
doc = json.load(open(STATIC, encoding="utf-8"))
|
|
runtime = json.load(open(args.runtime, encoding="utf-8"))
|
|
static_schemas = doc["components"]["schemas"]
|
|
runtime_schemas = runtime["components"]["schemas"]
|
|
|
|
patch_display_props(static_schemas, runtime_schemas)
|
|
patch_doc_schemas(static_schemas, runtime_schemas)
|
|
patch_response_refs(doc["paths"], runtime["paths"])
|
|
|
|
with open(STATIC, "w", encoding="utf-8", newline="\n") as fh:
|
|
json.dump(doc, fh, ensure_ascii=False, indent=2)
|
|
fh.write("\n")
|
|
print("display-fields OpenAPI updated: paths=", len(doc["paths"]),
|
|
"operations=", sum(len(v) for v in doc["paths"].values()),
|
|
"schemas=", len(static_schemas))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|