diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml index a1fdb27..2216524 100644 --- a/.github/workflows/setup.yml +++ b/.github/workflows/setup.yml @@ -5,6 +5,7 @@ on: branches: - main - update-* + - migrate-* paths-ignore: - 'README.md' @@ -25,10 +26,10 @@ jobs: patch: 0 - generation: 3.5.20.0 patch: 1 - - generation: 3.5.20.0 - patch: 2 - generation: 3.5.20.0 patch: 3 + - generation: 3.5.20.0 + patch: 4 runs-on: windows-latest steps: @@ -68,7 +69,9 @@ jobs: # # Install a custom add-on package from file # - # Path to the file: example/HVAC_Building_Process_Automation_SL_3.0.0.0.package + # Path to the file: + # example/custom_packages/HVAC_Building_Process_Automation_SL_3.0.0.0.package + # example/custom_packages/HVAC_KNX_SL_1.2.2.2.package - name: Setup CODESYS id: setup_codesys uses: ./ @@ -84,4 +87,5 @@ jobs: fb6f3506-d165-4e75-a1b9-98895d542cc8,4.5.0.0 bd131967-3a89-4e22-a845-79b0be0a3ce1,4.1.0.0 add-ons-from-file-list: | - example/HVAC_Building_Process_Automation_SL_3.0.0.0.package + example/custom_packages/HVAC_KNX_SL_1.2.2.2.package + example/custom_packages/HVAC_Building_Process_Automation_SL_3.0.0.0.package diff --git a/README.md b/README.md index e08fa07..c83593f 100644 --- a/README.md +++ b/README.md @@ -18,25 +18,23 @@ It can also be used to process test cases or other CI/CD jobs in your workflow. - name: Setup CODESYS uses: powerIO-GmbH/action-codesys-setup@v1 with: - installer-version: 2.2.2 + installer-version: 2.3.0 auto-update-installer: false - generation: 3.5.19.0 + generation: 3.5.20.0 architecture: 64 - patch: 6 - hotfix: 0 - build: 0 + patch: 4 ``` ## Usage examples -- Install CODESYS Version `3.5.17.2`: +- Install CODESYS Version `3.5.20.4`: ```yml - name: Setup CODESYS uses: powerIO-GmbH/action-codesys-setup@v1 with: - generation: 3.5.17.0 + generation: 3.5.20.0 architecture: 64 - patch: 2 + patch: 4 ``` - Install CODESYS Version `3.5.20.0` with following packages. @@ -49,7 +47,7 @@ It can also be used to process test cases or other CI/CD jobs in your workflow. id: setup_codesys uses: powerIO-GmbH/action-codesys-setup@v1 with: - installer-version: 2.2.2 + installer-version: 2.3.0 auto-update-installer: true generation: 3.5.20.0 architecture: 64 @@ -58,108 +56,25 @@ It can also be used to process test cases or other CI/CD jobs in your workflow. dd6c2da4-2ed2-4076-9bf7-52394db68819,1.4.0.0 fb6f3506-d165-4e75-a1b9-98895d542cc8,4.5.0.0 add-ons-from-file-list: | - example/HVAC_Building_Process_Automation_SL_3.0.0.0.package + example/custom_packages/HVAC_Building_Process_Automation_SL_3.0.0.0.package ``` ## Inputs -The action supports the following inputs: +| Input | Description | Required | Default | +|-------|-------------|----------|----------| +| `installer-version` | The version of the installer to use to install the CODESYS installation. | false | `2.3.0` | +| `generation` | This is the base generation you want to install (e.g., `3.5.19.0`). Even if you want to install version `3.5.19.6`, you have to define the generation as `3.5.19.0`. The patch version is defined by the `patch` input. | false | `3.5.19.0` | +| `architecture` | The installation architecture of CODESYS. Allowed inputs: `32` and `64`. | false | `64` | +| `patch` | The patch of the CODESYS version to install. | false | `0` | +| `hotfix` | The hotfix of the CODESYS version to install. | false | `0` | +| `build` | The build of the CODESYS version to install. | false | `0` | +| `installation-directory` | Custom installation directory. If empty, the path is set based on architecture and installation version. Examples:
- 64-bit, generation 3.5.19.0, patch 6: `C:\Program Files\CODESYS 3.5.19.6`
- 32-bit, generation 3.5.17.0, patch 2: `C:\Program Files (x86)\CODESYS 3.5.17.2` | false | `''` | +| `auto-update-installer` | If set to `true`, the installer will be updated before the installation. | false | `true` | +| `install-add-ons` | If set to `true`, the installer will install the CODESYS AddOns. | false | `false` | +| `add-ons-list` | List of addons to install, given by ID and version. Example:
`dd6c2da4-2ed2-4076-9bf7-52394db68819,1.4.0.0`
For multiple addons, create a new line for each addon. | false | `''` | +| `add-ons-from-file-list` | List of addons to install, given by the path to the `.package` file. | false | `''` | -- `installer-version` - - The version of the installer to use to install the CODESYS installation. - - **required:** *false* - **default:** *`2.2.2`* - -- `generation` - - This is the base generation you want to install. For example `3.5.19.0`. - Even if you want to install the version `3.5.19.6` you have to define the generation as `3.5.19.0`. - The patch version is defined by the `patch` input. - - **required:** *false* - **default:** *`3.5.19.0`* - -- `architecture` - - The installation architecture of CODESYS. Allowed inputs: `32` and `64`. - - **required:** *false* - **default:** *`64`* - -- `patch` - - The patch of the CODESYS version to install. - - **required:** *false* - **default:** *`0`* - -- `hotfix` - - The hotfix of the CODESYS version to install. - - **required:** *false* - **default:** *`0`* - -- `build` - - The build of the CODESYS version to install. - - **required:** *false* - **default:** *`0`* - -- `installation-directory` - - This can be used to define a custom installation directory. - If this input is empty, the installation path is set based on the architecture and installation version. - - For example - bit `64`, generation `3.5.19.0` and patch `6`: - `C:\Program Files\CODESYS 3.5.19.6` - - For example - bit `32`, generation `3.5.17.0` and patch `2`: - `C:\Program Files (x86)\CODESYS 3.5.17.2` - - **required:** *false* - **default:** *`''`* - -- `auto-update-installer` - - If set to `true`, the installer will be updated before the installation. - - **required:** *false* - **default:** *`true`* - -- `install-add-ons` - - If set to `true`, the installer will install the CODESYS AddOns. - - **required:** *false* - **default:** *`false`* - -- `add-ons-list` - - A list of addons to install. - Given by the id and the version of the addon. - For example - Install Git: `dd6c2da4-2ed2-4076-9bf7-52394db68819,1.4.0.0` - - If you want to install multiple addons, create a new line for each addon. - For example - Install Git and Library dev package: - ``` - dd6c2da4-2ed2-4076-9bf7-52394db68819,1.4.0.0 - fb6f3506-d165-4e75-a1b9-98895d542cc8,4.5.0.0 - ``` - - **required:** *false* - **default:** *`''`* - -- `add-ons-from-file-list` - - A list of addons to install. - Given by the path to the `.package` file - - **required:** *false* - **default:** *`''`* ## Outputs diff --git a/action.yml b/action.yml index e26e1fe..a3c667a 100644 --- a/action.yml +++ b/action.yml @@ -110,36 +110,41 @@ runs: - name: Check runner OS if: runner.os != 'Windows' shell: pwsh - run: | - echo "::error::This action is only supported on Windows runners." + run: | # powershell + Write-Host "::error::This action is only supported on Windows runners." exit 1 - name: Set globals id: globals shell: pwsh - run: | - echo "::group::Set Global variables for installation" + run: | # powershell + Write-Host "::group::Set Global variables for installation" - echo "BASE_URL_INSTALLER=https://store-archive.codesys.com/ftp_download/3S/Installer/000127" >> $env:GITHUB_OUTPUT - echo "INSTALLER_VERSION=${{ inputs.installer-version }}" >> $env:GITHUB_OUTPUT - echo "INSTALLER_DIR=C:\Program Files (x86)\CODESYS\APInstaller" >> $env:GITHUB_OUTPUT + "BASE_URL_INSTALLER=https://store-archive.codesys.com/ftp_download/3S/Installer/000127" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + "INSTALLER_VERSION=${{ inputs.installer-version }}" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + "INSTALLER_DIR=C:\Program Files (x86)\CODESYS\APInstaller" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - echo "::endgroup::" + Write-Host "::endgroup::" - name: Download installer - shell: bash - run: | - echo "::group::Download CODESYS installer" + shell: pwsh + run: | # powershell + Write-Host "::group::Download CODESYS installer" + + $base_url = "${{ steps.globals.outputs.BASE_URL_INSTALLER }}" + $version = "${{ steps.globals.outputs.INSTALLER_VERSION }}" + $installer_url = "$base_url/$version/CODESYS%20Installer%20$version.exe" + $output_file = "installer.exe" - base_url=${{ steps.globals.outputs.BASE_URL_INSTALLER }} - version=${{ steps.globals.outputs.INSTALLER_VERSION }} - curl "${base_url}/${version}/CODESYS%20Installer%20${version}.exe" -o installer.exe + Write-Host "Downloading installer from $installer_url" - echo "::endgroup::" + Invoke-WebRequest -Uri $installer_url -OutFile $output_file + + Write-Host "::endgroup::" - name: Install CODESYS installer shell: pwsh - run: | + run: | # powershell Write-Host "::group::Install CODESYS installer" Write-Host "This process will take a few seconds. Please be patient." @@ -152,7 +157,7 @@ runs: - if: ${{ inputs.auto-update-installer == 'true' }} name: Update Installer shell: pwsh - run: | + run: | # powershell Write-Host "::group::Update CODESYS installer" $exePath = "${{ steps.globals.outputs.INSTALLER_DIR }}\APInstaller.CLI.exe" @@ -168,132 +173,162 @@ runs: - name: Prepare and validate inputs id: parameter_validation - shell: bash - run: | - echo "::group::Validate inputs" - - if ! [[ ${{ inputs.generation }} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Generation format is invalid. Must be X.X.X.X where X is a number." - exit 1 - fi - if [ "${{ inputs.architecture }}" != "64" ] && [ "${{ inputs.architecture }}" != "32" ]; then - echo "Architecture must be 64 or 32." - exit 1 - fi - if ! [[ ${{ inputs.patch }} =~ ^[0-9]+$ ]] \ - || ! [[ ${{ inputs.hotfix }} =~ ^[0-9]+$ ]] \ - || ! [[ ${{ inputs.build }} =~ ^[0-9]+$ ]]; then - echo "Patch, Hotfix, and Build must be numeric." - exit 1 - fi - - IFS='.' read -ra version_parts <<< "${{ inputs.generation }}" - length=${#version_parts[@]} - let "last_index=length-1" - version_parts[$last_index]=${{ inputs.patch }} - new_generation="${version_parts[0]}" - for (( i=1; i<${#version_parts[@]}; i++ )); do - new_generation="$new_generation.${version_parts[$i]}" - done - installation_name="CODESYS $(echo "${new_generation}" | sed 's/ /./g')" - - if [[ -z "${{ inputs.installation-directory }}" ]]; then - if [ "${{ inputs.architecture }}" == "64" ]; then - installation_path="C:\\Program Files\\${installation_name}" - else - installation_path="C:\\Program Files (x86)\\${installation_name}" - fi - else - installation_path="${{ inputs.installation-directory }}" - fi - echo "Installation path set to: $installation_path" - echo "installation-path=$installation_path" >> $GITHUB_OUTPUT - echo "installation-name=$installation_name" >> $GITHUB_OUTPUT - - echo "::endgroup::" + shell: pwsh + run: | # powershell + Write-Host "::group::Validate inputs" + + $generation = "${{ inputs.generation }}" + $architecture = "${{ inputs.architecture }}" + $patch = "${{ inputs.patch }}" + $hotfix = "${{ inputs.hotfix }}" + $build = "${{ inputs.build }}" + $installationDirectory = "${{ inputs.installation-directory }}" + + if ($generation -notmatch '^\d+\.\d+\.\d+\.\d+$') { + Write-Host "Generation format is invalid. Must be X.X.X.X where X is a number." + exit 1 + } + if ($architecture -ne "64" -and $architecture -ne "32") { + Write-Host "Architecture must be 64 or 32." + exit 1 + } + if ($patch -notmatch '^\d+$' -or $hotfix -notmatch '^\d+$' -or $build -notmatch '^\d+$') { + Write-Host "Patch, Hotfix, and Build must be numeric." + exit 1 + } + + # Split the generation into parts + $version_parts = $generation -split '\.' + $length = $version_parts.Length + $last_index = $length - 1 + $version_parts[$last_index] = $patch + $new_generation = $version_parts -join '.' + + $installation_name = "CODESYS $new_generation" + + if ([string]::IsNullOrWhiteSpace($installationDirectory)) { + if ($architecture -eq "64") { + $installation_path = "C:\Program Files\$installation_name" + } else { + $installation_path = "C:\Program Files (x86)\$installation_name" + } + } else { + $installation_path = $installationDirectory + } + Write-Host "Installation path set to: $installation_path" + "installation-path=$installation_path" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + "installation-name=$installation_name" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + + Write-Host "::endgroup::" - name: Install CODESYS shell: pwsh - run: | + run: | # powershell Write-Host "::group::Install CODESYS" Write-Host "This process will take a few minutes. Please be patient." - + $exePath = "${{ steps.globals.outputs.INSTALLER_DIR }}\APInstaller.CLI.exe" $arguments = "--createInstallation " + - "--product CODESYS " + - "--generation `"${{ inputs.generation }}`" " + - "--bit `"${{ inputs.architecture }}`" " + - "--patch `"${{ inputs.patch }}`" " + - "--hotfix `"${{ inputs.hotfix }}`" " + - "--build `"${{ inputs.build }}`" " + - "--installationName `"${{ steps.parameter_validation.outputs.installation-name }}`" " + - "--destinationFolder `"${{ steps.parameter_validation.outputs.installation-path }}`"" - - $process = Start-Process -FilePath $exePath -ArgumentList $arguments -Wait -NoNewWindow -PassThru - if ($process.ExitCode -eq 1 -or $process.ExitCode -eq -1) { - exit 0 - } elseif ($process.ExitCode -ne 0) { - throw "Update failed with exit code $($process.ExitCode)." + "--product CODESYS " + + "--generation `"${{ inputs.generation }}`" " + + "--bit `"${{ inputs.architecture }}`" " + + "--patch `"${{ inputs.patch }}`" " + + "--hotfix `"${{ inputs.hotfix }}`" " + + "--build `"${{ inputs.build }}`" " + + "--installationName `"${{ steps.parameter_validation.outputs.installation-name }}`" " + + "--destinationFolder `"${{ steps.parameter_validation.outputs.installation-path }}`"" + + Write-Host "Executing: $exePath $arguments" + + $startInfo = New-Object System.Diagnostics.ProcessStartInfo + $startInfo.FileName = $exePath + $startInfo.Arguments = $arguments + $startInfo.UseShellExecute = $true # Required for elevation + $startInfo.Verb = "runas" # Request elevation + + try { + $process = Start-Process -FilePath $exePath -ArgumentList $arguments -Verb runas -Wait -PassThru + $exitCode = $process.ExitCode + + Write-Host "Process completed with exit code: $exitCode" + + if ($exitCode -eq 1 -or $exitCode -eq -1) { + Write-Host "Installation completed with expected exit code" + exit 0 + } elseif ($exitCode -ne 0) { + throw "Installation failed with exit code $exitCode" + } + } + catch { + Write-Host "Error during installation: $_" + exit 1 } + Write-Host "Finished installation" Write-Host "::endgroup::" - name: Decide add-ons path id: add_ons_path - shell: bash - run: | - echo "::group::Show installation path" - - base_path="${{ steps.parameter_validation.outputs.installation-path }}" - dir_add_ons='' - if [[ -d "$base_path" ]]; then - if [[ -d "${base_path}\CODESYS\AdditionalFolders\${{ steps.parameter_validation.outputs.installation-name }}" ]]; then - dir_add_ons="${base_path}\CODESYS\AdditionalFolders\${{ steps.parameter_validation.outputs.installation-name }}" - else - if [[ -d "${base_path}\CODESYS" ]]; then - dir_add_ons="${base_path}\CODESYS" - else - echo "Installation path does not exist" - exit 1 - fi - fi - else - echo "Installation path does not exist" - exit 1 - fi - - echo "Add-Ons directory: $dir_add_ons" - echo "directory=$dir_add_ons" >> $GITHUB_OUTPUT + shell: pwsh + run: | # powershell + Write-Host "::group::Show installation path" + + $base_path = "${{ steps.parameter_validation.outputs.installation-path }}" + $installation_name = "${{ steps.parameter_validation.outputs.installation-name }}" + $dir_add_ons = '' + + if (Test-Path $base_path) { + $path1 = Join-Path $base_path "CODESYS\AdditionalFolders\$installation_name" + $path2 = Join-Path $base_path "CODESYS" + if (Test-Path $path1) { + $dir_add_ons = $path1 + } elseif (Test-Path $path2) { + $dir_add_ons = $path2 + } else { + Write-Host "Installation path does not exist" + exit 1 + } + } else { + Write-Host "Installation path does not exist" + exit 1 + } - echo "::endgroup::" + Write-Host "Add-Ons directory: $dir_add_ons" + "directory=$dir_add_ons" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + + Write-Host "::endgroup::" - if: (inputs.install-add-ons == 'true' && inputs.add-ons-list != '') - name: Install Add-ons from list + name: Install Add-ons from text entry list shell: pwsh - run: | + run: | # powershell Write-Host "::group::Install AddOns" - $addonsToInstall = "${{ inputs.add-ons-list }}" -split "\r?\n" - foreach ($addon in $addonsToInstall) { - if (-not [string]::IsNullOrWhiteSpace($addon)) { - $details = $addon -split "," - $id = $details[0].Trim() - $version = $details[1].Trim() - echo "Installing addon with ID: $id and Version: $version" - - $exePath = "${{ steps.globals.outputs.INSTALLER_DIR }}\APInstaller.CLI.exe" - $arguments = "--installAddOn " + - "--location `"${{ steps.add_ons_path.outputs.directory }}`" " + - "--id `"${id}`" " + - "--version `"${version}`"" - - $process = Start-Process -FilePath $exePath -ArgumentList $arguments -Wait -NoNewWindow -PassThru - if ($process.ExitCode -eq 1 -or $process.ExitCode -eq -1) { - exit 0 - } elseif ($process.ExitCode -ne 0) { - throw "AddOn installation failed with exit code $($process.ExitCode)." - } + $addonsToInstall = @() + $rawList = "${{ inputs.add-ons-list }}" -split "\r?\n" + foreach ($line in $rawList) { + if (-not [string]::IsNullOrWhiteSpace($line)) { + $addonsToInstall += $line.Trim() + } + } + foreach ($addon in $addonsToInstall) { + $details = $addon -split "," + $id = $details[0].Trim() + $version = $details[1].Trim() + Write-Host "Installing addon with ID: $id and Version: $version" + + $exePath = "${{ steps.globals.outputs.INSTALLER_DIR }}\APInstaller.CLI.exe" + $arguments = "--installAddOn " + + "--location `"${{ steps.add_ons_path.outputs.directory }}`" " + + "--id `"${id}`" " + + "--version `"${version}`"" + + $process = Start-Process -FilePath $exePath -ArgumentList $arguments -Verb runas -Wait -PassThru + if ($process.ExitCode -eq 1 -or $process.ExitCode -eq -1) { + exit 0 + } elseif ($process.ExitCode -ne 0) { + throw "AddOn installation failed with exit code $($process.ExitCode)." } } Write-Host "Finished installing addons" @@ -301,37 +336,44 @@ runs: Write-Host "::endgroup::" - if: (inputs.install-add-ons == 'true' && inputs.add-ons-from-file-list != '') - name: Install Add-ons from list + name: Install Add-ons from file list shell: pwsh - run: | - echo "::group::Install AddOns" + run: | # powershell + Write-Host "::group::Install AddOns" + + $packagesToInstall = @() + $rawList = "${{ inputs.add-ons-from-file-list }}" -split "\r?\n" + foreach ($line in $rawList) { + if (-not [string]::IsNullOrWhiteSpace($line)) { + # Properly handle paths with Join-Path + $packagePath = Join-Path $env:GITHUB_WORKSPACE $line.Trim() + $packagesToInstall += $packagePath + } + } - $packagesToInstall = "${{ inputs.add-ons-from-file-list }}" -split "\r?\n" foreach ($packagePath in $packagesToInstall) { - if (-not [string]::IsNullOrWhiteSpace($packagePath)) { - Write-Host "Installing package from path: $packagePath" - - $exePath = "${{ steps.globals.outputs.INSTALLER_DIR }}\APInstaller.CLI.exe" - $arguments = " --installAddOnFromFile " + - "--location `"${{ steps.add_ons_path.outputs.directory }}`" " + - "--sourcefile `"${packagePath}`"" - - $process = Start-Process -FilePath $exePath -ArgumentList $arguments -Wait -NoNewWindow -PassThru - if ($process.ExitCode -eq 1 -or $process.ExitCode -eq -1) { - exit 0 - } elseif ($process.ExitCode -ne 0) { - throw "AddOn installation failed with exit code $($process.ExitCode)." - } + Write-Host "Installing package from path: $packagePath" + + $exePath = "${{ steps.globals.outputs.INSTALLER_DIR }}\APInstaller.CLI.exe" + $arguments = "--installAddOnFromFile " + + "--location `"${{ steps.add_ons_path.outputs.directory }}`" " + + "--sourcefile `"${packagePath}`"" + + $process = Start-Process -FilePath $exePath -ArgumentList $arguments -Verb runas -Wait -PassThru + if ($process.ExitCode -eq 1 -or $process.ExitCode -eq -1) { + exit 0 + } elseif ($process.ExitCode -ne 0) { + throw "AddOn installation failed with exit code $($process.ExitCode)." } } - echo "Finished installing addons" + Write-Host "Finished installing addons" - echo "::endgroup::" + Write-Host "::endgroup::" - name: Show installation information id: install_info shell: pwsh - run: | + run: | # powershell Write-Host "::group::Show installation information" Write-Host "This process will take a few seconds. Please be patient." @@ -350,9 +392,9 @@ runs: throw "Information extraction failed with exit code $($process.ExitCode)." } - Write-Host "installation-info-file-path=$outputFile" >> $env:GITHUB_OUTPUT + "installation-info-file-path=$outputFile" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append Write-Host "Output file path: $outputFile" Get-Content -Path "$outputFile" -Encoding UTF8 Write-Host "Finished installation information extraction" - Write-Host "::endgroup::" \ No newline at end of file + Write-Host "::endgroup::" diff --git a/example/HVAC_Building_Process_Automation_SL_3.0.0.0.package b/example/custom_packages/HVAC_Building_Process_Automation_SL_3.0.0.0.package similarity index 100% rename from example/HVAC_Building_Process_Automation_SL_3.0.0.0.package rename to example/custom_packages/HVAC_Building_Process_Automation_SL_3.0.0.0.package diff --git a/example/custom_packages/HVAC_KNX_SL_1.2.2.2.package b/example/custom_packages/HVAC_KNX_SL_1.2.2.2.package new file mode 100644 index 0000000..421c392 Binary files /dev/null and b/example/custom_packages/HVAC_KNX_SL_1.2.2.2.package differ