def ReleaseService(self,
                       service_ref,
                       config_changes,
                       tracker=None,
                       asyn=False,
                       allow_unauthenticated=None):
        """Change the given service in prod using the given config_changes.

    Ensures a new revision is always created, even if the spec of the revision
    has not changed.

    Arguments:
      service_ref: Resource, the service to release
      config_changes: list, objects that implement Adjust().
      tracker: StagedProgressTracker, to report on the progress of releasing.
      asyn: bool, if True, release asyncronously
      allow_unauthenticated: bool, True if creating a hosted Cloud Run
        service which should also have its IAM policy set to allow
        unauthenticated access. False if removing the IAM policy to allow
        unauthenticated access from a service.
    """
        if tracker is None:
            tracker = progress_tracker.NoOpStagedProgressTracker(
                stages.ServiceStages(allow_unauthenticated is not None),
                interruptable=True,
                aborted_message='aborted')
        with_image = any(
            isinstance(c, config_changes_mod.ImageChange)
            for c in config_changes)
        self._UpdateOrCreateService(service_ref, config_changes, with_image)

        if allow_unauthenticated is not None:
            try:
                tracker.StartStage(stages.SERVICE_IAM_POLICY_SET)
                tracker.UpdateStage(stages.SERVICE_IAM_POLICY_SET, '')
                self.AddOrRemoveIamPolicyBinding(
                    service_ref, allow_unauthenticated,
                    ALLOW_UNAUTH_POLICY_BINDING_MEMBERS,
                    ALLOW_UNAUTH_POLICY_BINDING_ROLE)
                tracker.CompleteStage(stages.SERVICE_IAM_POLICY_SET)
            except api_exceptions.HttpError:
                warning_message = (
                    'Setting IAM policy failed, try "gcloud beta run services '
                    '{}-iam-policy-binding --region={region} --member=allUsers '
                    '--role=roles/run.invoker {service}"'.format(
                        'add' if allow_unauthenticated else 'remove',
                        region=self._region,
                        service=service_ref.servicesId))
                tracker.CompleteStageWithWarning(
                    stages.SERVICE_IAM_POLICY_SET,
                    warning_message=warning_message)

        if not asyn:
            getter = functools.partial(self.GetService, service_ref)
            poller = ServiceConditionPoller(getter, tracker)
            self.WaitForCondition(poller)
            for msg in run_condition.GetNonTerminalMessages(
                    poller.GetConditions()):
                tracker.AddWarning(msg)
  def ReleaseService(self,
                     service_ref,
                     config_changes,
                     tracker=None,
                     asyn=False,
                     allow_unauthenticated=None,
                     for_replace=False,
                     prefetch=False,
                     build_op_ref=None,
                     build_log_url=None):
    """Change the given service in prod using the given config_changes.

    Ensures a new revision is always created, even if the spec of the revision
    has not changed.

    Arguments:
      service_ref: Resource, the service to release.
      config_changes: list, objects that implement Adjust().
      tracker: StagedProgressTracker, to report on the progress of releasing.
      asyn: bool, if True, return without waiting for the service to be updated.
      allow_unauthenticated: bool, True if creating a hosted Cloud Run
        service which should also have its IAM policy set to allow
        unauthenticated access. False if removing the IAM policy to allow
        unauthenticated access from a service.
      for_replace: bool, If the change is for a replacing the service from a
        YAML specification.
      prefetch: the service, pre-fetched for ReleaseService. `False` indicates
        the caller did not perform a prefetch; `None` indicates a nonexistant
        service.
      build_op_ref: The reference to the build.
      build_log_url: The log url of the build result.
    """
    if tracker is None:
      tracker = progress_tracker.NoOpStagedProgressTracker(
          stages.ServiceStages(allow_unauthenticated is not None),
          interruptable=True, aborted_message='aborted')
    if build_op_ref is not None:
      tracker.StartStage(stages.BUILD_READY)
      tracker.UpdateHeaderMessage('Building Container.')
      tracker.UpdateStage(
          stages.BUILD_READY, 'Logs are available at [{build_log_url}].'.format(
              build_log_url=build_log_url))
      client = cloudbuild_util.GetClientInstance()
      poller = waiter.CloudOperationPoller(client.projects_builds,
                                           client.operations)
      operation = waiter.PollUntilDone(poller, build_op_ref)
      response_dict = encoding.MessageToPyValue(operation.response)
      if response_dict and response_dict['status'] != 'SUCCESS':
        tracker.FailStage(
            stages.BUILD_READY, None,
            message='Container build failed and '
            'logs are available at [{build_log_url}].'.format(
                build_log_url=build_log_url))
        return
      else:
        tracker.CompleteStage(stages.BUILD_READY)
    if prefetch is None:
      serv = None
    else:
      serv = prefetch or self.GetService(service_ref)
    if for_replace:
      with_image = True
    else:
      with_image = any(
          isinstance(c, config_changes_mod.ImageChange) for c in config_changes)
      self._AddRevisionForcingChange(serv, config_changes)
      if serv and not with_image:
        # Avoid changing the running code by making the new revision by digest
        self._EnsureImageDigest(serv, config_changes)
    config_changes = [_SetClientNameAndVersion()] + config_changes

    self._UpdateOrCreateService(
        service_ref, config_changes, with_image, serv)

    if allow_unauthenticated is not None:
      try:
        tracker.StartStage(stages.SERVICE_IAM_POLICY_SET)
        tracker.UpdateStage(stages.SERVICE_IAM_POLICY_SET, '')
        self.AddOrRemoveIamPolicyBinding(service_ref, allow_unauthenticated,
                                         ALLOW_UNAUTH_POLICY_BINDING_MEMBER,
                                         ALLOW_UNAUTH_POLICY_BINDING_ROLE)
        tracker.CompleteStage(stages.SERVICE_IAM_POLICY_SET)
      except api_exceptions.HttpError:
        warning_message = (
            'Setting IAM policy failed, try "gcloud beta run services '
            '{}-iam-policy-binding --region={region} --member=allUsers '
            '--role=roles/run.invoker {service}"'.format(
                'add' if allow_unauthenticated else 'remove',
                region=self._region,
                service=service_ref.servicesId))
        tracker.CompleteStageWithWarning(
            stages.SERVICE_IAM_POLICY_SET, warning_message=warning_message)

    if not asyn:
      getter = functools.partial(self.GetService, service_ref)
      poller = ServiceConditionPoller(
          getter,
          tracker,
          dependencies=stages.ServiceDependencies(),
          serv=serv)
      self.WaitForCondition(poller)
      for msg in run_condition.GetNonTerminalMessages(poller.GetConditions()):
        tracker.AddWarning(msg)