Hello @AndreRosot
Thank you for your answer. The one of problems was that I haven’t been familiar to dark features flags and didn’t realise that i have to turn flag com.atlassian.jira.migration-assistant.enable.app-vendor-check on. Just done it:
After setting the flag, I see another option in checks (so I assumed everything works):
However i was not able to trigger anny warning/error message due to my check. It seems my validation checks are still not triggered at all. I always got an info about valid response from check (as on above screen).
So I cloned example app repo and run it just to check how it worl/should look but the app seems to be not avaliable in cloud, so JCMA even didn’t catch the app to migrate.
At this point I don’t know what to do to be able to display an check message.
My check repo class
import com.atlassian.migration.app.check.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.*;
import static com.atlassian.migration.app.check.CheckResultBuilder.resultBuilder;
import static com.atlassian.migration.app.check.CheckStatus.*;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonMap;
@Component
@Slf4j
public class ExampleMigrationChecks implements PreMigrationCheckRepository {
@Override
public Set<CheckSpec> getAvailableChecks() {
HashSet<CheckSpec> checks = new HashSet<>();
try {
// You can have multiple checks, up to 3 checks will be executed. If there's more than that, some checks will be ignored.
checks.add(createTspValidationCheck());
checks.add(createTSPDeferencesCheck());
} catch (IllegalArgumentException e) {
// Invalid checkIds, title and stepsToResolve can throw this exception from CheckSpec's constructor
e.printStackTrace();
}
return checks;
}
/*
* Perform the checks for that specific checkId.
* If you have multiple checks they may be executed in parallel.
* This method should reply under 5 minutes to avoid time-outs.
*/
@Override
public CheckResult executeCheck(String checkId, MigrationPlanContext migrationPlanContext) {
log.info("Running checks for plan {}", migrationPlanContext.getPlanName());
log.info("Context of the migration: {}", Arrays.toString(migrationPlanContext.getContainers().toArray()));
switch (checkId) {
case "Test-validation-check":
return new CheckResult(SUCCESS); // You probably want to run some checks. Here we just keep it simple
case "Test-deference-check":
return executeComplicatedCheck();
default:
throw new IllegalStateException("Unknown check: " + checkId);
}
}
private static CheckSpec createTestValidationCheck() {
// Creating our first check. CheckSpec will validate some base pre-conditions, like valid checkId.
CheckSpec simplePermissionCheck = new CheckSpec(
"Test-validation-check", // Unique ID across all the implemented checks
"Test Validation Check", // Check's title
"There are invalid scheduled issues!", // A brief description
singletonMap("template1", "Steps how to resolve this check") // A template that contains instructions on how to resolve this check
);
/* Before returning these checks we advise to invoke the `validate()` method. We truncate the content
* based on the following rules:
* `title` should not exceed 60 characters
* `stepsToResolve` should not exceed 1050 characters
*
* validate() will return List<String> that contains these error messages
*/
List<String> validationErrors = simplePermissionCheck.validate();
if (!validationErrors.isEmpty()) {
log.warn("Validation errors found: " + validationErrors);
}
return simplePermissionCheck;
}
private CheckSpec createTestDeferencesCheck() {
CheckSpec complicatedCheckWithTemplates = new CheckSpec(
"Test-deference-check",
"Test Deference check",
"Some configuration is impossible to migrate",
buildStepsToResolveTemplates());
List<String> validationErrors = complicatedCheckWithTemplates.validate();
if (!validationErrors.isEmpty()) {
log.warn("Validation errors found: " + validationErrors);
}
return complicatedCheckWithTemplates;
}
private CheckResult executeComplicatedCheck() {
try {
// Optional details that can be downloaded by the user in CSV format
CsvFileContent csvFile = new CsvFileContent(asList("Jira Issue", "Description"));
csvFile.addRow(asList("FTP-13", "A very important customer request"));
csvFile.addRow(asList("FTP-9", "Another very important customer request"));
// Using CheckResultBuilder, but you can also directly instantiate CheckResult
CheckResultBuilder builder = resultBuilder(BLOCKING).withCsvFileContent(csvFile);
if (checkSomething()) { // Let's suppose that you detected issues with permissions, for example
builder.withStepsToResolveKey("Test-steps-to-resolve-missing-team-field"); // Be sure to use an existing stepsToResolveKey previously provided on the CheckSpec
}
return builder.build();
} catch (
Exception e) { // Optional. If your code throws an exception, we'll implicitly convert it into a failed result like this one.
return resultBuilder(CHECK_EXECUTION_ERROR).build();
}
}
private static boolean checkSomething() {
return true; // We aren't really checking :)
}
/*
* stepsToResolve is a map between a stepsToResolveKey and the actual description of steps to unblock the customer.
* The stepsToResolveKey has to match the value used on CheckResult
*/
private Map<String, String> buildStepsToResolveTemplates() {
/*
* You can format the instructions for better readability, this will be reflected in the UI.
* Only these 3 tags are recognized:
* <paragraph>
* <ordered-item>
* <unordered-item>
*
* We encourage all texts to be placed in proper tags and within limit of 1050 (including tags) characters,
* any invalid/improper tag is not guaranteed to be rendered properly in UI. Templates exceeding the limit will
* be truncated.
*
* These templates allow you to choose the appropriate instructions to resolve the issue when returning a
* `CheckResult`.
*/
Map<String, String> stepsToResolve = new HashMap<>();
stepsToResolve.put("Test-steps-to-resolve-missing-team-field",
"<paragraph>Some projects had issue where field \"Team\" was not set. Please follow steps to fix those issues.</> " +
"<unordered-item>Go to project mentioned in the csv file.</>" +
"<unordered-item>Open the respective issues mentioned in the csv file</>" +
"<unordered-item>Update the value of field:Team</>");
// In this example we won't use it, but you can have multiple stepsToResolve entries
stepsToResolve.put("Test-steps-to-resolve-permission-error",
"<paragraph>App do not have right permissions at some projects. Please follow steps to fix those issues.</>" +
"<ordered-item>Go to project settings for project keys mentioned in the csv file.</>" +
"<ordered-item>Assign read/write permissions to app</>" +
"<ordered-item>Re-run the check</>");
return stepsToResolve;
}
}