private BuildPromotion getBuildToTrigger()

in rest-api/src/jetbrains/buildServer/server/rest/model/build/Build.java [1748:1927]


  private BuildPromotion getBuildToTrigger(@Nullable final SUser user, @NotNull final ServiceLocator serviceLocator, @NotNull final Map<Long, Long> buildPromotionIdReplacements) {
    List<BuildPromotion> customDependencies = Collections.emptyList();
    if (submittedBuildDependencies != null) {
      customDependencies = submittedBuildDependencies.getFromPosted(serviceLocator, buildPromotionIdReplacements);
    }

    SVcsModification changeToUse = null;
    SVcsModification personalChangeToUse = null;
    if (myLastChanges != null) {
      List<SVcsModification> lastChanges = myLastChanges.getChangesFromPosted(serviceLocator.getSingletonService(ChangeFinder.class));
      if (lastChanges.size() > 0) {
        boolean changeProcessed = false;
        boolean personalChangeProcessed = false;
        for (SVcsModification change : lastChanges) {
          if (!change.isPersonal()) {
            if (!changeProcessed) {
              changeToUse = change;
              changeProcessed = true;
            } else {
              throw new BadRequestException("Several non-personal changes are submitted, only one can be present");
            }
          } else {
            if (!personalChangeProcessed) {
              personalChangeToUse = change;
              personalChangeProcessed = true;
            } else {
              throw new BadRequestException("Several personal changes are submitted, only one can be present");
            }
          }
        }
      }
    }

    final SBuildType submittedBuildType = getSubmittedBuildType(serviceLocator, personalChangeToUse, user);
    final BuildCustomizerEx customizer = (BuildCustomizerEx)serviceLocator.getSingletonService(BuildCustomizerFactory.class).createBuildCustomizer(submittedBuildType, user);
    if (changeToUse != null) {
      customizer.setChangesUpTo(changeToUse); //might need to rework after comparison to code in jetbrains.buildServer.controllers.RunBuildBean.setupBuildCustomizer: customizer.setNodeRevisions, etc.
    } else if (submittedRevisions != null) {
      try {
        setupRevisionsInCustomizer(customizer, submittedBuildType, submittedRevisions, customDependencies);
      } catch (RevisionsNotFoundException e) {
        StringBuilder missingRevisionsError = new StringBuilder("Missing revisions for the following build configurations and VCS roots:");
        e.getMissingRevisionsMap().forEach((bt, roots) -> {
          missingRevisionsError.append("\n");
          missingRevisionsError.append("build configuration: ").append(bt.getExternalId()).append(", VCS roots: ");
          missingRevisionsError.append(StringUtil.join(",", roots.stream().map(r -> r.getParent().getExternalId()).collect(Collectors.toList())));
        });

        missingRevisionsError.append("\n(add attribute failOnMissingRevisions=false to the revisions element to disable this check)");

        throw new BadRequestException(missingRevisionsError.toString());
      }
    }

    if (myComment != null) {
      if (myComment.text != null) {
        customizer.setBuildComment(myComment.text);
      } else {
        throw new BadRequestException("Submitted comment does not have 'text' set.");
      }
    }

    if (myProperties != null) {
      final ParameterFactory parameterFactory = serviceLocator.getSingletonService(ParameterFactory.class);

      if (myProperties.getProperties() != null) {
        List<Parameter> parameters = myProperties.getProperties().stream().map(prop -> {
          String propValue = Objects.toString(prop.value, "");
          if (prop.name != null && prop.type != null && prop.type.rawValue != null) {
            return parameterFactory.createTypedParameter(prop.name, propValue, prop.type.rawValue);
          } else if (prop.name != null) {
            return parameterFactory.createSimpleParameter(prop.name, propValue);
          } else {
            throw new BadRequestException("Incorrectly configured parameter: the name is null.");
          }
        }).collect(Collectors.toList());

        customizer.setParameters(parameters);
      }
    }

    if (submittedBranchName != null) {
      customizer.setDesiredBranchName(
        submittedBranchName); //this should ideally be used only when defaultBranc flag is not set. If set to false, should use customizer.setDesiredBranchName(submittedBranchName, false)
    }
    if (submittedPersonal != null) customizer.setPersonal(submittedPersonal);

    if (!customDependencies.isEmpty()) {
      try {
        customizer.setSnapshotDependencyNodes(customDependencies);
      } catch (IllegalArgumentException e) {
        throw new BadRequestException("Error trying to use specified snapshot dependencies" + getRelatedBuildDescription() + ":" + e.getMessage());
      } catch (NotFoundException e) {
        throw new BadRequestException("Error searching for snapshot dependency" + getRelatedBuildDescription() + ": " + e.getMessage(), e);
      }
    }

    if (myTriggeringOptions != null) {
      if (myTriggeringOptions.cleanSources != null) {
        customizer.setCleanSources(myTriggeringOptions.cleanSources);
      }
      if (myTriggeringOptions.cleanSourcesInAllDependencies != null) {
        customizer.setApplyCleanSourcesToDependencies(myTriggeringOptions.cleanSourcesInAllDependencies);
      }
      if (myTriggeringOptions.freezeSettings != null) {
        customizer.setFreezeSettings(myTriggeringOptions.freezeSettings);
      }
      if (myTriggeringOptions.tagDependencies != null) {
        customizer.setApplyTagsToDependencies(myTriggeringOptions.tagDependencies);
      }
      if (myTriggeringOptions.rebuildAllDependencies != null) {
        customizer.setRebuildDependencies(myTriggeringOptions.rebuildAllDependencies);
      }
      if (myTriggeringOptions.rebuildFailedOrIncompleteDependencies != null && myTriggeringOptions.rebuildFailedOrIncompleteDependencies) {
        customizer.setRebuildDependencies(BuildCustomizerEx.RebuildDependenciesMode.FAILED_OR_INCOMPLETE);
      }
      if (myTriggeringOptions.rebuildDependencies != null) {
        customizer.setRebuildDependencies(CollectionsUtil.convertCollection(
          myTriggeringOptions.rebuildDependencies.getFromPosted(serviceLocator.getSingletonService(BuildTypeFinder.class)), source -> {
            if (source.getBuildType() == null) {
              //noinspection ConstantConditions
              throw new BadRequestException("Template is specified instead of a build type. Template id: '" + source.getTemplate().getExternalId() + "'");
            }
            return source.getBuildType().getInternalId();
          }));
      }
    }

    List<BuildPromotion> artifactDepsBuildsPosted;
    try {
      artifactDepsBuildsPosted = submittedBuildArtifactDependencies == null ? null : submittedBuildArtifactDependencies.getFromPosted(serviceLocator, buildPromotionIdReplacements);
    } catch (NotFoundException e) {
      throw new BadRequestException("Error searching for artifact dependency" + getRelatedBuildDescription() + ": " + e.getMessage(), e);
    }
    if (submittedCustomBuildArtifactDependencies != null) {
      //todo: investigate if OK: here new dependencies are created and set into the build. Custom run build dialog onthe contrary, sets artifact deps with the same IDs into the build
      final List<SArtifactDependency> customDeps = submittedCustomBuildArtifactDependencies.getFromPosted(submittedBuildType.getArtifactDependencies(), serviceLocator);
      if (artifactDepsBuildsPosted == null) {
        setDepsWithNullCheck(customizer, customDeps);
      } else {
        //patch with "artifact-dependencies"
        setDepsWithNullCheck(customizer, getBuildPatchedDeps(customDeps, true, serviceLocator, artifactDepsBuildsPosted));
      }
    } else {
      if (artifactDepsBuildsPosted != null) {
        //use "artifact-dependencies" as the only dependencies as this allows to repeat a build
        setDepsWithNullCheck(customizer, getBuildPatchedDeps(submittedBuildType.getArtifactDependencies(), false, serviceLocator, artifactDepsBuildsPosted));
      } else {
        //no artifact dependencies customizations necessary
      }
    }

    if (myTags != null) {
      customizer.setTagDatas(new HashSet<TagData>(myTags.getFromPosted(serviceLocator.getSingletonService(UserFinder.class))));
    }
    if (myAttributes != null) {
      customizer.setAttributes(myAttributes.getMap());
    }
    final BuildPromotion result;
    try {
      result = customizer.createPromotion();
    } catch (IllegalStateException e) {
      //IllegalStateException is thrown e.g. when we try to create a personal build in a build type which does not allow this
      throw new BadRequestException("Cannot trigger build: " + e.getMessage());
    } catch (RevisionsNotFoundException e) {
      throw new BadRequestException(
        "Cannot trigger build, if the changes are specified, they should be visible on the build configuration Change Log under the requested branch. Original error: " +
        e.getMessage());
    }
    BuildTypeEx modifiedBuildType = getCustomizedSubmittedBuildType(serviceLocator);
    if (modifiedBuildType != null) {
      //it's core's responsibility to check permissions here
      try {
        ((BuildPromotionEx)result).freezeSettings(modifiedBuildType, "rest");
      } catch (IOException e) {
        throw new OperationException("Error while freezing promotion settings", e); //include nested erorr or it can expose too much data?
      }
    }
    return result;
  }