portainer/app/react/docker/stacks/ItemView/StackEditorTab/stackYamlValidation.ts

65 lines
1.9 KiB
TypeScript

import YAML from 'yaml';
import _ from 'lodash';
import { extractContainerNamesFromYaml } from '../container-names';
/**
* Validates Docker Compose YAML content
* @param yaml - The YAML content to validate
* @param containerNames - Array of container names currently running in the environment
* @param originalContainerNames - Array of original container names from the stack (before edit)
* @returns Error message if validation fails, empty string if valid
*/
export function validateYAML(
yaml: string,
containerNames: string[] = [],
originalContainerNames: string[] = []
): string {
let yamlObject;
try {
yamlObject = YAML.parse(yaml, { maxAliasCount: 10000 });
} catch (err) {
return `There is an error in the yaml syntax: ${err}`;
}
const names = extractContainerNamesFromYaml(yamlObject);
// Find containers that are:
// 1. In the current environment (containerNames)
// 2. NOT in the original stack (originalContainerNames)
// 3. Present in the new YAML (names)
// This identifies conflicts with other stacks/containers
const duplicateContainers = _.intersection(
_.difference(containerNames, originalContainerNames),
names
);
if (duplicateContainers.length === 0) {
return '';
}
return `${
duplicateContainers.length === 1
? 'This container name is'
: 'These container names are'
} already used by another container running in this environment: ${_.join(
duplicateContainers,
', '
)}.`;
}
/**
* Checks if the YAML content has changed (ignoring line ending differences)
* @param original - Original YAML content
* @param updated - Updated YAML content
* @returns True if content has changed, false otherwise
*/
export function hasYamlChanged(original: string, updated: string): boolean {
return normalizeLineEndings(original) !== normalizeLineEndings(updated);
function normalizeLineEndings(str: string) {
return str.replace(/(\r\n|\n|\r)/gm, '');
}
}