Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 2 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@
"env": {
"cmf_cli_feature__use_repository_clients": "true"
},
"cwd": "${workspaceFolder}/repo",
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
"console": "internalConsole"
},
{
"name": ".NET Core Attach",
Expand Down
75 changes: 75 additions & 0 deletions .vscode/scaffold-cli-project.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash
set -euo pipefail

scaffold_project() {
local projectVersion="${1:-1.0.0}"
local mesVersion="${2:-12.0.0}"

# Determine the workspace folder (parent directory of this script)
local scriptDir
scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local workspaceFolder
workspaceFolder="$(dirname "$scriptDir")"

local cmfPath="${workspaceFolder}/cmf-cli/bin/Debug/cmf"

if [ ! -x "$cmfPath" ]; then
echo "cmf executable not found at $cmfPath"
return 1
fi

# Create a fresh temp directory for this run
local tmpDir
tmpDir="$(mktemp -d -t cli-project-XXXXXX)"
cd "$tmpDir"

local deploymentBaseDir="$tmpDir/deployment"
mkdir -p "$deploymentBaseDir"

# Create infra.json
cat > infra.json << 'EOF'
{
"NPMRegistry": "https://dev.criticalmanufacturing.io/repository/npm-public/",
"CmfPipelineRepository": "https://dev.criticalmanufacturing.io/repository/npm-public/",
"NuGetRegistry": "https://dev.criticalmanufacturing.io/repository/nuget-hosted/index.json"
}
EOF

# Create env.json
cat > env.json << 'EOF'
{
"SYSTEM_NAME": "cmftraining",
"TENANT_NAME": "cmftraining",
"APPLICATION_PUBLIC_HTTP_ADDRESS": "cmftraining.local",
"APPLICATION_PUBLIC_HTTP_PORT": "80",
"APPLICATION_PUBLIC_HTTP_TLS_ENABLED": "false",
"DATABASE_ONLINE_MSSQL_ADDRESS": "db",
"DATABASE_ONLINE_MSSQL_ADDRESS": "db",
"SECURITY_PORTAL_STRATEGY_LOCAL_AD_DEFAULT_DOMAIN": "",
"DATABASE_MSSQL_ALWAYS_ON_ENABLED": "false"
}
EOF

# Run the cmf init command
local cmd=(
"$cmfPath" init ExampleProject
--version "$projectVersion"
--infra infra.json
--config env.json
--MESVersion "$mesVersion"
--deploymentDir "$deploymentBaseDir"
)
echo "Executing: ${cmd[*]}"
"${cmd[@]}"

cd "$tmpDir"
echo "Scaffolded project in: $tmpDir"
echo "Working directory is now: $(pwd)"

if [[ "${BASH_SOURCE[0]}" == "$0" ]] && [[ -t 0 ]]; then
echo "Opening an interactive shell in the scaffolded project..."
exec "${SHELL:-/bin/bash}" -i
fi
}

scaffold_project "$@"
38 changes: 38 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@
"type": "shell",
"command": "dotnet test --configuration Release -verbosity diagnostic",
"dependsOn": "use-node"
},
{
"type": "shell",
"label": "scaffold-cli",
"command": "./.vscode/scaffold-cli-project.sh \"${input:ScaffoldProjectVersion}\" \"${input:ScaffoldMesVersion}\" && exec zsh -i",
"problemMatcher": [],
"presentation": {
"echo": false,
"focus": true,
"group": "scaffold-cli",
"panel": "dedicated"
},
"runOptions": {
"runOn": "folderOpen"
}
},
{
"type": "shell",
"label": "clean-all-scaffold-cli",
"command": "find /tmp -maxdepth 1 -type d -name 'cli-project*' -exec rm -rf {} +",
"problemMatcher": [],
"presentation": {
"echo": true,
"focus": false,
"panel": "dedicated"
}
}
],
"inputs": [
Expand All @@ -61,6 +87,18 @@
"20"
],
"default": "18"
},
{
"id": "ScaffoldProjectVersion",
"type": "promptString",
"description": "Insert scaffold project's version",
"default": "12.0.0"
},
{
"id": "ScaffoldMesVersion",
"type": "promptString",
"description": "Insert scaffold project's MES version",
"default": "1.0.0"
}
]
}
18 changes: 18 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.

