轻松聘AI开发
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

# -*- 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()