Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
18a8c44
Issue 4664 allow a custom default version for a tool
sidoruka Oct 16, 2026
6a4618f
Issue 4664 set, show and use the default version of a tool in the GUI
sidoruka Oct 16, 2026
3233bc0
Issue 4664 launch the default version of a tool from pipe run
sidoruka Oct 16, 2026
1dd2808
Issue 4664 preselect the default version of a tool in the VS Code ext…
sidoruka Oct 16, 2026
aeb000d
Docs: Issue 4664 describe the default version of a tool
sidoruka Oct 16, 2026
1ee5dec
Issue 4664 add UI testcases for the default version of a tool
sidoruka Oct 16, 2026
7d2613c
Issue 4664 fix the spacing and wording of the default version messages
sidoruka Oct 16, 2026
565c967
Issue 4664 update the UI testcases affected by the default version of…
sidoruka Oct 16, 2026
97fe35a
Issue 4664 do not push the latest version on commit into a tool with …
sidoruka Oct 16, 2026
1a6aade
Docs: Issue 4664 describe a commit into a tool with a default version
sidoruka Oct 16, 2026
fb2209b
Issue 4664 warn that deleting another version of the default version'…
sidoruka Oct 16, 2026
0847b79
Issue 4664 expect the deletion warning in the testcase of another ver…
sidoruka Oct 16, 2026
2fdc693
Docs: Issue 4664 the deletion warning for another version of the defa…
sidoruka Oct 16, 2026
1e951ea
Issue 4664 GUI: use the default version for a pool image without a ta…
rodichenko Nov 4, 2026
a0cf49d
Docs: Issue 4664 the version used once the default version is deleted
rodichenko Nov 4, 2026
879c744
Issue 4664 testcases for the deletion warning of the default version …
rodichenko Nov 4, 2026
8a8737b
Issue 4664 default tool version: refactor
SilinPavel Nov 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions api/src/main/java/com/epam/pipeline/acl/docker/ToolApiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ public Tool updateTool(Tool tool) {
return toolManager.updateTool(tool);
}

@PreAuthorize(TOOL_WRITE)
@AclMask
public Tool updateToolDefaultVersion(final Long id, final String version) {
return toolManager.updateToolDefaultVersion(id, version);
}

@PreAuthorize(TOOL_WRITE)
@AclMask
public Tool deleteToolDefaultVersion(final Long id) {
return toolManager.deleteToolDefaultVersion(id);
}

