YAML/YQ - 删除具有包含特定属性匹配项的子部分的部分

YAML/YQ - remove sections that have sub-sections containing a particular attribute match

我正在尝试使用 mikefarah 的 yq 远程访问 yaml 文件的部分,这些部分的子部分具有特定属性匹配。

更具体地说,假设我们有以下 OpenAPI 文件:

openapi: 3.0.0
protocol: https
tags:
  - description: Sample API
    name: Sample Echo API
info:
  title: UUID generator based on httpbin.org
  version: 1.0.3
paths:
  /uuid:
    get:
      responses:
        "200":
          description: A UUID4.
      summary: Return a UUID4.
      tags:
        - UUID Ops
  /uuid/{uuid}:
    delete:
      parameters:
        - in: path
          name: uuid
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Deleted okay.
      summary: This endpoint makes no sense.
      tags:
        - UUID Ops
        - Experimental
  /delay/{delay}:
    get:
      parameters:
        - in: path
          name: delay
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Returns a delayed response
      summary: Returns a delayed response
      tags:
        - Delayed Response  
        - Experimental
servers:
  - url: https://httpbin.org/

我想删除所有带有“实验”标签的 API 端点,所以基本上生成的文件是:

openapi: 3.0.0
protocol: https
tags:
  - description: Sample API
    name: Sample Echo API
info:
  title: UUID generator based on httpbin.org
  version: 1.0.3
paths:
  /uuid:
    get:
      responses:
        "200":
          description: A UUID4.
      summary: Return a UUID4.
      tags:
        - UUID Ops
servers:
  - url: https://httpbin.org/

我苦苦挣扎的地方是为 yq 命令找到正确的 'level' 以这种方式工作。

例如,我知道我可以用几种不同的方式显示所有标签:

yq eval '.paths[]?[]?.tags?' openapi.yaml

yq eval '.. | select(. == "Experimental")' openapi.yaml

但是当我尝试如下操作时,根据标签删除父部分(即实际的 API 块):

yq eval '.paths | del(.. | select(. == "Experimental"))' openapi.yaml

yq eval '.paths |= with_entries(del(select(.. | select(. == "Experimental"))) )' openapi.yaml

它所做的只是删除特定的 Experimental 标签,而不是实际的 API 块。

请问我做错了什么?

对于 mikefarah/yq,这有点棘手,但您可以使用 with_entriescontains 方法来实现您想要的结果

yq e '
  .paths |= 
     with_entries( select( .value[].tags | contains(["Experimental"] ) | not ) )' yaml

使用 with_entries,您的每个地图元素都被转换为 key/value 对,并且通过使用特殊符号 .value[],您可以绕过顶级键 - /uuid, /uuid/{uuid} 并直接在 tags

上应用您的过滤器

使用 contains,我们能够仅过滤仅包含 "Experimental" 的必要对象,并使用 not 否定该条件以获得您想要的结果。