code: func AddLogDogToBuild(
  	c context.Context, ub URLBuilder, mainAnno *miloProto.Step, build *ui.MiloBuildLegacy) {
  
  	// Now fill in each of the step components.
  	// TODO(hinoka): This is totes cachable.
  	build.Summary = miloBuildStep(c, ub, mainAnno, false)
  	build.Components, build.PropertyGroup = SubStepsToUI(c, ub, mainAnno.Substep)
  
  	// Take care of properties
  	propGroup := &ui.PropertyGroup{GroupName: "Main"}
  	for _, prop := range mainAnno.Property {
  		propGroup.Property = append(propGroup.Property, &ui.Property{
  			Key:   prop.Name,
  			Value: prop.Value,
  		})
  	}
  	build.PropertyGroup = append(build.PropertyGroup, propGroup)
  
  	// Build a property map so we can extract revision properties.
  	propMap := map[string]string{}
  	for _, pg := range build.PropertyGroup {
  		for _, p := range pg.Property {
  			propMap[p.Key] = p.Value
  		}
  	}
  	// HACK(hinoka,iannucci): Extract revision out of properties. This should use
  	// source manifests instead.
  	jrev, ok := propMap["got_revision"]
  	if !ok {
  		jrev, ok = propMap["revision"]
  	}
  	if ok {
  		// got_revision/revision are json strings, so it looks like "aaaaaabbcc123..."
  		var rev string
  		err := json.Unmarshal([]byte(jrev), &rev)
  		if err == nil {
  			if build.Trigger == nil {
  				build.Trigger = &ui.Trigger{}
  			}
  			build.Trigger.Revision = ui.NewLink(
  				rev, fmt.Sprintf("https://crrev.com/%s", rev), fmt.Sprintf("revision %s", rev))
  		}
  	}
  
  	return
  }
docs: // AddLogDogToBuild takes a set of logdog streams and populate a milo build.
  // build.Summary.Finished must be set.