## [6.0.0-2](https://github.com/criticalmanufacturing/cli/compare/6.0.0-1...6.0.0-2) (2026-07-22)


### Features

* add intelisense to biz scenarios scripts ([d1ac39e](https://github.com/criticalmanufacturing/cli/commit/d1ac39ed5c31e11042425b3f60493a6d8ebb81a1))
* update iot task scaffolding with new task bases ([#765](https://github.com/criticalmanufacturing/cli/issues/765)) ([6af4eaa](https://github.com/criticalmanufacturing/cli/commit/6af4eaab73962d4138039776c68cd98663449770))
* update iot test package scaffolding to use test orchestrator ([9ca59d5](https://github.com/criticalmanufacturing/cli/commit/9ca59d5db7a46763688678353ba3708b292492f2))
* update new iot driver scaffolding to handle file access ([28f7afc](https://github.com/criticalmanufacturing/cli/commit/28f7afc93210f973e79305cad13890d27d90dc36))


### Bug Fixes

* html config overrides oob config.json on deploy ([e7dede5](https://github.com/criticalmanufacturing/cli/commit/e7dede5906b4f1f93dd63be9d042e595e81eaa58))
* iot tasks scaffolding handle empty choices ([860e6a4](https://github.com/criticalmanufacturing/cli/commit/860e6a47cd940b341c643f200984c0cfbe1e2602))
* remove deprecated always_auth from npmrc sync ([692d8f6](https://github.com/criticalmanufacturing/cli/commit/692d8f6484cbf9a1cc12ed7de92a4195d46bc06c))
* **scaffold:** use dynamic TargetFramework for data package Actions project ([a8fa808](https://github.com/criticalmanufacturing/cli/commit/a8fa80871a3a01191a07c7a28ebe568f11694952)), closes [#770](https://github.com/criticalmanufacturing/cli/issues/770)

## [6.0.0-1](https://github.com/criticalmanufacturing/cli/compare/6.0.0-0...6.0.0-1) (2026-07-06)


Expand Down
2 changes: 1 addition & 1 deletion cmf-cli/cmf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<DefaultDocumentationFileNameMode>Name</DefaultDocumentationFileNameMode>
<DefaultDocumentationNestedTypeVisibility>Namespace</DefaultDocumentationNestedTypeVisibility>
<DefaultDocumentationGeneratedPages>Namespaces</DefaultDocumentationGeneratedPages>
<Version>6.0.0-1</Version>
<Version>6.0.0-2</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 2 additions & 4 deletions core/Enums/MessageType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
/// </summary>
public enum MessageType
{
/// <summary>
/// The import object
/// </summary>
ImportObject = 0
ImportObject = 0,
ExecuteActionCode = 1
}
}
37 changes: 29 additions & 8 deletions core/Services/CmfPackageController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,25 @@ private static List<string> CheckForUnknownAttributes(XElement element, IEnumera
var allAttributes = element.Attributes().Select(a => a.Name.LocalName);
return allAttributes.Except(knownAttributes).ToList();
}

private static TEnum? ParseStepEnumAttribute<TEnum>(XElement element, string attributeName, bool strictStepParsing, ref bool hasParsingErrors) where TEnum : struct, Enum
{
var rawValue = element.Attribute(attributeName)?.Value;
if (rawValue == null)
{
return null;
}

if (Enum.TryParse<TEnum>(rawValue, out var parsedValue))
{
return parsedValue;
}

hasParsingErrors = true;
var logMsg = $"Step attribute '{attributeName}' could not be parsed as {typeof(TEnum).Name}: '{rawValue}'";
if (strictStepParsing) Log.Error(logMsg); else Log.Debug(logMsg);
return null;
}

private static CmfPackageV1 FromXmlManifest(string manifest, bool setDefaultValues = false)
{
Expand Down Expand Up @@ -373,16 +392,18 @@ public static CmfPackageV1 FromXml(XDocument xml)
throw new CliException("Invalid manifest");
}

Log.Debug($"Parsing '{rootNode.Element("packageId", true)?.Value}@{rootNode.Element("version", true)?.Value}' package's XML manifest.");

var strictStepParsing = Environment.GetEnvironmentVariable("cmf_cli_internal_strict_step_parsing") != null;
var parsingErrors = new List<string>();
bool hasParsingErrors = false;

PackageType cliPackageType = PackageType.Generic;
if (!Enum.TryParse<PackageType>(rootNode.Element("clipackagetype", true)?.Value, out cliPackageType))
{
if (!Enum.TryParse<PackageType>(rootNode.Element("packageType", true)?.Value, out cliPackageType))
{
var logMsg = $"Unknown packageType: '{rootNode.Element("packageType", true)?.Value}'";
parsingErrors.Add(logMsg);
hasParsingErrors = true;
if (strictStepParsing) Log.Error(logMsg); else Log.Debug(logMsg);
}

Expand All @@ -401,14 +422,14 @@ public static CmfPackageV1 FromXml(XDocument xml)
if (!typeParsed)
{
var logMsg = $"Step has an unknown type: {typeAttributeValue}";
parsingErrors.Add(logMsg);
hasParsingErrors = true;
if (strictStepParsing) Log.Error(logMsg); else Log.Debug(logMsg);
}

if (unknownAttributes.Count > 0)
{
var logMsg = $"Step (type: {typeAttributeValue}) has unknown attributes. Attributes: {string.Join(", ", unknownAttributes)}";
parsingErrors.Add(logMsg);
hasParsingErrors = true;
if (strictStepParsing) Log.Error(logMsg); else Log.Debug(logMsg);
}

Expand All @@ -421,7 +442,7 @@ public static CmfPackageV1 FromXml(XDocument xml)
File = element.Attribute("file")?.Value,
TagFile = bool.TryParse(element.Attribute("tagFile")?.Value, out bool tagFile) ? tagFile : null,
TargetDatabase = element.Attribute("targetDatabase")?.Value,
MessageType = Enum.TryParse(element.Attribute("messageType")?.Value, out MessageType messageType) ? messageType : null,
MessageType = ParseStepEnumAttribute<MessageType>(element, "messageType", strictStepParsing, ref hasParsingErrors),
RelativePath = null,
FilePath = element.Attribute("filePath")?.Value,
OldSystemName = element.Attribute("oldSystemName")?.Value,
Expand All @@ -433,7 +454,7 @@ public static CmfPackageV1 FromXml(XDocument xml)
ImportXMLObjectPath = element.Attribute("importXMLObjectPath")?.Value,
AutomationWorkflowFileBasePath = element.Attribute("automationWorkflowFileBasePath")?.Value,
CreateInCollection = bool.TryParse(element.Attribute("createInCollection")?.Value, out bool createInCollection) ? createInCollection : null,
TargetPlatform = Enum.TryParse(element.Attribute("targetPlatform")?.Value, out MasterDataTargetPlatformType targetPlatform) ? targetPlatform : null,
TargetPlatform = ParseStepEnumAttribute<MasterDataTargetPlatformType>(element, "targetPlatform", strictStepParsing, ref hasParsingErrors),
UserKey = element.Attribute("userKey")?.Value,
Quota = element.Attribute("quota")?.Value,
Id = element.Attribute("id")?.Value,
Expand Down Expand Up @@ -469,9 +490,9 @@ public static CmfPackageV1 FromXml(XDocument xml)
}
}

if (strictStepParsing && parsingErrors.Count > 0)
if (strictStepParsing && hasParsingErrors)
{
throw new CliException("CLI encountered unknown metadata when parsing package's manifest.xml! Check error messages for details.");
throw new CliException($"CLI encountered unknown metadata when parsing '{rootNode.Element("packageId", true)?.Value}@{rootNode.Element("version", true)?.Value}' package's manifest.xml! Check error messages for details.");
}

DependencyCollection deps = new();
Expand Down
2 changes: 1 addition & 1 deletion core/core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<PackageId>CriticalManufacturing.CLI.Core</PackageId>
<RootNamespace>Cmf.CLI.Core</RootNamespace>
<Version>6.0.0-1</Version>
<Version>6.0.0-2</Version>
<Authors>CriticalManufacturing</Authors>
<Company>CriticalManufacturing</Company>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
Expand Down
4 changes: 2 additions & 2 deletions npm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion npm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@criticalmanufacturing/cli",
"version": "6.0.0-1",
"version": "6.0.0-2",
"description": "Critical Manufacturing command line client",
"bin": {
"cmf": "run.js"
Expand Down
Loading
Loading