Search code examples
yamlyq

yq replace a value with another value of a map


  myFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myFunction
      Handler: myFunction.lambda_handler

  myOtherFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myOtherFunction
      Handler: myOtherFunction.lambda_handler

I want to run a yq command such that for every Type:AWS::Serverless::Function resources, I'd like to grab the value of the Handler and make another attribute under properties called Environment.Variables.HANDLER.

I have following command so far.
yq '(.Resources.[] | select(.Type=="AWS::Serverless::Function") | .Properties.Environment.Variables.HANDLER) += (.Resources.[].Properties.Handler)' test.yaml

Which ends up with

  myFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myFunction
      Handler: myFunction.lambda_handler
      Environment:
      Variables:
        HANDLER: myOtherFunction.lambda_handler # This is wrong

  myOtherFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myOtherFunction
      Handler: myOtherFunction.lambda_handler
      Environment:
        Variables:
          HANDLER: myOtherFunction.lambda_handler

Where Environment.Variables.HANDLER is replaced with myOtherFunction's Handler for all the functions. How do I respectively grab the value from the particular resource to be replaced?


Solution

  • Use the update operator |= whenever you want to stay in context.

    .Resources[]
      |= select(.Type=="AWS::Serverless::Function").Properties
        |= .Environment.Variables.HANDLER = .Handler
    

    Or use the with function:

    with(
      .Resources[] | select(.Type=="AWS::Serverless::Function").Properties;
      .Environment.Variables.HANDLER = .Handler
    )
    

    Both evaluate to:

    Resources:
      myFunction:
        Type: AWS::Serverless::Function
        Properties:
          FunctionName: myFunction
          Handler: myFunction.lambda_handler
          Environment:
            Variables:
              HANDLER: myFunction.lambda_handler
      myOtherFunction:
        Type: AWS::Serverless::Function
        Properties:
          FunctionName: myOtherFunction
          Handler: myOtherFunction.lambda_handler
          Environment:
            Variables:
              HANDLER: myOtherFunction.lambda_handler
    

    Note: In your approach, using .Resources.[] a second time started iterating all over again, so all matching items received the last value fetched.