@PreAuthorize(ADMIN_ONLY + OR + TOOL_ADMIN_ONLY)
@AclMask
public ToolVersionScanResult updateWhiteListWithToolVersion(final long toolId, final String version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public final class MessageConstants {
public static final String ERROR_TOOL_INVALID_IMAGE = "error.tool.invalid.image";
public static final String ERROR_TOOL_VERSION_INVALID_SIZE = "error.tool.version.invalid.size";
public static final String ERROR_TOOL_VERSION_DELETE_FAILED = "error.tool.version.delete.failed";
public static final String ERROR_TOOL_DEFAULT_VERSION_NOT_FOUND = "error.tool.default.version.not.found";
public static final String ERROR_TOOL_CLOUD_REGION_NOT_ALLOWED = "error.tool.cloud.region.not.allowed";

public static final String ERROR_TOOL_SYMLINK_SOURCE_TOOL_ID_MISSING = "error.tool.symlink.source.tool.id.missing";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,34 @@ public Result<List<ToolVersion>> loadToolVersionSettings(@PathVariable final Lon
return Result.success(toolApiService.loadToolVersionSettings(toolId, version));
}

@PostMapping(value = "/tool/{toolId}/defaultVersion")
@ResponseBody
@ApiOperation(
value = "Sets a tool version, which is used in place of the latest one.",
notes = "Sets a tool version, which is used in place of the latest one: f.i. it is launched, "
+ "if a tool image is specified without a tag. The version shall exist in a docker registry.",
produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(
value = {@ApiResponse(code = HTTP_STATUS_OK, message = API_STATUS_DESCRIPTION)
})
public Result<Tool> updateToolDefaultVersion(@PathVariable final Long toolId,
@RequestParam final String version) {
return Result.success(toolApiService.updateToolDefaultVersion(toolId, version));
}

@DeleteMapping(value = "/tool/{toolId}/defaultVersion")
@ResponseBody
@ApiOperation(
value = "Removes a tool default version, so that the latest version is used again.",
notes = "Removes a tool default version, so that the latest version is used again.",
produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(
value = {@ApiResponse(code = HTTP_STATUS_OK, message = API_STATUS_DESCRIPTION)
})
public Result<Tool> deleteToolDefaultVersion(@PathVariable final Long toolId) {
return Result.success(toolApiService.deleteToolDefaultVersion(toolId));
}

@RequestMapping(value = "/tool/symlink", method= RequestMethod.POST)
@ResponseBody
@ApiOperation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ enum RepositoryProperty {
TOOL_LABELS,
TOOL_ENDPOINTS,
TOOL_DEFAULT_COMMAND,
TOOL_DEFAULT_VERSION,
TOOL_OWNER,
TOOL_ICON_ID,
TOOL_ALLOW_SENSITIVE,
Expand Down Expand Up @@ -287,6 +288,7 @@ private static void initTool(ResultSet rs, Long registryId, DockerRegistry regis
}

tool.setDefaultCommand(rs.getString(TOOL_DEFAULT_COMMAND.name()));
tool.setDefaultVersion(rs.getString(TOOL_DEFAULT_VERSION.name()));
}

private static void initToolOsVersion(final ResultSet rs, final Tool tool) throws SQLException {
Expand Down
21 changes: 21 additions & 0 deletions api/src/main/java/com/epam/pipeline/dao/tool/ToolDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class ToolDao extends NamedParameterJdbcDaoSupport {
private String createToolQuery;
private String updateToolQuery;
private String updateOwnerQuery;
private String updateDefaultVersionQuery;
private String loadToolQuery;
private String loadAllToolsQuery;
private String loadToolsByGroupQuery;
Expand Down Expand Up @@ -106,6 +107,19 @@ public void updateOwner(Tool tool) {
getNamedParameterJdbcTemplate().update(updateOwnerQuery, getParameters(tool, getConnection()));
}

/**
* Sets a tool's default version, it is the only query writing it, so that a tool update cannot clear it
* @param toolId tool's id
* @param defaultVersion a version to be used in place of the "latest" one, or null to use the "latest" one
*/
@Transactional(propagation = Propagation.MANDATORY)
public void updateDefaultVersion(final Long toolId, final String defaultVersion) {
final MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue(ToolParameters.ID.name(), toolId);
params.addValue(ToolParameters.DEFAULT_VERSION.name(), defaultVersion);
getNamedParameterJdbcTemplate().update(updateDefaultVersionQuery, params);
}

public List<Tool> loadAllTools(Long registryId) {
return loadAllTools(registryId, null);
}
Expand Down Expand Up @@ -244,6 +258,7 @@ enum ToolParameters {
SHORT_DESCRIPTION,
PLATFORM,
DEFAULT_COMMAND,
DEFAULT_VERSION,
LABELS_TO_SEARCH,
OWNER,
DISK,
Expand Down Expand Up @@ -327,6 +342,7 @@ private static Tool basicInitTool(ResultSet rs, Tool tool) throws SQLException {
tool.setShortDescription(rs.getString(ToolParameters.SHORT_DESCRIPTION.name()));
tool.setPlatform(rs.getString(ToolParameters.PLATFORM.name()));
tool.setDefaultCommand(rs.getString(ToolParameters.DEFAULT_COMMAND.name()));
tool.setDefaultVersion(rs.getString(ToolParameters.DEFAULT_VERSION.name()));
tool.setOwner(rs.getString(ToolParameters.OWNER.name()));
tool.setDisk(rs.getInt(ToolParameters.DISK.name()));
tool.setInstanceType(rs.getString(ToolParameters.INSTANCE_TYPE.name()));
Expand Down Expand Up @@ -402,6 +418,11 @@ public void setUpdateOwnerQuery(String updateOwnerQuery) {
this.updateOwnerQuery = updateOwnerQuery;
}

@Required
public void setUpdateDefaultVersionQuery(final String updateDefaultVersionQuery) {
this.updateDefaultVersionQuery = updateDefaultVersionQuery;
}

@Required
public void setLoadToolQuery(String loadToolQuery) {
this.loadToolQuery = loadToolQuery;
Expand Down
10 changes: 5 additions & 5 deletions api/src/main/java/com/epam/pipeline/dao/tool/ToolVersionDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class ToolVersionDao extends NamedParameterJdbcDaoSupport {
private String loadToolVersionListSettingsQuery;
private String createToolVersionWithSettingsQuery;
private String updateToolVersionWithSettingsQuery;
private String loadAllLatestToolVersionsQuery;
private String loadAllDefaultToolVersionsQuery;

@Autowired
private DaoHelper daoHelper;
Expand Down Expand Up @@ -122,8 +122,8 @@ public Map<String, ToolVersion> loadToolVersions(final Long toolId, final List<S
.collect(Collectors.toMap(ToolVersion::getVersion, Function.identity()));
}

public List<ToolVersion> loadAllLatestToolVersions() {
return getJdbcTemplate().query(loadAllLatestToolVersionsQuery,
public List<ToolVersion> loadAllDefaultToolVersions() {
return getJdbcTemplate().query(loadAllDefaultToolVersionsQuery,
ToolVersionParameters.getRowMapperWithSettings());
}

Expand Down Expand Up @@ -253,7 +253,7 @@ public void setLoadToolVersionListSettingsQuery(final String loadToolVersionList
}

@Required
public void setLoadAllLatestToolVersionsQuery(final String loadAllLatestToolVersionsQuery) {
this.loadAllLatestToolVersionsQuery = loadAllLatestToolVersionsQuery;
public void setLoadAllDefaultToolVersionsQuery(final String loadAllDefaultToolVersionsQuery) {
this.loadAllDefaultToolVersionsQuery = loadAllDefaultToolVersionsQuery;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ private Set<String> getGpuInstanceTypes() {

private Set<Long> getGpuToolIds() {
final Set<String> gpuTypes = getGpuInstanceTypes();
return ListUtils.emptyIfNull(toolVersionManager.loadAllLatestToolVersionSettings()).stream()
return ListUtils.emptyIfNull(toolVersionManager.loadAllDefaultToolVersionSettings()).stream()
.filter(toolVersion -> ListUtils.emptyIfNull(toolVersion.getSettings()).stream()
.map(configuration -> Optional.ofNullable(configuration.getConfiguration())
.map(PipelineConfiguration::getInstanceType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ public List<ToolVersion> loadToolVersionSettings(final Long toolId, final String
return toolVersionDao.loadToolWithSettings(toolId);
}

public List<ToolVersion> loadAllLatestToolVersionSettings() {
return toolVersionDao.loadAllLatestToolVersions();
public List<ToolVersion> loadAllDefaultToolVersionSettings() {
return toolVersionDao.loadAllDefaultToolVersions();
}

private void validateToolExistsAndCanBeModified(final Long toolId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private void scanTool(final DockerRegistry registry, final Tool tool) {
} catch (Exception e) {
log.error(messageHelper.getMessage(MessageConstants.ERROR_TOOL_SCAN_FAILED, tool.getImage()), e);
toolManager.updateToolVersionScanStatus(tool.getId(), ToolScanStatus.FAILED, new Date(),
"latest", null, null, new HashMap<>(), null, null);
toolManager.resolveDefaultVersion(tool), null, null, new HashMap<>(), null, null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ public void checkToolBySecurityPolicy(JoinPoint joinPoint, PipelineStart runVO)

PipelineConfiguration configuration = configurationManager.getPipelineConfiguration(runVO);

String tag = toolManager.getTagFromImageName(configuration.getDockerImage());
Tool tool = toolManager.loadByNameOrId(configuration.getDockerImage());
String tag = toolManager.getTagFromImageName(configuration.getDockerImage(),
toolManager.resolveDefaultVersion(tool));
final ToolExecutionCheckStatus checkStatus = clairToolScanManager.checkTool(tool, tag);
if (!checkStatus.isAllowed()) {
throw new ToolExecutionDeniedException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ public boolean hasNFSParameter(PipelineConfiguration entry) {
}

public PipelineConfiguration getConfigurationForTool(final Tool tool, final PipelineConfiguration configuration) {
return Optional.ofNullable(getConfigurationForToolVersion(tool.getId(), configuration.getDockerImage(), null))
return Optional.ofNullable(getConfigurationForToolVersion(tool, configuration.getDockerImage(), null))
.map(ConfigurationEntry::getConfiguration)
.orElseGet(PipelineConfiguration::new);
}
Expand Down Expand Up @@ -515,11 +515,11 @@ private ConfigurationEntry initRegisteredPipelineConfiguration(final Long pipeli
}
}

public ConfigurationEntry getConfigurationForToolVersion(final Long toolId, final String dockerImage,
public ConfigurationEntry getConfigurationForToolVersion(final Tool tool, final String dockerImage,
final String configurationName) {
String tag = toolManager.getTagFromImageName(dockerImage);
String tag = toolManager.getTagFromImageName(dockerImage, toolManager.resolveDefaultVersion(tool));
List<ConfigurationEntry> configurationEntries =
toolVersionManager.loadToolVersionSettings(toolId, tag)
toolVersionManager.loadToolVersionSettings(tool.getId(), tag)
.stream()
.findFirst()
.map(ToolVersion::getSettings)
Expand Down Expand Up @@ -549,7 +549,7 @@ private PipelineConfiguration getConfigurationForToolRunOrPipelineRun(final Pipe
PipelineConfiguration defaultConfiguration;
ConfigurationEntry entry;
if (toolRun) {
entry = getConfigurationForToolVersion(tool.getId(), runVO.getDockerImage(),
entry = getConfigurationForToolVersion(tool, runVO.getDockerImage(),
runVO.getConfigurationName());
} else {
entry = initRegisteredPipelineConfiguration(runVO.getPipelineId(), runVO.getVersion(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2335,7 +2335,7 @@ private void validateToolSharing(final String dockerImage) {
final Tool tool = toolManager.loadByNameOrId(dockerImage);
// tool version setting has single default configuration
final ConfigurationEntry toolConfiguration = configurationManager
.getConfigurationForToolVersion(tool.getId(), dockerImage, null);
.getConfigurationForToolVersion(tool, dockerImage, null);
if (Objects.isNull(toolConfiguration)) {
return;
}
Expand Down
Loading