From b4ffb29dc058f76210c85c300cc65b85e5daf8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Mon, 23 Jan 2023 03:38:53 +0100 Subject: [PATCH 1/4] Fix failing tests on windows-2022 due to WSL tool changes --- .github/workflows/template/test.yml | 26 ++++++++++++++++++++------ .github/workflows/test.yml | 23 ++++++++++++++++------- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/.github/workflows/template/test.yml b/.github/workflows/template/test.yml index 2b979c09..66651d8b 100644 --- a/.github/workflows/template/test.yml +++ b/.github/workflows/template/test.yml @@ -193,10 +193,18 @@ jobs: && (steps.execute_action.outcome == 'success') shell: wsl-bash {0} run: > - wslconfig.exe /list | iconv -f UTF-16LE -t UTF-8 + cat + <(wsl.exe --list || true) + <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) + <(wslconfig.exe /list || true) + <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) [[ - "$(wslconfig.exe /list | iconv -f UTF-16LE -t UTF-8)" + "$(cat + <(wsl.exe --list || true) + <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) + <(wslconfig.exe /list || true) + <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))" == *${{ matrix.distribution.wsl-id }}\ \(Default\)* ]] @@ -923,12 +931,18 @@ jobs: && (steps.execute_action4.outcome == 'success') shell: wsl-bash {0} run: > - wslconfig.exe /list - - wslconfig.exe /list | iconv -f UTF-16LE -t UTF-8 + cat + <(wsl.exe --list || true) + <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) + <(wslconfig.exe /list || true) + <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) [[ - "$(wslconfig.exe /list | iconv -f UTF-16LE -t UTF-8)" + "$(cat + <(wsl.exe --list || true) + <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) + <(wslconfig.exe /list || true) + <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))" == *${{ matrix.distributions.distribution2.wsl-id }}\ \(Default\)* ]] diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 061e95ef..c517072a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -135,8 +135,11 @@ jobs: shell: "wsl-bash {0}" - if: "always() && (steps.execute_action.outcome == 'success')" name: "Test - the default distribution should be correct" - run: "wslconfig.exe /list | iconv -f UTF-16LE -t UTF-8\n[[ \"$(wslconfig.exe\ - \ /list | iconv -f UTF-16LE -t UTF-8)\" == *${{ matrix.distribution.wsl-id\ + run: "cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE\ + \ -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true |\ + \ iconv -f UTF-16LE -t UTF-8)\n[[ \"$(cat <(wsl.exe --list || true) <(wsl.exe\ + \ --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true)\ + \ <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))\" == *${{ matrix.distribution.wsl-id\ \ }}\\ \\(Default\\)* ]]\n" shell: "wsl-bash {0}" - if: "always() && (steps.execute_action.outcome == 'success')" @@ -311,8 +314,11 @@ jobs: shell: "wsl-bash {0}" - if: "always() && (steps.execute_action1.outcome == 'success')" name: "Test - the default distribution should be correct" - run: "wslconfig.exe /list | iconv -f UTF-16LE -t UTF-8\n[[ \"$(wslconfig.exe\ - \ /list | iconv -f UTF-16LE -t UTF-8)\" == *${{ matrix.distribution.wsl-id\ + run: "cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE\ + \ -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true |\ + \ iconv -f UTF-16LE -t UTF-8)\n[[ \"$(cat <(wsl.exe --list || true) <(wsl.exe\ + \ --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true)\ + \ <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))\" == *${{ matrix.distribution.wsl-id\ \ }}\\ \\(Default\\)* ]]\n" shell: "wsl-bash {0}" - if: "always() && (steps.execute_action1.outcome == 'success')" @@ -827,8 +833,11 @@ jobs: - if: "always() && (steps.execute_action4.outcome == 'success')" name: "Test - the default distribution should be the last installed distribution\ \ with set-as-default true" - run: "wslconfig.exe /list\nwslconfig.exe /list | iconv -f UTF-16LE -t UTF-8\n\ - [[ \"$(wslconfig.exe /list | iconv -f UTF-16LE -t UTF-8)\" == *${{ matrix.distributions.distribution2.wsl-id\ + run: "cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE\ + \ -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true |\ + \ iconv -f UTF-16LE -t UTF-8)\n[[ \"$(cat <(wsl.exe --list || true) <(wsl.exe\ + \ --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true)\ + \ <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))\" == *${{ matrix.distributions.distribution2.wsl-id\ \ }}\\ \\(Default\\)* ]]\n" shell: "wsl-bash {0}" - if: "always() && (steps.execute_action4.outcome == 'success')" @@ -1390,4 +1399,4 @@ jobs: "user-id": "Ubuntu-16.04" "match-pattern": "*Ubuntu*16.04*" "default-absent-tool": "dos2unix" - fail-fast: false + fail-fast: false \ No newline at end of file From 4eea7c92d6c56a39bfcebcdcb93be63388497f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Mon, 23 Jan 2023 03:24:56 +0100 Subject: [PATCH 2/4] Migrate GitHub workflows to Kotlin DSL --- .../workflows/check-action-typing.main.kts | 78 + .github/workflows/check-action-typing.yaml | 57 + .github/workflows/check-action-typing.yml | 30 - .../check-dependency-versions.main.kts | 97 + .../workflows/check-dependency-versions.yaml | 62 + .../workflows/check-dependency-versions.yml | 38 - .github/workflows/template/test.yml | 1414 -------------- .github/workflows/test.main.kts | 1137 +++++++++++ .github/workflows/test.yaml | 1677 +++++++++++++++++ .github/workflows/test.yml | 1402 -------------- .../validate-gradle-wrapper.main.kts | 78 + .../workflows/validate-gradle-wrapper.yaml | 57 + .github/workflows/validate-gradle-wrapper.yml | 30 - build.gradle.kts | 4 +- .../kotlin/net/kautler/dao/GitHubWorkflow.kt | 464 ----- .../net/kautler/github_actions.gradle.kts | 64 + .../main/kotlin/net/kautler/tests.gradle.kts | 68 - .../net/kautler/util/YamlMapExtension.kt | 10 +- readme/README_template.md | 2 +- 19 files changed, 3311 insertions(+), 3458 deletions(-) create mode 100755 .github/workflows/check-action-typing.main.kts create mode 100644 .github/workflows/check-action-typing.yaml delete mode 100644 .github/workflows/check-action-typing.yml create mode 100755 .github/workflows/check-dependency-versions.main.kts create mode 100644 .github/workflows/check-dependency-versions.yaml delete mode 100644 .github/workflows/check-dependency-versions.yml delete mode 100644 .github/workflows/template/test.yml create mode 100755 .github/workflows/test.main.kts create mode 100644 .github/workflows/test.yaml delete mode 100644 .github/workflows/test.yml create mode 100755 .github/workflows/validate-gradle-wrapper.main.kts create mode 100644 .github/workflows/validate-gradle-wrapper.yaml delete mode 100644 .github/workflows/validate-gradle-wrapper.yml delete mode 100644 buildSrc/src/main/kotlin/net/kautler/dao/GitHubWorkflow.kt create mode 100644 buildSrc/src/main/kotlin/net/kautler/github_actions.gradle.kts delete mode 100644 buildSrc/src/main/kotlin/net/kautler/tests.gradle.kts diff --git a/.github/workflows/check-action-typing.main.kts b/.github/workflows/check-action-typing.main.kts new file mode 100755 index 00000000..c0725c0e --- /dev/null +++ b/.github/workflows/check-action-typing.main.kts @@ -0,0 +1,78 @@ +#!/usr/bin/env kotlin + +/* + * Copyright 2020-2023 Björn Kautler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:DependsOn("it.krzeminski:github-actions-kotlin-dsl:0.35.0") + +import it.krzeminski.githubactions.actions.actions.CheckoutV3 +import it.krzeminski.githubactions.actions.krzema12.GithubActionsTypingV0 +import it.krzeminski.githubactions.domain.RunnerType.UbuntuLatest +import it.krzeminski.githubactions.domain.triggers.PullRequest +import it.krzeminski.githubactions.domain.triggers.Push +import it.krzeminski.githubactions.dsl.workflow +import it.krzeminski.githubactions.yaml.writeToFile + +workflow( + name = "Check Action Typing", + on = listOf( + Push(), + PullRequest() + ), + sourceFile = __FILE__.toPath() +) { + job( + id = "check_action_typing", + name = "Check Action Typing", + runsOn = UbuntuLatest + ) { + run( + name = "Configure Git", + command = "git config --global core.autocrlf input" + ) + uses( + name = "Checkout", + action = CheckoutV3() + ) + uses( + name = "Check Action Typing", + action = GithubActionsTypingV0() + ) + } +}.apply { + writeToFile() + __FILE__.resolveSibling(targetFileName).apply { + writeText( + """ + |# Copyright 2020-2023 Björn Kautler + |# + |# Licensed under the Apache License, Version 2.0 (the "License"); + |# you may not use this file except in compliance with the License. + |# You may obtain a copy of the License at + |# + |# http://www.apache.org/licenses/LICENSE-2.0 + |# + |# Unless required by applicable law or agreed to in writing, software + |# distributed under the License is distributed on an "AS IS" BASIS, + |# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + |# See the License for the specific language governing permissions and + |# limitations under the License. + | + ${readText().prependIndent("|")} + """.trimMargin() + ) + } +} diff --git a/.github/workflows/check-action-typing.yaml b/.github/workflows/check-action-typing.yaml new file mode 100644 index 00000000..b8e62ee0 --- /dev/null +++ b/.github/workflows/check-action-typing.yaml @@ -0,0 +1,57 @@ +# Copyright 2020-2023 Björn Kautler +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file was generated using Kotlin DSL (.github/workflows/check-action-typing.main.kts). +# If you want to modify the workflow, please change the Kotlin file and regenerate this YAML file. +# Generated with https://github.com/krzema12/github-workflows-kt + +name: Check Action Typing +on: + push: {} + pull_request: {} +jobs: + check_yaml_consistency: + runs-on: ubuntu-latest + steps: + - id: step-0 + name: Check out + uses: actions/checkout@v3 + - id: step-1 + name: Set up Java in proper version + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: zulu + cache: gradle + - id: step-2 + name: Execute script + run: rm '.github/workflows/check-action-typing.yaml' && '.github/workflows/check-action-typing.main.kts' + - id: step-3 + name: Consistency check + run: git diff --exit-code '.github/workflows/check-action-typing.yaml' + check_action_typing: + name: Check Action Typing + runs-on: ubuntu-latest + needs: + - check_yaml_consistency + steps: + - id: step-0 + name: Configure Git + run: git config --global core.autocrlf input + - id: step-1 + name: Checkout + uses: actions/checkout@v3 + - id: step-2 + name: Check Action Typing + uses: krzema12/github-actions-typing@v0 diff --git a/.github/workflows/check-action-typing.yml b/.github/workflows/check-action-typing.yml deleted file mode 100644 index d2dd928b..00000000 --- a/.github/workflows/check-action-typing.yml +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2022 Piotr Krzemiński -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Check Action Typing - -on: - push: - pull_request: - -jobs: - check_action_typing: - name: Check Action Typing - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Check Action Typing - uses: krzema12/github-actions-typing@v0 diff --git a/.github/workflows/check-dependency-versions.main.kts b/.github/workflows/check-dependency-versions.main.kts new file mode 100755 index 00000000..d68df031 --- /dev/null +++ b/.github/workflows/check-dependency-versions.main.kts @@ -0,0 +1,97 @@ +#!/usr/bin/env kotlin + +/* + * Copyright 2020-2023 Björn Kautler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:DependsOn("it.krzeminski:github-actions-kotlin-dsl:0.35.0") + +import it.krzeminski.githubactions.actions.CustomAction +import it.krzeminski.githubactions.actions.actions.CheckoutV2 +import it.krzeminski.githubactions.domain.RunnerType.WindowsLatest +import it.krzeminski.githubactions.domain.triggers.Cron +import it.krzeminski.githubactions.domain.triggers.Schedule +import it.krzeminski.githubactions.dsl.workflow +import it.krzeminski.githubactions.yaml.writeToFile + +workflow( + name = "Check Dependency Versions", + on = listOf( + Schedule( + listOf( + Cron( + minute = "0", + hour = "0", + // work-around for https://github.com/krzema12/github-workflows-kt/issues/642 + // use FRI after the issue is fixed + dayWeek = "5" + ) + ) + ) + ), + sourceFile = __FILE__.toPath() +) { + job( + id = "check_dependency_versions", + name = "Check Dependency Versions", + runsOn = WindowsLatest + ) { + run( + name = "Configure Git", + command = "git config --global core.autocrlf input" + ) + uses( + name = "Checkout", + action = CheckoutV2() + ) + uses( + name = "Check Dependency Versions", + action = CustomAction( + actionOwner = "burrunan", + actionName = "gradle-cache-action", + actionVersion = "v1", + inputs = mapOf( + "arguments" to "dependencyUpdates", + "debug" to "false", + "concurrent" to "true", + "gradle-dependencies-cache-key" to "buildSrc/**/Versions.kt" + ) + ) + ) + } +}.apply { + writeToFile() + __FILE__.resolveSibling(targetFileName).apply { + writeText( + """ + |# Copyright 2020-2023 Björn Kautler + |# + |# Licensed under the Apache License, Version 2.0 (the "License"); + |# you may not use this file except in compliance with the License. + |# You may obtain a copy of the License at + |# + |# http://www.apache.org/licenses/LICENSE-2.0 + |# + |# Unless required by applicable law or agreed to in writing, software + |# distributed under the License is distributed on an "AS IS" BASIS, + |# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + |# See the License for the specific language governing permissions and + |# limitations under the License. + | + ${readText().prependIndent("|")} + """.trimMargin() + ) + } +} diff --git a/.github/workflows/check-dependency-versions.yaml b/.github/workflows/check-dependency-versions.yaml new file mode 100644 index 00000000..3d36e9d3 --- /dev/null +++ b/.github/workflows/check-dependency-versions.yaml @@ -0,0 +1,62 @@ +# Copyright 2020-2023 Björn Kautler +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file was generated using Kotlin DSL (.github/workflows/check-dependency-versions.main.kts). +# If you want to modify the workflow, please change the Kotlin file and regenerate this YAML file. +# Generated with https://github.com/krzema12/github-workflows-kt + +name: Check Dependency Versions +on: + schedule: + - cron: 0 0 * * 5 +jobs: + check_yaml_consistency: + runs-on: ubuntu-latest + steps: + - id: step-0 + name: Check out + uses: actions/checkout@v3 + - id: step-1 + name: Set up Java in proper version + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: zulu + cache: gradle + - id: step-2 + name: Execute script + run: rm '.github/workflows/check-dependency-versions.yaml' && '.github/workflows/check-dependency-versions.main.kts' + - id: step-3 + name: Consistency check + run: git diff --exit-code '.github/workflows/check-dependency-versions.yaml' + check_dependency_versions: + name: Check Dependency Versions + runs-on: windows-latest + needs: + - check_yaml_consistency + steps: + - id: step-0 + name: Configure Git + run: git config --global core.autocrlf input + - id: step-1 + name: Checkout + uses: actions/checkout@v2 + - id: step-2 + name: Check Dependency Versions + uses: burrunan/gradle-cache-action@v1 + with: + arguments: dependencyUpdates + debug: false + concurrent: true + gradle-dependencies-cache-key: buildSrc/**/Versions.kt diff --git a/.github/workflows/check-dependency-versions.yml b/.github/workflows/check-dependency-versions.yml deleted file mode 100644 index 5679ad51..00000000 --- a/.github/workflows/check-dependency-versions.yml +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2020 Björn Kautler -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Check Dependency Versions - -on: - schedule: - - cron: 0 0 * * FRI - -jobs: - build: - name: Check Dependency Versions - runs-on: windows-latest - steps: - - name: Configure Git - run: git config --global core.autocrlf input - - - name: Checkout - uses: actions/checkout@v2 - - - name: Check Dependency Versions - uses: burrunan/gradle-cache-action@v1 - with: - arguments: dependencyUpdates - debug: false - concurrent: true - gradle-dependencies-cache-key: buildSrc/**/Versions.kt diff --git a/.github/workflows/template/test.yml b/.github/workflows/template/test.yml deleted file mode 100644 index 66651d8b..00000000 --- a/.github/workflows/template/test.yml +++ /dev/null @@ -1,1414 +0,0 @@ -# Copyright 2020-2022 Björn Kautler -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Build and Test - -on: - push: - pull_request: - schedule: - - cron: 0 0 * * * - -jobs: - includes: - name: Define includes - if: 'false' - runs-on: self-hosted - steps: - - &execute_action - name: Execute action - id: execute_action - uses: ./ - - build: - name: Build - runs-on: windows-latest - steps: - - name: Configure Git - run: git config --global core.autocrlf input - - - name: Checkout - uses: actions/checkout@v2 - - - name: Build - uses: burrunan/gradle-cache-action@v1 - with: - arguments: build --info --stacktrace --scan - debug: false - concurrent: true - gradle-dependencies-cache-key: buildSrc/**/Versions.kt - - - &built_artifacts_cache - name: Save built artifacts to cache - uses: actions/cache@v2 - with: - path: | - action.yml - build/distributions/ - key: ${{ github.run_id }} - - test_invalid_distribution: - name: Test "${{ matrix.distribution.label }}" distribution on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - with: - distribution: ${{ matrix.distribution.user-id }} - continue-on-error: true - - - name: Test - action should fail if an invalid distribution is given - shell: cmd - run: | - if '${{ steps.execute_action.outcome }}' NEQ 'failure' exit 1 - - strategy: - fail-fast: false - matrix: - environment: &environments - - windows-2019 - - windows-2022 - - windows-latest - distribution: - - id: invalid - label: invalid - - id: '' - label: '' - - id: null - label: 'null' - - test_default_distribution: - name: Test default distribution on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - with: - update: 'true' - - - &test_wsl-bash_should_be_available_as_custom_shell - name: Test - wsl-bash should be available as custom shell - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - : - - - &test_wsl-bash_should_fail_if_the_script_fails_provocation - name: Test - wsl-bash should fail if the script fails (provocation) - id: wrapper_should_fail_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - false - continue-on-error: true - - - &test_wsl-bash_should_fail_if_the_script_fails_verification - name: Test - wsl-bash should fail if the script fails (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: cmd - # do not just rely on false here, but explicitly use exit - # in case failing commands do not make the script fail - # and use "shell: cmd" to capture that the wrapper script is hiding errors - run: | - IF '${{ steps.wrapper_should_fail_provocation.outcome }}' NEQ 'failure' EXIT /B 1 - - - &test_wsl-bash_should_fail_if_one_of_the_commands_fails_provocation - name: Test - wsl-bash should fail if one of the commands fails (provocation) - id: set_e_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - false - : - continue-on-error: true - - - &test_wsl-bash_should_fail_if_one_of_the_commands_fails_verification - name: Test - wsl-bash should fail if one of the commands fails (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - # do not just rely on false here, but explicitly use exit - # in case failing commands do not make the script fail - run: | - [ '${{ steps.set_e_provocation.outcome }}' == 'failure' ] || exit 1 - - - &test_wsl-bash_should_fail_if_an_undefined_variable_is_used_provocation - name: Test - wsl-bash should fail if an undefined variable is used (provocation) - id: set_u_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: $foo - continue-on-error: true - - - &test_wsl-bash_should_fail_if_an_undefined_variable_is_used_verification - name: Test - wsl-bash should fail if an undefined variable is used (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.set_u_provocation.outcome }}' == 'failure' ] - - - &test_wsl-bash_should_fail_if_any_command_in_a_pipe_fails_provocation - name: Test - wsl-bash should fail if any command in a pipe fails (provocation) - id: set_pipefail_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: false | true - continue-on-error: true - - - &test_wsl-bash_should_fail_if_any_command_in_a_pipe_fails_verification - name: Test - wsl-bash should fail if any command in a pipe fails (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.set_pipefail_provocation.outcome }}' == 'failure' ] - - - &test_the_default_distribution_should_be_correct - name: Test - the default distribution should be correct - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: > - cat - <(wsl.exe --list || true) - <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) - <(wslconfig.exe /list || true) - <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) - - [[ - "$(cat - <(wsl.exe --list || true) - <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) - <(wslconfig.exe /list || true) - <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))" - == - *${{ matrix.distribution.wsl-id }}\ \(Default\)* - ]] - - - &test_wsl-bash_should_use_the_correct_distribution - name: Test - wsl-bash should use the correct distribution - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distribution.match-pattern }} - ]] - - - &test_multi-line_commands_should_not_be_disturbed_by_CRLF_line_endings - name: Test - multi-line commands should not be disturbed by CRLF line endings - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - : # this comment catches the CR if present - ! grep -q $'\r' "$0" # this comment catches the CR if present - - - name: Test - wsl-bash should fail if no script file is given (provocation) - id: no_script_file_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash - run: | - : - continue-on-error: true - - - name: Test - wsl-bash should fail if no script file is given (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.no_script_file_provocation.outcome }}' == 'failure' ] - - - name: Test - wsl-bash should fail if more than one parameter is given and first is not -u (provocation) - id: wrong_first_parameter_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash user {0} - run: | - : - continue-on-error: true - - - name: Test - wsl-bash should fail if more than one parameter is given and first is not -u (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.wrong_first_parameter_provocation.outcome }}' == 'failure' ] - - - name: Test - wsl-bash should fail if only user is given (provocation) - id: only_user_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash -u {0} - run: | - : - continue-on-error: true - - - name: Test - wsl-bash should fail if only user is given (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.only_user_provocation.outcome }}' == 'failure' ] - - - name: Test - wsl-bash should fail if excess argument is given (provocation) - id: excess_argument_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash -u user {0} foo - run: | - : - continue-on-error: true - - - name: Test - wsl-bash should fail if excess argument is given (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.excess_argument_provocation.outcome }}' == 'failure' ] - - - name: Test - wsl-bash should fail if given script file does not exist (provocation) - id: script_file_does_not_exist_provocation - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash -u user {0}foo - run: | - : - continue-on-error: true - - - name: Test - wsl-bash should fail if given script file does not exist (verification) - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.script_file_does_not_exist_provocation.outcome }}' == 'failure' ] - - strategy: - fail-fast: false - matrix: - environment: *environments - distribution: - - &debian - wsl-id: Debian - user-id: Debian - match-pattern: '*Debian*' - default-absent-tool: dos2unix - - test: - name: Test "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - id: execute_action1 - with: - distribution: ${{ matrix.distribution.user-id }} - use-cache: false - - - <<: *test_wsl-bash_should_be_available_as_custom_shell - name: Test - wsl-bash should fail if bash is not present by default (provocation) - id: no_default_bash_provocation - if: matrix.distribution.user-id == 'Alpine' - continue-on-error: true - - - name: Test - wsl-bash should fail if bash is not present by default (verification) - if: always() - && (matrix.distribution.user-id == 'Alpine') - && (steps.execute_action1.outcome == 'success') - run: | - wsl sh -euc "[ '${{ steps.no_default_bash_provocation.outcome }}' = 'failure' ]" - - - name: Delete wsl-bash - if: always() - && (matrix.distribution.user-id == 'Alpine') - && (steps.execute_action1.outcome == 'success') - shell: cmd - run: DEL /F "${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}" - - - <<: *execute_action - name: Install Bash on Alpine - if: always() - && (matrix.distribution.user-id == 'Alpine') - && (steps.execute_action1.outcome == 'success') - id: execute_action2 - with: - distribution: ${{ matrix.distribution.user-id }} - additional-packages: bash - - - <<: *test_wsl-bash_should_be_available_as_custom_shell - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_the_script_fails_provocation - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_the_script_fails_verification - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_one_of_the_commands_fails_provocation - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_one_of_the_commands_fails_verification - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_an_undefined_variable_is_used_provocation - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_an_undefined_variable_is_used_verification - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_any_command_in_a_pipe_fails_provocation - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_fail_if_any_command_in_a_pipe_fails_verification - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_the_default_distribution_should_be_correct - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_wsl-bash_should_use_the_correct_distribution - if: always() - && (steps.execute_action1.outcome == 'success') - - - <<: *test_multi-line_commands_should_not_be_disturbed_by_CRLF_line_endings - if: always() - && (steps.execute_action1.outcome == 'success') - - - name: Test - ${{ matrix.distribution.default-absent-tool }} should not be installed by default (provocation) - id: default_absent_tool_absent_provocation - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: ${{ matrix.distribution.default-absent-tool }} --version - continue-on-error: true - - - name: Test - ${{ matrix.distribution.default-absent-tool }} should not be installed by default (verification) - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.default_absent_tool_absent_provocation.outcome }}' == 'failure' ] - - - name: Test - bash should be installed by default - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: bash -c true - - - name: Test - sh should be installed by default - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: sh -c true - - - name: Test - wsl-sh should not be present (provocation) - id: wsl-sh_absent_provocation - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-sh {0} - run: | - : - continue-on-error: true - - - name: Test - wsl-sh should not be present (verification) - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: | - [ '${{ steps.wsl-sh_absent_provocation.outcome }}' == 'failure' ] - - - <<: *execute_action - name: Add wsl-sh wrapper - id: execute_action3 - with: - distribution: ${{ matrix.distribution.user-id }} - wsl-shell-command: sh -eu - - - name: Test - wsl-sh should be present - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-sh {0} - run: | - : - - - name: Test - wsl-bash should use bash - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-bash {0} - run: | - ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' - [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" == 'bash' ] - - - name: Test - wsl-sh should use sh - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-sh {0} - run: | - ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' - [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" = 'sh' ] - - - name: Delete wsl-bash - if: always() - && (steps.execute_action3.outcome == 'success') - shell: cmd - run: DEL /F "${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}" - - - name: Test - wsl-bash should not be present (provocation) - id: wsl-bash_absent_provocation - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-bash {0} - run: | - : - continue-on-error: true - - - name: Test - wsl-bash should not be present (verification) - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-sh {0} - run: | - [ '${{ steps.wsl-bash_absent_provocation.outcome }}' = 'failure' ] - - - <<: *execute_action - name: Re-add wsl-bash wrapper - id: execute_action4 - with: - distribution: ${{ matrix.distribution.user-id }} - - - name: Test - wsl-bash should be present - if: always() - && (steps.execute_action4.outcome == 'success') - shell: wsl-bash {0} - run: | - : - - - name: Test - wsl-bash should use bash - if: always() - && (steps.execute_action4.outcome == 'success') - shell: wsl-bash {0} - run: | - ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' - [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" == 'bash' ] - - - name: Test - wsl-bash should use root as default user - if: always() - && (steps.execute_action4.outcome == 'success') - shell: wsl-bash {0} - run: | - whoami - [ "$(whoami)" == 'root' ] - - - name: Add user test - shell: wsl-bash {0} - run: | - useradd -m -p 4qBD5NWD3IkbU test - - - <<: *execute_action - name: Set wsl-bash wrapper to use user test by default - id: execute_action5 - with: - distribution: ${{ matrix.distribution.user-id }} - additional-packages: sudo - wsl-shell-command: bash -c "sudo -u test bash --noprofile --norc -euo pipefail "\ - - - name: Test - wsl-bash should use test as default user - if: always() - && (steps.execute_action5.outcome == 'success') - shell: wsl-bash {0} - run: | - whoami - [ "$(whoami)" == 'test' ] - - - <<: *execute_action - name: Set wsl-bash wrapper to use user test by default with inline script usage - id: execute_action6 - with: - distribution: ${{ matrix.distribution.user-id }} - wsl-shell-command: bash -c "sudo -u test bash --noprofile --norc -euo pipefail '{0}'" - - - name: Test - wsl-bash should use test as default user with inline script usage - if: always() - && (steps.execute_action6.outcome == 'success') - shell: wsl-bash {0} - run: | - whoami - [ "$(whoami)" == 'test' ] - - - name: Delete wsl-bash - shell: cmd - run: DEL /F "${{ steps.execute_action6.outputs.wsl-shell-wrapper-path }}" - - - <<: *execute_action - name: Set wsl-bash wrapper to use default user by default - id: execute_action7 - with: - distribution: ${{ matrix.distribution.user-id }} - - - name: Test - wsl-bash should use root as default user - if: always() - && (steps.execute_action7.outcome == 'success') - shell: wsl-bash {0} - run: | - whoami - [ "$(whoami)" == 'root' ] - - - name: Test - test user does already exist - if: always() - && (steps.execute_action7.outcome == 'success') - shell: wsl-bash {0} - run: | - id -u test - - - name: Delete wsl-bash - shell: cmd - run: DEL /F "${{ steps.execute_action7.outputs.wsl-shell-wrapper-path }}" - - - <<: *execute_action - name: Set wsl-bash wrapper to use existing user test by default with extra parameter - id: execute_action8 - with: - distribution: ${{ matrix.distribution.user-id }} - wsl-shell-user: test - - - name: Test - wsl-bash should use existing user test as default user with extra parameter - if: always() - && (steps.execute_action8.outcome == 'success') - shell: wsl-bash {0} - run: | - whoami - [ "$(whoami)" == 'test' ] - - - name: Test - test2 user does not exist - if: always() - && (steps.execute_action8.outcome == 'success') - shell: wsl-bash {0} - run: | - ! id -u test2 - - - name: Delete wsl-bash - shell: cmd - run: DEL /F "${{ steps.execute_action8.outputs.wsl-shell-wrapper-path }}" - - - <<: *execute_action - name: Set wsl-bash wrapper to use non-existing user test2 by default with extra parameter - id: execute_action9 - with: - distribution: ${{ matrix.distribution.user-id }} - wsl-shell-user: test2 - - - name: Test - wsl-bash should use auto-generated user test2 as default user - if: always() - && (steps.execute_action9.outcome == 'success') - shell: wsl-bash {0} - run: | - whoami - [ "$(whoami)" == 'test2' ] - - - name: Test - wsl-bash should use ad-hoc user test - if: always() - && (steps.execute_action9.outcome == 'success') - shell: wsl-bash -u test {0} - run: | - whoami - [ "$(whoami)" == 'test' ] - - - name: Test - wsl-bash should use ad-hoc user root - if: always() - && (steps.execute_action9.outcome == 'success') - shell: wsl-bash -u root {0} - run: | - whoami - [ "$(whoami)" == 'root' ] - - - <<: *execute_action - name: Make a no-op execution of the action - id: execute_action10 - with: - distribution: ${{ matrix.distribution.user-id }} - - - name: Test - wsl-bash should still use test2 as default user - if: always() - && (steps.execute_action10.outcome == 'success') - shell: wsl-bash {0} - run: | - whoami - [ "$(whoami)" == 'test2' ] - - strategy: &distributions_matrix - fail-fast: false - matrix: - environment: *environments - distribution: &distributions - - *debian - - &alpine - wsl-id: Alpine - user-id: Alpine - match-pattern: '*Alpine*' - default-absent-tool: dos2unix - - &kali - wsl-id: kali-linux - user-id: kali-linux - match-pattern: '*Kali*' - default-absent-tool: dos2unix - - &open_suse_leap_15_2 - wsl-id: openSUSE-Leap-15.2 - user-id: openSUSE-Leap-15.2 - match-pattern: '*openSUSE*Leap*15.2*' - default-absent-tool: which - - &ubuntu_22_04 - wsl-id: Ubuntu - user-id: Ubuntu-22.04 - match-pattern: '*Ubuntu*22.04*' - default-absent-tool: dos2unix - - &ubuntu_20_04 - wsl-id: Ubuntu - user-id: Ubuntu-20.04 - match-pattern: '*Ubuntu*20.04*' - default-absent-tool: dos2unix - - &ubuntu_18_04 - wsl-id: Ubuntu-18.04 - user-id: Ubuntu-18.04 - match-pattern: '*Ubuntu*18.04*' - default-absent-tool: dos2unix - - &ubuntu_16_04 - wsl-id: Ubuntu-16.04 - user-id: Ubuntu-16.04 - match-pattern: '*Ubuntu*16.04*' - default-absent-tool: dos2unix - - test_wsl-conf_on_initial_execution: - name: Test /etc/wsl.conf handling on initial execution for "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - id: execute_action1 - with: - distribution: ${{ matrix.distribution.user-id }} - wsl-conf: | - [automount] - options = uid=1000 - - - name: Delete wsl-bash - if: always() - && (matrix.distribution.user-id == 'Alpine') - && (steps.execute_action1.outcome == 'success') - shell: cmd - run: DEL /F "${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}" - - - <<: *execute_action - name: Install Bash on Alpine - if: always() - && (matrix.distribution.user-id == 'Alpine') - && (steps.execute_action1.outcome == 'success') - id: execute_action2 - with: - distribution: ${{ matrix.distribution.user-id }} - additional-packages: bash - - - name: Test - /etc/wsl.conf should exist - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: | - [ -f /etc/wsl.conf ] - cat /etc/wsl.conf - - - name: Test - /mnt/c should be mounted with uid 1000 - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: | - ls -alh /mnt - [[ "$(stat -c %u /mnt/c)" == 1000 ]] - - strategy: *distributions_matrix - - test_wsl-conf_on_subsequent_execution: - name: Test /etc/wsl.conf handling on subsequent execution for "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - id: execute_action1 - with: - distribution: ${{ matrix.distribution.user-id }} - - - name: Delete wsl-bash - if: always() - && (matrix.distribution.user-id == 'Alpine') - && (steps.execute_action1.outcome == 'success') - shell: cmd - run: DEL /F "${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}" - - - <<: *execute_action - name: Install Bash on Alpine - if: always() - && (matrix.distribution.user-id == 'Alpine') - && (steps.execute_action1.outcome == 'success') - id: execute_action2 - with: - distribution: ${{ matrix.distribution.user-id }} - additional-packages: bash - - - name: Test - /etc/wsl.conf should not exist - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: | - [ ! -f /etc/wsl.conf ] - - - name: | - Test - C: should be mounted at /mnt/c - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: | - mount - mount | grep 'C:.* on /mnt/c' - - - name: Test - /mnt/c should be mounted with uid 0 - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash {0} - run: | - ls -alh /mnt - [[ "$(stat -c %u /mnt/c)" == 0 ]] - - - <<: *execute_action - id: execute_action3 - if: always() - && (steps.execute_action1.outcome == 'success') - with: - distribution: ${{ matrix.distribution.user-id }} - wsl-conf: | - [automount] - root = / - - - name: Test - /etc/wsl.conf should exist - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-bash {0} - run: | - [ -f /etc/wsl.conf ] - cat /etc/wsl.conf - - - name: | - Test - C: should be mounted at /c - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-bash {0} - run: | - mount - mount | grep 'C:.* on /c' - - strategy: *distributions_matrix - - test_additional_packages: - name: Test additional packages for "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - with: - distribution: ${{ matrix.distribution.user-id }} - additional-packages: > - ${{ matrix.distribution.default-absent-tool }} - bash - - - name: Test - ${{ matrix.distribution.default-absent-tool }} should be installed - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: ${{ matrix.distribution.default-absent-tool }} --version - - - name: Test - bash should be installed - if: always() - && (steps.execute_action.outcome == 'success') - shell: wsl-bash {0} - run: bash -c true - strategy: *distributions_matrix - - test_multiple_usage_with_different_distributions: - name: Test multiple usage with different distributions - ("${{ matrix.distributions.distribution1.user-id }}" - / "${{ matrix.distributions.distribution2.user-id }}" - / "${{ matrix.distributions.distribution3.user-id }}") - on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution1.user-id }} - id: execute_action1 - with: - distribution: ${{ matrix.distributions.distribution1.user-id }} - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution2.user-id }} - id: execute_action2 - with: - distribution: ${{ matrix.distributions.distribution2.user-id }} - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution3.user-id }} - id: execute_action3 - with: - distribution: ${{ matrix.distributions.distribution3.user-id }} - set-as-default: 'false' - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution1.user-id }} again - id: execute_action4 - with: - distribution: ${{ matrix.distributions.distribution1.user-id }} - - - name: Test - the default distribution should be the last installed distribution with set-as-default true - if: always() - && (steps.execute_action4.outcome == 'success') - shell: wsl-bash {0} - run: > - cat - <(wsl.exe --list || true) - <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) - <(wslconfig.exe /list || true) - <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) - - [[ - "$(cat - <(wsl.exe --list || true) - <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) - <(wslconfig.exe /list || true) - <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))" - == - *${{ matrix.distributions.distribution2.wsl-id }}\ \(Default\)* - ]] - - - name: Test - wsl-bash should use the last installed distribution with set-as-default true - if: always() - && (steps.execute_action4.outcome == 'success') - shell: wsl-bash {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution2.match-pattern }} - ]] - - strategy: - fail-fast: false - matrix: - environment: *environments - distributions: - - distribution1: *debian - distribution2: *ubuntu_20_04 - distribution3: *ubuntu_18_04 - - - distribution1: *debian - distribution2: *ubuntu_18_04 - distribution3: *ubuntu_20_04 - - - distribution1: *ubuntu_20_04 - distribution2: *debian - distribution3: *ubuntu_18_04 - - - distribution1: *ubuntu_20_04 - distribution2: *ubuntu_18_04 - distribution3: *debian - - - distribution1: *ubuntu_18_04 - distribution2: *debian - distribution3: *ubuntu_20_04 - - - distribution1: *ubuntu_18_04 - distribution2: *ubuntu_20_04 - distribution3: *debian - - test_multiple_usage_with_same_distribution: - name: Test multiple usage with "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - id: execute_action1 - with: - distribution: ${{ matrix.distribution.user-id }} - additional-packages: bash - - - <<: *execute_action - name: Update distribution - # work-around for https://bugs.kali.org/view.php?id=6672 - if: matrix.distribution.user-id != 'kali-linux' - id: execute_action2 - with: - distribution: ${{ matrix.distribution.user-id }} - update: 'true' - - - <<: *execute_action - name: Install default absent tool - id: execute_action3 - with: - distribution: ${{ matrix.distribution.user-id }} - additional-packages: ${{ matrix.distribution.default-absent-tool }} - - - name: Test - ${{ matrix.distribution.default-absent-tool }} should be installed - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-bash {0} - run: ${{ matrix.distribution.default-absent-tool }} --version - - - <<: *execute_action - name: Execute action for ${{ matrix.distribution2.user-id }} - id: execute_action4 - with: - distribution: ${{ matrix.distribution2.user-id }} - - - name: Test - "${{ matrix.distribution2.user-id }}" should be the default distribution after installation - if: always() - && (steps.execute_action4.outcome == 'success') - shell: wsl-bash {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distribution2.match-pattern }} - ]] - - - <<: *execute_action - name: Re-execute action - id: execute_action5 - with: - distribution: ${{ matrix.distribution.user-id }} - - - name: Test - "${{ matrix.distribution2.user-id }}" should still be the default distribution after re-running for "${{ matrix.distribution.user-id }}" - if: always() - && (steps.execute_action5.outcome == 'success') - shell: wsl-bash {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distribution2.match-pattern }} - ]] - - - <<: *execute_action - name: Set as default - id: execute_action6 - with: - distribution: ${{ matrix.distribution.user-id }} - set-as-default: 'true' - - - name: Test - "${{ matrix.distribution.user-id }}" should be the default distribution after re-running with set-as-default true - if: always() - && (steps.execute_action6.outcome == 'success') - shell: wsl-bash {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distribution.match-pattern }} - ]] - - strategy: - <<: *distributions_matrix - matrix: - environment: *environments - distribution: *distributions - distribution2: - - *debian - exclude: - - environment: windows-2019 - distribution: *debian - distribution2: *debian - - environment: windows-2022 - distribution: *debian - distribution2: *debian - - environment: windows-latest - distribution: *debian - distribution2: *debian - include: - - environment: windows-2019 - distribution: *debian - distribution2: *ubuntu_20_04 - - environment: windows-2022 - distribution: *debian - distribution2: *ubuntu_20_04 - - environment: windows-latest - distribution: *debian - distribution2: *ubuntu_20_04 - - test_distribution_specific_wsl_bash_scripts: - name: Test distribution specific wsl-bash scripts on ${{ matrix.environment }} - needs: build - runs-on: ${{ matrix.environment }} - steps: - - name: Restore built artifacts from cache - <<: *built_artifacts_cache - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution1.user-id }} - id: execute_action1 - with: - distribution: ${{ matrix.distributions.distribution1.user-id }} - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution2.user-id }} - id: execute_action2 - with: - distribution: ${{ matrix.distributions.distribution2.user-id }} - additional-packages: bash - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution3.user-id }} - id: execute_action3 - with: - distribution: ${{ matrix.distributions.distribution3.user-id }} - set-as-default: 'false' - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution4.user-id }} - id: execute_action4 - with: - distribution: ${{ matrix.distributions.distribution4.user-id }} - set-as-default: 'false' - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution5.user-id }} - id: execute_action5 - with: - distribution: ${{ matrix.distributions.distribution5.user-id }} - set-as-default: 'false' - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution6.user-id }} - id: execute_action6 - with: - distribution: ${{ matrix.distributions.distribution6.user-id }} - set-as-default: 'false' - - - <<: *execute_action - name: Execute action for ${{ matrix.distributions.distribution7.user-id }} - id: execute_action7 - with: - distribution: ${{ matrix.distributions.distribution7.user-id }} - set-as-default: 'false' - - - name: Test - wsl-bash_${{ matrix.distributions.distribution1.user-id }} should use the correct distribution - if: always() - && (steps.execute_action1.outcome == 'success') - shell: wsl-bash_Debian {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution1.match-pattern }} - ]] - - - name: Test - wsl-bash_${{ matrix.distributions.distribution2.user-id }} should use the correct distribution - if: always() - && (steps.execute_action2.outcome == 'success') - shell: wsl-bash_Alpine {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution2.match-pattern }} - ]] - - - name: Test - wsl-bash_${{ matrix.distributions.distribution3.user-id }} should use the correct distribution - if: always() - && (steps.execute_action3.outcome == 'success') - shell: wsl-bash_kali-linux {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution3.match-pattern }} - ]] - - - name: Test - wsl-bash_${{ matrix.distributions.distribution4.user-id }} should use the correct distribution - if: always() - && (steps.execute_action4.outcome == 'success') - shell: wsl-bash_openSUSE-Leap-15.2 {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution4.match-pattern }} - ]] - - - name: Test - wsl-bash_${{ matrix.distributions.distribution5.user-id }} should use the correct distribution - if: always() - && (steps.execute_action5.outcome == 'success') - && (matrix.distributions.distribution5.user-id == 'Ubuntu-22.04') - shell: wsl-bash_Ubuntu-22.04 {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution5.match-pattern }} - ]] - - - name: Test - wsl-bash_${{ matrix.distributions.distribution5.user-id }} should use the correct distribution - if: always() - && (steps.execute_action5.outcome == 'success') - && (matrix.distributions.distribution5.user-id == 'Ubuntu-20.04') - shell: wsl-bash_Ubuntu-20.04 {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution5.match-pattern }} - ]] - - - name: Test - wsl-bash_${{ matrix.distributions.distribution6.user-id }} should use the correct distribution - if: always() - && (steps.execute_action6.outcome == 'success') - shell: wsl-bash_Ubuntu-18.04 {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution6.match-pattern }} - ]] - - - name: Test - wsl-bash_${{ matrix.distributions.distribution7.user-id }} should use the correct distribution - if: always() - && (steps.execute_action7.outcome == 'success') - shell: wsl-bash_Ubuntu-16.04 {0} - run: > - cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true) - - [[ - "$(cat - <(lsb_release -a || true) - <(uname -a || true) - <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) - <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) - <([ -f /proc/version ] && cat /proc/version || true))" - == - ${{ matrix.distributions.distribution7.match-pattern }} - ]] - - strategy: - fail-fast: false - matrix: - environment: *environments - distributions: - - distribution1: *debian - distribution2: *alpine - distribution3: *kali - distribution4: *open_suse_leap_15_2 - distribution5: *ubuntu_20_04 - distribution6: *ubuntu_18_04 - distribution7: *ubuntu_16_04 - - distribution1: *debian - distribution2: *alpine - distribution3: *kali - distribution4: *open_suse_leap_15_2 - distribution5: *ubuntu_22_04 - distribution6: *ubuntu_18_04 - distribution7: *ubuntu_16_04 diff --git a/.github/workflows/test.main.kts b/.github/workflows/test.main.kts new file mode 100755 index 00000000..74416bda --- /dev/null +++ b/.github/workflows/test.main.kts @@ -0,0 +1,1137 @@ +#!/usr/bin/env kotlin + +/* + * Copyright 2020-2023 Björn Kautler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:DependsOn("it.krzeminski:github-actions-kotlin-dsl:0.35.0") + +import it.krzeminski.githubactions.actions.CustomAction +import it.krzeminski.githubactions.actions.actions.CacheV2 +import it.krzeminski.githubactions.actions.actions.CheckoutV2 +import it.krzeminski.githubactions.actions.vampire.SetupWslV1 +import it.krzeminski.githubactions.actions.vampire.SetupWslV1.Distribution +import it.krzeminski.githubactions.domain.CommandStep +import it.krzeminski.githubactions.domain.ExternalActionStepWithOutputs +import it.krzeminski.githubactions.domain.RunnerType +import it.krzeminski.githubactions.domain.RunnerType.WindowsLatest +import it.krzeminski.githubactions.domain.Shell +import it.krzeminski.githubactions.domain.Shell.Cmd +import it.krzeminski.githubactions.domain.Step +import it.krzeminski.githubactions.domain.triggers.Cron +import it.krzeminski.githubactions.domain.triggers.PullRequest +import it.krzeminski.githubactions.domain.triggers.Push +import it.krzeminski.githubactions.domain.triggers.Schedule +import it.krzeminski.githubactions.dsl.JobBuilder +import it.krzeminski.githubactions.dsl.expressions.expr +import it.krzeminski.githubactions.dsl.workflow +import it.krzeminski.githubactions.yaml.writeToFile + +val environments = listOf( + "windows-2019", + "windows-2022", + "windows-latest" +) + +val debian = mapOf( + "wsl-id" to "Debian", + "user-id" to "Debian", + "match-pattern" to "*Debian*", + "default-absent-tool" to "dos2unix" +) + +val alpine = mapOf( + "wsl-id" to "Alpine", + "user-id" to "Alpine", + "match-pattern" to "*Alpine*", + "default-absent-tool" to "dos2unix" +) + +val kali = mapOf( + "wsl-id" to "kali-linux", + "user-id" to "kali-linux", + "match-pattern" to "*Kali*", + "default-absent-tool" to "dos2unix" +) + +val openSuseLeap15_2 = mapOf( + "wsl-id" to "openSUSE-Leap-15.2", + "user-id" to "openSUSE-Leap-15.2", + "match-pattern" to "*openSUSE*Leap*15.2*", + "default-absent-tool" to "which" +) + +val ubuntu2204 = mapOf( + "wsl-id" to "Ubuntu", + "user-id" to "Ubuntu-22.04", + "match-pattern" to "*Ubuntu*22.04*", + "default-absent-tool" to "dos2unix" +) + +val ubuntu2004 = mapOf( + "wsl-id" to "Ubuntu", + "user-id" to "Ubuntu-20.04", + "match-pattern" to "*Ubuntu*20.04*", + "default-absent-tool" to "dos2unix" +) + +val ubuntu1804 = mapOf( + "wsl-id" to "Ubuntu-18.04", + "user-id" to "Ubuntu-18.04", + "match-pattern" to "*Ubuntu*18.04*", + "default-absent-tool" to "dos2unix" +) + +val ubuntu1604 = mapOf( + "wsl-id" to "Ubuntu-16.04", + "user-id" to "Ubuntu-16.04", + "match-pattern" to "*Ubuntu*16.04*", + "default-absent-tool" to "dos2unix" +) + +val distributions = listOf( + debian, + alpine, + kali, + openSuseLeap15_2, + ubuntu2204, + ubuntu2004, + ubuntu1804, + ubuntu1604 +) + +val wslBash = Shell.Custom("wsl-bash {0}") + +val wslSh = Shell.Custom("wsl-sh {0}") + +lateinit var executeActionStep: ExternalActionStepWithOutputs + +workflow( + name = "Build and Test", + on = listOf( + Push(), + PullRequest(), + Schedule(listOf(Cron(minute = "0", hour = "0"))) + ), + sourceFile = __FILE__.toPath() +) { + val builtArtifactsCache = CacheV2( + path = listOf( + "action.yml", + "build/distributions/" + ), + key = expr { github.run_id } + ) + + val executeAction = SetupWslV1( + distribution = Distribution.Custom(expr("matrix.distribution.user-id")) + ) + + val build = job( + id = "build", + name = "Build", + runsOn = WindowsLatest + ) { + run( + name = "Configure Git", + command = "git config --global core.autocrlf input" + ) + uses( + name = "Checkout", + action = CheckoutV2() + ) + uses( + name = "Build", + action = CustomAction( + actionOwner = "burrunan", + actionName = "gradle-cache-action", + actionVersion = "v1", + inputs = mapOf( + "arguments" to "build --info --stacktrace --scan", + "debug" to "false", + "concurrent" to "true", + "gradle-dependencies-cache-key" to "buildSrc/**/Versions.kt" + ) + ) + ) + uses( + name = "Save built artifacts to cache", + action = builtArtifactsCache + ) + } + + job( + id = "test_invalid_distribution", + name = """Test "${expr("matrix.distribution.label")}" distribution on ${expr("matrix.environment")}""", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distribution" to listOf( + mapOf( + "id" to "invalid", + "label" to "invalid" + ), + mapOf( + "id" to "", + "label" to "" + ), + mapOf( + "id" to null, + "label" to "null" + ) + ) + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + executeActionStep = usesSelf( + action = executeAction, + continueOnError = true + ) + run( + name = "Test - action should fail if an invalid distribution is given", + shell = Cmd, + command = "if '${expr(executeActionStep.outcome)}' NEQ 'failure' exit 1" + ) + } + + job( + id = "test_default_distribution", + name = "Test default distribution on ${expr("matrix.environment")}", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distribution" to listOf(debian) + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + executeActionStep = usesSelf( + action = SetupWslV1( + update = true + ) + ) + commonTests() + verifyFailure( + name = "Test - wsl-bash should fail if no script file is given", + provocationShell = Shell.Custom("wsl-bash") + ) + verifyFailure( + name = "Test - wsl-bash should fail if more than one parameter is given and first is not -u", + provocationShell = Shell.Custom("wsl-bash user {0}") + ) + verifyFailure( + name = "Test - wsl-bash should fail if only user is given", + provocationShell = Shell.Custom("wsl-bash -u {0}") + ) + verifyFailure( + name = "Test - wsl-bash should fail if excess argument is given", + provocationShell = Shell.Custom("wsl-bash -u user {0} foo") + ) + verifyFailure( + name = "Test - wsl-bash should fail if given script file does not exist", + provocationShell = Shell.Custom("wsl-bash -u user {0}foo") + ) + } + + job( + id = "test", + name = """Test "${expr("matrix.distribution.user-id")}" distribution on ${expr("matrix.environment")}""", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distribution" to distributions + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + executeActionStep = usesSelf( + action = executeAction.copy( + useCache = false + ) + ) + verifyFailure( + name = "Test - wsl-bash should fail if bash is not present by default", + conditionTransformer = { executeActionStep.successOnAlpineCondition }, + verificationShell = null, + verificationTransformer = { _, command -> + """wsl sh -euc "${command.replace("==", "=")}"""" + } + ) + deleteWslBashOnAlpine() + usesSelf( + name = "Install Bash on Alpine", + action = executeAction.copy( + additionalPackages = listOf("bash") + ), + condition = executeActionStep.successOnAlpineCondition + ) + commonTests() + verifyFailure( + name = "Test - ${expr("matrix.distribution.default-absent-tool")} should not be installed by default", + provocationCommand = "${expr("matrix.distribution.default-absent-tool")} --version" + ) + runAfterSuccess( + name = "Test - bash should be installed by default", + command = "bash -c true" + ) + runAfterSuccess( + name = "Test - sh should be installed by default", + command = "sh -c true" + ) + verifyFailure( + name = "Test - wsl-sh should not be present", + provocationShell = wslSh + ) + val wslBashPath = executeActionStep.outputs.wslShellWrapperPath + executeActionStep = usesSelfAfterSuccess( + name = "Add wsl-sh wrapper", + action = executeAction.copy( + wslShellCommand = "sh -eu" + ) + ) + runAfterSuccess( + name = "Test - wsl-sh should be present", + shell = wslSh + ) + runAfterSuccess( + name = "Test - wsl-bash should use bash", + command = """ + ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' + [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" == 'bash' ] + """ + ) + runAfterSuccess( + name = "Test - wsl-sh should use sh", + shell = wslSh, + command = """ + ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' + [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" = 'sh' ] + """ + ) + deleteWslBash( + wslBashPathExpression = wslBashPath + ) + verifyFailure( + name = "Test - wsl-bash should not be present", + verificationShell = wslSh, + verificationTransformer = { _, command -> + command.replace("==", "=") + } + ) + executeActionStep = usesSelfAfterSuccess( + name = "Re-add wsl-bash wrapper", + action = executeAction + ) + runAfterSuccess( + name = "Test - wsl-bash should be present" + ) + runAfterSuccess( + name = "Test - wsl-bash should use bash", + command = """ + ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' + [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" == 'bash' ] + """ + ) + verifyCommandResult( + name = "Test - wsl-bash should use root as default user", + actualCommand = "whoami", + expected = "root" + ) + runAfterSuccess( + name = "Add user test", + command = "useradd -m -p 4qBD5NWD3IkbU test" + ) + executeActionStep = usesSelfAfterSuccess( + name = "Set wsl-bash wrapper to use user test by default", + action = executeAction.copy( + additionalPackages = listOf("sudo"), + wslShellCommand = """bash -c "sudo -u test bash --noprofile --norc -euo pipefail "\""" + ) + ) + verifyCommandResult( + name = "Test - wsl-bash should use test as default user", + actualCommand = "whoami", + expected = "test" + ) + executeActionStep = usesSelfAfterSuccess( + name = "Set wsl-bash wrapper to use user test by default with inline script usage", + action = executeAction.copy( + wslShellCommand = """bash -c "sudo -u test bash --noprofile --norc -euo pipefail '{0}'"""" + ) + ) + verifyCommandResult( + name = "Test - wsl-bash should use test as default user with inline script usage", + actualCommand = "whoami", + expected = "test" + ) + deleteWslBash() + executeActionStep = usesSelfAfterSuccess( + name = "Set wsl-bash wrapper to use default user by default", + action = executeAction + ) + verifyCommandResult( + name = "Test - wsl-bash should use root as default user", + actualCommand = "whoami", + expected = "root" + ) + runAfterSuccess( + name = "Test - test user does already exist", + command = "id -u test" + ) + deleteWslBash() + executeActionStep = usesSelfAfterSuccess( + name = "Set wsl-bash wrapper to use existing user test by default with extra parameter", + action = executeAction.copy( + wslShellUser = "test" + ) + ) + verifyCommandResult( + name = "Test - wsl-bash should use existing user test as default user with extra parameter", + actualCommand = "whoami", + expected = "test" + ) + runAfterSuccess( + name = "Test - test2 user does not exist", + command = "! id -u test2" + ) + deleteWslBash() + executeActionStep = usesSelfAfterSuccess( + name = "Set wsl-bash wrapper to use non-existing user test2 by default with extra parameter", + action = executeAction.copy( + wslShellUser = "test2" + ) + ) + verifyCommandResult( + name = "Test - wsl-bash should use auto-generated user test2 as default user", + actualCommand = "whoami", + expected = "test2" + ) + verifyCommandResult( + name = "Test - wsl-bash should use ad-hoc user test", + actualCommand = "whoami", + shell = Shell.Custom("wsl-bash -u test {0}"), + expected = "test" + ) + verifyCommandResult( + name = "Test - wsl-bash should use ad-hoc user root", + actualCommand = "whoami", + shell = Shell.Custom("wsl-bash -u root {0}"), + expected = "root" + ) + executeActionStep = usesSelfAfterSuccess( + name = "Make a no-op execution of the action", + action = executeAction + ) + verifyCommandResult( + name = "Test - wsl-bash should still use test2 as default user", + actualCommand = "whoami", + expected = "test2" + ) + } + + job( + id = "test_wsl-conf_on_initial_execution", + name = """Test /etc/wsl.conf handling on initial execution for "${expr("matrix.distribution.user-id")}" distribution on ${expr("matrix.environment")}""", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distribution" to distributions + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + executeActionStep = usesSelf( + action = executeAction.copy( + wslConf = """ + [automount] + options = uid=1000 + """.trimIndent() + ) + ) + deleteWslBashOnAlpine() + usesSelf( + name = "Install Bash on Alpine", + action = executeAction.copy( + additionalPackages = listOf("bash") + ), + condition = executeActionStep.successOnAlpineCondition + ) + runAfterSuccess( + name = "Test - /etc/wsl.conf should exist", + command = """ + [ -f /etc/wsl.conf ] + cat /etc/wsl.conf + """ + ) + runAfterSuccess( + name = "Test - /mnt/c should be mounted with uid 1000", + command = """ + ls -alh /mnt + [[ "$(stat -c %u /mnt/c)" == 1000 ]] + """ + ) + } + + job( + id = "test_wsl-conf_on_subsequent_execution", + name = """Test /etc/wsl.conf handling on subsequent execution for "${expr("matrix.distribution.user-id")}" distribution on ${expr("matrix.environment")}""", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distribution" to distributions + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + executeActionStep = usesSelf( + action = executeAction + ) + deleteWslBashOnAlpine() + usesSelf( + name = "Install Bash on Alpine", + action = executeAction.copy( + additionalPackages = listOf("bash") + ), + condition = executeActionStep.successOnAlpineCondition + ) + runAfterSuccess( + name = "Test - /etc/wsl.conf should not exist", + command = "[ ! -f /etc/wsl.conf ]" + ) + runAfterSuccess( + name = "Test - C: should be mounted at /mnt/c", + command = """ + mount + mount | grep 'C:.* on /mnt/c' + """ + ) + runAfterSuccess( + name = "Test - /mnt/c should be mounted with uid 0", + command = """ + ls -alh /mnt + [[ "$(stat -c %u /mnt/c)" == 0 ]] + """ + ) + executeActionStep = usesSelfAfterSuccess( + action = executeAction.copy( + wslConf = """ + [automount] + root = / + """.trimIndent() + ) + ) + runAfterSuccess( + name = "Test - /etc/wsl.conf should exist", + command = """ + [ -f /etc/wsl.conf ] + cat /etc/wsl.conf + """ + ) + runAfterSuccess( + name = "Test - C: should be mounted at /c", + command = """ + mount + mount | grep 'C:.* on /c' + """ + ) + } + + job( + id = "test_additional_packages", + name = """Test additional packages for "${expr("matrix.distribution.user-id")}" distribution on ${expr("matrix.environment")}""", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distribution" to distributions + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + executeActionStep = usesSelf( + action = executeAction.copy( + additionalPackages = listOf( + expr("matrix.distribution.default-absent-tool"), + "bash" + ) + ) + ) + runAfterSuccess( + name = "Test - ${expr("matrix.distribution.default-absent-tool")} should be installed", + command = "${expr("matrix.distribution.default-absent-tool")} --version" + ) + runAfterSuccess( + name = "Test - bash should be installed", + command = "bash -c true" + ) + } + + job( + id = "test_multiple_usage_with_different_distributions", + name = """ + Test multiple usage with different distributions + ("${expr("matrix.distributions.distribution1.user-id")}" + / "${expr("matrix.distributions.distribution2.user-id")}" + / "${expr("matrix.distributions.distribution3.user-id")}") + on ${expr("matrix.environment")} + """.trimIndent().replace("\n", " "), + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distributions" to listOf( + mapOf( + "distribution1" to debian, + "distribution2" to ubuntu2004, + "distribution3" to ubuntu1804 + ), + mapOf( + "distribution1" to debian, + "distribution2" to ubuntu1804, + "distribution3" to ubuntu2004 + ), + mapOf( + "distribution1" to ubuntu2004, + "distribution2" to debian, + "distribution3" to ubuntu1804 + ), + mapOf( + "distribution1" to ubuntu2004, + "distribution2" to ubuntu1804, + "distribution3" to debian + ), + mapOf( + "distribution1" to ubuntu1804, + "distribution2" to debian, + "distribution3" to ubuntu2004 + ), + mapOf( + "distribution1" to ubuntu1804, + "distribution2" to ubuntu2004, + "distribution3" to debian + ) + ) + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + usesSelf( + name = "Execute action for ${expr("matrix.distributions.distribution1.user-id")}", + action = SetupWslV1( + distribution = Distribution.Custom(expr("matrix.distributions.distribution1.user-id")) + ) + ) + usesSelf( + name = "Execute action for ${expr("matrix.distributions.distribution2.user-id")}", + action = SetupWslV1( + distribution = Distribution.Custom(expr("matrix.distributions.distribution2.user-id")) + ) + ) + usesSelf( + name = "Execute action for ${expr("matrix.distributions.distribution3.user-id")}", + action = SetupWslV1( + distribution = Distribution.Custom(expr("matrix.distributions.distribution3.user-id")), + setAsDefault = false + ) + ) + executeActionStep = usesSelf( + name = "Execute action for ${expr("matrix.distributions.distribution1.user-id")} again", + action = SetupWslV1( + distribution = Distribution.Custom(expr("matrix.distributions.distribution1.user-id")) + ) + ) + verifyCommandResult( + name = "Test - the default distribution should be the last installed distribution with set-as-default true", + actualCommand = """ + cat + <(wsl.exe --list || true) + <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) + <(wslconfig.exe /list || true) + <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) + """.trimIndent().replace("\n", " "), + expectedPattern = """*${expr("matrix.distributions.distribution2.wsl-id")}\ \(Default\)*""" + ) + verifyInstalledDistribution( + name = "Test - wsl-bash should use the last installed distribution with set-as-default true", + expectedPatternExpression = "matrix.distributions.distribution2.match-pattern" + ) + } + + job( + id = "test_multiple_usage_with_same_distribution", + name = """Test multiple usage with "${expr("matrix.distribution.user-id")}" distribution on ${expr("matrix.environment")}""", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + "distribution" to distributions, + "distribution2" to listOf(debian), + "exclude" to environments.map { + mapOf( + "environment" to it, + "distribution" to debian, + "distribution2" to debian + ) + }, + "include" to environments.map { + mapOf( + "environment" to it, + "distribution" to debian, + "distribution2" to ubuntu2004 + ) + } + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + usesSelf( + action = executeAction.copy( + additionalPackages = listOf("bash") + ) + ) + usesSelf( + name = "Update distribution", + action = executeAction.copy( + update = true + ), + // work-around for https://bugs.kali.org/view.php?id=6672 + condition = "matrix.distribution.user-id != 'kali-linux'" + ) + executeActionStep = usesSelf( + name = "Install default absent tool", + action = executeAction.copy( + additionalPackages = listOf(expr("matrix.distribution.default-absent-tool")) + ) + ) + runAfterSuccess( + name = "Test - ${expr("matrix.distribution.default-absent-tool")} should be installed", + command = "${expr("matrix.distribution.default-absent-tool")} --version" + ) + executeActionStep = usesSelfAfterSuccess( + name = "Execute action for ${expr("matrix.distribution2.user-id")}", + action = SetupWslV1( + distribution = Distribution.Custom(expr("matrix.distribution2.user-id")) + ) + ) + verifyInstalledDistribution( + name = """Test - "${expr("matrix.distribution2.user-id")}" should be the default distribution after installation""", + expectedPatternExpression = "matrix.distribution2.match-pattern" + ) + executeActionStep = usesSelfAfterSuccess( + name = "Re-execute action", + action = executeAction + ) + verifyInstalledDistribution( + name = """Test - "${expr("matrix.distribution2.user-id")}" should still be the default distribution after re-running for "${expr("matrix.distribution.user-id")}"""", + expectedPatternExpression = "matrix.distribution2.match-pattern" + ) + executeActionStep = usesSelfAfterSuccess( + name = "Set as default", + action = executeAction.copy( + setAsDefault = true + ) + ) + verifyInstalledDistribution( + name = """Test - "${expr("matrix.distribution.user-id")}" should be the default distribution after re-running with set-as-default true""" + ) + } + + job( + id = "test_distribution_specific_wsl_bash_scripts", + name = "Test distribution specific wsl-bash scripts on ${expr("matrix.environment")}", + needs = listOf(build), + runsOn = RunnerType.Custom(expr("matrix.environment")), + _customArguments = mapOf( + "strategy" to mapOf( + "fail-fast" to false, + "matrix" to mapOf( + "environment" to environments, + // ubuntu2004 and ubuntu2204 currently have the same wsl-id + // so their distribution specific wsl_bash scripts will clash + // and thus cannot be tested together + "distributions" to listOf(ubuntu2204, ubuntu2004) + .map { incompatibleUbuntu -> + distributions + .filter { it != incompatibleUbuntu } + .mapIndexed { i, distribution -> + "distribution${i + 1}" to distribution + } + .toMap() + } + ) + ) + ) + ) { + uses( + name = "Restore built artifacts from cache", + action = builtArtifactsCache + ) + (1 until distributions.size) + .associateWith { + usesSelf( + name = "Execute action for ${expr("matrix.distributions.distribution$it.user-id")}", + action = SetupWslV1( + distribution = Distribution.Custom(expr("matrix.distributions.distribution$it.user-id")), + additionalPackages = if (it == 2) listOf("bash") else null, + setAsDefault = if (it >= 3) false else null + ) + ) + } + .forEach { (i, localExecuteActionStep) -> + executeActionStep = localExecuteActionStep + verifyInstalledDistribution( + name = "Test - wsl-bash_${expr("matrix.distributions.distribution$i.user-id")} should use the correct distribution", + conditionTransformer = if (i == 5) { + { executeActionStep.successNotOnUbuntu2004Condition } + } else { + { it } + }, + // the formula adds 1 to the indices after 5 + // to mitigate the double entry for index 5 + shell = Shell.Custom("wsl-bash_${distributions[(i / 6) + i - 1]["user-id"]} {0}"), + expectedPatternExpression = "matrix.distributions.distribution$i.match-pattern" + ) + if (i == 5) { + verifyInstalledDistribution( + name = "Test - wsl-bash_${expr("matrix.distributions.distribution$i.user-id")} should use the correct distribution", + conditionTransformer = { executeActionStep.successNotOnUbuntu2204Condition }, + shell = Shell.Custom("wsl-bash_${distributions[i]["user-id"]} {0}"), + expectedPatternExpression = "matrix.distributions.distribution$i.match-pattern" + ) + } + } + + } +}.apply { + writeToFile() + __FILE__.resolveSibling(targetFileName).apply { + writeText( + """ + |# Copyright 2020-2023 Björn Kautler + |# + |# Licensed under the Apache License, Version 2.0 (the "License"); + |# you may not use this file except in compliance with the License. + |# You may obtain a copy of the License at + |# + |# http://www.apache.org/licenses/LICENSE-2.0 + |# + |# Unless required by applicable law or agreed to in writing, software + |# distributed under the License is distributed on an "AS IS" BASIS, + |# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + |# See the License for the specific language governing permissions and + |# limitations under the License. + | + ${readText().prependIndent("|")} + """.trimMargin() + ) + } +} + +fun JobBuilder<*>.commonTests() { + runAfterSuccess( + name = "Test - wsl-bash should be available as custom shell" + ) + verifyFailure( + name = "Test - wsl-bash should fail if the script fails", + provocationCommand = "false", + verificationShell = Cmd, + verificationTransformer = { provocationStep, _ -> + // do not just rely on false here, but explicitly use exit + // in case failing commands do not make the script fail + // and use "shell = Cmd" to capture that the wrapper script is hiding errors + "IF '${expr(provocationStep.outcome)}' NEQ 'failure' EXIT /B 1" + } + ) + verifyFailure( + name = "Test - wsl-bash should fail if one of the commands fails", + provocationCommand = """ + false + : + """, + // do not just rely on false here, but explicitly use exit + // in case failing commands do not make the script fail + verificationTransformer = { _, command -> "$command || exit 1" } + ) + verifyFailure( + name = "Test - wsl-bash should fail if an undefined variable is used", + provocationCommand = "\$foo" + ) + verifyFailure( + name = "Test - wsl-bash should fail if any command in a pipe fails", + provocationCommand = "false | true" + ) + verifyCommandResult( + name = "Test - the default distribution should be correct", + actualCommand = """ + cat + <(wsl.exe --list || true) + <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) + <(wslconfig.exe /list || true) + <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) + """.trimIndent().replace("\n", " "), + expectedPattern = """*${expr("matrix.distribution.wsl-id")}\ \(Default\)*""" + ) + verifyInstalledDistribution( + name = "Test - wsl-bash should use the correct distribution" + ) + runAfterSuccess( + name = "Test - multi-line commands should not be disturbed by CRLF line endings", + command = """ + : # this comment catches the CR if present + ! grep -q $'\r' "$0" # this comment catches the CR if present + """ + ) +} + +fun JobBuilder<*>.usesSelfAfterSuccess( + name: String = "Execute action", + action: SetupWslV1 +) = usesSelf( + name = name, + action = action, + condition = executeActionStep.successCondition +) + +fun JobBuilder<*>.usesSelf( + name: String = "Execute action", + action: SetupWslV1, + condition: String? = null, + continueOnError: Boolean? = null +) = uses( + name = name, + action = action, + condition = condition, + continueOnError = continueOnError, + _customArguments = mapOf( + "uses" to "./" + ) +) + +fun JobBuilder<*>.deleteWslBashOnAlpine() = deleteWslBash( + conditionTransformer = { executeActionStep.successOnAlpineCondition } +) + +fun JobBuilder<*>.deleteWslBash( + wslBashPathExpression: String = executeActionStep.outputs.wslShellWrapperPath, + conditionTransformer: (String) -> String = { it } +) = run( + name = "Delete wsl-bash", + condition = conditionTransformer(executeActionStep.successCondition).trimIndent(), + shell = Cmd, + command = """DEL /F "${expr(wslBashPathExpression)}"""" +) + +fun JobBuilder<*>.runAfterSuccess( + name: String, + conditionTransformer: (String) -> String = { it }, + shell: Shell? = wslBash, + command: String = ":", + continueOnError: Boolean? = null +) = run( + name = name, + condition = conditionTransformer(executeActionStep.successCondition).trimIndent(), + shell = shell, + command = command.trimIndent(), + continueOnError = continueOnError +) + +fun JobBuilder<*>.verifyFailure( + name: String, + conditionTransformer: (String) -> String = { it }, + provocationShell: Shell = wslBash, + provocationCommand: String = ":", + verificationShell: Shell? = wslBash, + verificationTransformer: (CommandStep, String) -> String = { _, command -> command } +) { + val provocationStep = runAfterSuccess( + name = "$name (provocation)", + conditionTransformer = conditionTransformer, + shell = provocationShell, + command = provocationCommand, + continueOnError = true + ) + runAfterSuccess( + name = "$name (verification)", + conditionTransformer = conditionTransformer, + shell = verificationShell, + command = verificationTransformer( + provocationStep, + "[ '${expr(provocationStep.outcome)}' == 'failure' ]" + ) + ) +} + +fun JobBuilder<*>.verifyInstalledDistribution( + name: String, + conditionTransformer: (String) -> String = { it }, + shell: Shell = wslBash, + expectedPatternExpression: String = "matrix.distribution.match-pattern" +) = verifyCommandResult( + name = name, + conditionTransformer = conditionTransformer, + actualCommand = """ + cat + <(lsb_release -a || true) + <(uname -a || true) + <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) + <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) + <([ -f /proc/version ] && cat /proc/version || true) + """.trimIndent().replace("\n", " "), + shell = shell, + expectedPattern = expr(expectedPatternExpression) +) + +fun JobBuilder<*>.verifyCommandResult( + name: String, + conditionTransformer: (String) -> String = { it }, + actualCommand: String, + shell: Shell = wslBash, + expected: String? = null, + expectedPattern: String? = null +) { + require((expected != null) || (expectedPattern != null)) { + "Either expected or expectedPattern must be non-null" + } + require( + ((expected != null) && (expectedPattern == null)) + || ((expected == null) && (expectedPattern != null)) + ) { + "Either expected or expectedPattern must be non-null, but not both" + } + runAfterSuccess( + name = name, + conditionTransformer = conditionTransformer, + shell = shell, + command = if (expected != null) """ + ${actualCommand.trimIndent()} + [ "$(${actualCommand.trimIndent()})" == '${expected.trimIndent()}' ] + """ else if (expectedPattern != null) """ + ${actualCommand.trimIndent()} + [[ "$(${actualCommand.trimIndent()})" == ${expectedPattern.trimIndent()} ]] + """ else error("Erroneous method input validation") + ) +} + +val Step.successCondition + get() = """ + always() + && ($outcome == 'success') + """.trimIndent() + +val Step.successOnAlpineCondition + get() = """ + always() + && ($outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + """.trimIndent() + +val Step.successNotOnUbuntu2004Condition + get() = """ + always() + && ($outcome == 'success') + && (matrix.distributions.distribution5.user-id != 'Ubuntu-20.04') + """.trimIndent() + +val Step.successNotOnUbuntu2204Condition + get() = """ + always() + && ($outcome == 'success') + && (matrix.distributions.distribution5.user-id != 'Ubuntu-22.04') + """.trimIndent() + +val Step.outcome get() = "steps.$id.outcome" + +// work-around for https://github.com/krzema12/github-workflows-kt/issues/640 +fun SetupWslV1.copy( + distribution: SetupWslV1.Distribution? = null, + useCache: Boolean? = null, + wslConf: String? = null, + setAsDefault: Boolean? = null, + update: Boolean? = null, + additionalPackages: List? = null, + wslShellUser: String? = null, + wslShellCommand: String? = null +) = SetupWslV1( + distribution = distribution ?: this.distribution, + useCache = useCache ?: this.useCache, + wslConf = wslConf ?: this.wslConf, + setAsDefault = setAsDefault ?: this.setAsDefault, + update = update ?: this.update, + additionalPackages = additionalPackages ?: this.additionalPackages, + wslShellUser = wslShellUser ?: this.wslShellUser, + wslShellCommand = wslShellCommand ?: this.wslShellCommand +) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 00000000..412734f6 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,1677 @@ +# Copyright 2020-2023 Björn Kautler +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file was generated using Kotlin DSL (.github/workflows/test.main.kts). +# If you want to modify the workflow, please change the Kotlin file and regenerate this YAML file. +# Generated with https://github.com/krzema12/github-workflows-kt + +name: Build and Test +on: + push: {} + pull_request: {} + schedule: + - cron: 0 0 * * * +jobs: + check_yaml_consistency: + runs-on: ubuntu-latest + steps: + - id: step-0 + name: Check out + uses: actions/checkout@v3 + - id: step-1 + name: Set up Java in proper version + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: zulu + cache: gradle + - id: step-2 + name: Execute script + run: rm '.github/workflows/test.yaml' && '.github/workflows/test.main.kts' + - id: step-3 + name: Consistency check + run: git diff --exit-code '.github/workflows/test.yaml' + build: + name: Build + runs-on: windows-latest + needs: + - check_yaml_consistency + steps: + - id: step-0 + name: Configure Git + run: git config --global core.autocrlf input + - id: step-1 + name: Checkout + uses: actions/checkout@v2 + - id: step-2 + name: Build + uses: burrunan/gradle-cache-action@v1 + with: + arguments: build --info --stacktrace --scan + debug: false + concurrent: true + gradle-dependencies-cache-key: buildSrc/**/Versions.kt + - id: step-3 + name: Save built artifacts to cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + test_invalid_distribution: + name: Test "${{ matrix.distribution.label }}" distribution on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distribution: + - id: invalid + label: invalid + - id: '' + label: '' + - id: null + label: 'null' + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action + continue-on-error: true + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + - id: step-2 + name: Test - action should fail if an invalid distribution is given + shell: cmd + run: if '${{ steps.step-1.outcome }}' NEQ 'failure' exit 1 + test_default_distribution: + name: Test default distribution on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distribution: + - wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action + uses: ./ + with: + update: true + - id: step-2 + name: Test - wsl-bash should be available as custom shell + shell: wsl-bash {0} + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-3 + name: Test - wsl-bash should fail if the script fails (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: false + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-4 + name: Test - wsl-bash should fail if the script fails (verification) + shell: cmd + run: IF '${{ steps.step-3.outcome }}' NEQ 'failure' EXIT /B 1 + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-5 + name: Test - wsl-bash should fail if one of the commands fails (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: |- + false + : + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-6 + name: Test - wsl-bash should fail if one of the commands fails (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-5.outcome }}'' == ''failure'' ] || exit 1' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-7 + name: Test - wsl-bash should fail if an undefined variable is used (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: $foo + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-8 + name: Test - wsl-bash should fail if an undefined variable is used (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-7.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-9 + name: Test - wsl-bash should fail if any command in a pipe fails (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: false | true + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-10 + name: Test - wsl-bash should fail if any command in a pipe fails (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-9.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-11 + name: Test - the default distribution should be correct + shell: wsl-bash {0} + run: |- + cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) + [[ "$(cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))" == *${{ matrix.distribution.wsl-id }}\ \(Default\)* ]] + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-12 + name: Test - wsl-bash should use the correct distribution + shell: wsl-bash {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distribution.match-pattern }} ]] + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-13 + name: Test - multi-line commands should not be disturbed by CRLF line endings + shell: wsl-bash {0} + run: |- + : # this comment catches the CR if present + ! grep -q $'\r' "$0" # this comment catches the CR if present + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-14 + name: Test - wsl-bash should fail if no script file is given (provocation) + continue-on-error: true + shell: wsl-bash + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-15 + name: Test - wsl-bash should fail if no script file is given (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-14.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-16 + name: Test - wsl-bash should fail if more than one parameter is given and first is not -u (provocation) + continue-on-error: true + shell: wsl-bash user {0} + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-17 + name: Test - wsl-bash should fail if more than one parameter is given and first is not -u (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-16.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-18 + name: Test - wsl-bash should fail if only user is given (provocation) + continue-on-error: true + shell: wsl-bash -u {0} + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-19 + name: Test - wsl-bash should fail if only user is given (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-18.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-20 + name: Test - wsl-bash should fail if excess argument is given (provocation) + continue-on-error: true + shell: wsl-bash -u user {0} foo + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-21 + name: Test - wsl-bash should fail if excess argument is given (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-20.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-22 + name: Test - wsl-bash should fail if given script file does not exist (provocation) + continue-on-error: true + shell: wsl-bash -u user {0}foo + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-23 + name: Test - wsl-bash should fail if given script file does not exist (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-22.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + test: + name: Test "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distribution: + - wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - wsl-id: Alpine + user-id: Alpine + match-pattern: '*Alpine*' + default-absent-tool: dos2unix + - wsl-id: kali-linux + user-id: kali-linux + match-pattern: '*Kali*' + default-absent-tool: dos2unix + - wsl-id: openSUSE-Leap-15.2 + user-id: openSUSE-Leap-15.2 + match-pattern: '*openSUSE*Leap*15.2*' + default-absent-tool: which + - wsl-id: Ubuntu + user-id: Ubuntu-22.04 + match-pattern: '*Ubuntu*22.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-16.04 + user-id: Ubuntu-16.04 + match-pattern: '*Ubuntu*16.04*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + use-cache: false + - id: step-2 + name: Test - wsl-bash should fail if bash is not present by default (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-3 + name: Test - wsl-bash should fail if bash is not present by default (verification) + run: wsl sh -euc "[ '${{ steps.step-2.outcome }}' = 'failure' ]" + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-4 + name: Delete wsl-bash + shell: cmd + run: DEL /F "${{ steps.step-1.outputs.wsl-shell-wrapper-path }}" + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-5 + name: Install Bash on Alpine + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + additional-packages: bash + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-6 + name: Test - wsl-bash should be available as custom shell + shell: wsl-bash {0} + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-7 + name: Test - wsl-bash should fail if the script fails (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: false + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-8 + name: Test - wsl-bash should fail if the script fails (verification) + shell: cmd + run: IF '${{ steps.step-7.outcome }}' NEQ 'failure' EXIT /B 1 + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-9 + name: Test - wsl-bash should fail if one of the commands fails (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: |- + false + : + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-10 + name: Test - wsl-bash should fail if one of the commands fails (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-9.outcome }}'' == ''failure'' ] || exit 1' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-11 + name: Test - wsl-bash should fail if an undefined variable is used (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: $foo + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-12 + name: Test - wsl-bash should fail if an undefined variable is used (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-11.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-13 + name: Test - wsl-bash should fail if any command in a pipe fails (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: false | true + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-14 + name: Test - wsl-bash should fail if any command in a pipe fails (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-13.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-15 + name: Test - the default distribution should be correct + shell: wsl-bash {0} + run: |- + cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) + [[ "$(cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))" == *${{ matrix.distribution.wsl-id }}\ \(Default\)* ]] + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-16 + name: Test - wsl-bash should use the correct distribution + shell: wsl-bash {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distribution.match-pattern }} ]] + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-17 + name: Test - multi-line commands should not be disturbed by CRLF line endings + shell: wsl-bash {0} + run: |- + : # this comment catches the CR if present + ! grep -q $'\r' "$0" # this comment catches the CR if present + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-18 + name: Test - ${{ matrix.distribution.default-absent-tool }} should not be installed by default (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: ${{ matrix.distribution.default-absent-tool }} --version + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-19 + name: Test - ${{ matrix.distribution.default-absent-tool }} should not be installed by default (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-18.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-20 + name: Test - bash should be installed by default + shell: wsl-bash {0} + run: bash -c true + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-21 + name: Test - sh should be installed by default + shell: wsl-bash {0} + run: sh -c true + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-22 + name: Test - wsl-sh should not be present (provocation) + continue-on-error: true + shell: wsl-sh {0} + run: ':' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-23 + name: Test - wsl-sh should not be present (verification) + shell: wsl-bash {0} + run: '[ ''${{ steps.step-22.outcome }}'' == ''failure'' ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-24 + name: Add wsl-sh wrapper + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + wsl-shell-command: sh -eu + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-25 + name: Test - wsl-sh should be present + shell: wsl-sh {0} + run: ':' + if: |- + always() + && (steps.step-24.outcome == 'success') + - id: step-26 + name: Test - wsl-bash should use bash + shell: wsl-bash {0} + run: |- + ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' + [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" == 'bash' ] + if: |- + always() + && (steps.step-24.outcome == 'success') + - id: step-27 + name: Test - wsl-sh should use sh + shell: wsl-sh {0} + run: |- + ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' + [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" = 'sh' ] + if: |- + always() + && (steps.step-24.outcome == 'success') + - id: step-28 + name: Delete wsl-bash + shell: cmd + run: DEL /F "${{ steps.step-1.outputs.wsl-shell-wrapper-path }}" + if: |- + always() + && (steps.step-24.outcome == 'success') + - id: step-29 + name: Test - wsl-bash should not be present (provocation) + continue-on-error: true + shell: wsl-bash {0} + run: ':' + if: |- + always() + && (steps.step-24.outcome == 'success') + - id: step-30 + name: Test - wsl-bash should not be present (verification) + shell: wsl-sh {0} + run: '[ ''${{ steps.step-29.outcome }}'' = ''failure'' ]' + if: |- + always() + && (steps.step-24.outcome == 'success') + - id: step-31 + name: Re-add wsl-bash wrapper + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + if: |- + always() + && (steps.step-24.outcome == 'success') + - id: step-32 + name: Test - wsl-bash should be present + shell: wsl-bash {0} + run: ':' + if: |- + always() + && (steps.step-31.outcome == 'success') + - id: step-33 + name: Test - wsl-bash should use bash + shell: wsl-bash {0} + run: |- + ps -o pid='' -o comm='' | grep "^\s\+$$\s\+" | grep -o '\S\+$' + [ "$(ps -o pid='' -o comm='' 2>/dev/null | grep "^\s\+$$\s\+" | grep -o '\S\+$')" == 'bash' ] + if: |- + always() + && (steps.step-31.outcome == 'success') + - id: step-34 + name: Test - wsl-bash should use root as default user + shell: wsl-bash {0} + run: |- + whoami + [ "$(whoami)" == 'root' ] + if: |- + always() + && (steps.step-31.outcome == 'success') + - id: step-35 + name: Add user test + shell: wsl-bash {0} + run: useradd -m -p 4qBD5NWD3IkbU test + if: |- + always() + && (steps.step-31.outcome == 'success') + - id: step-36 + name: Set wsl-bash wrapper to use user test by default + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + additional-packages: sudo + wsl-shell-command: bash -c "sudo -u test bash --noprofile --norc -euo pipefail "\ + if: |- + always() + && (steps.step-31.outcome == 'success') + - id: step-37 + name: Test - wsl-bash should use test as default user + shell: wsl-bash {0} + run: |- + whoami + [ "$(whoami)" == 'test' ] + if: |- + always() + && (steps.step-36.outcome == 'success') + - id: step-38 + name: Set wsl-bash wrapper to use user test by default with inline script usage + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + wsl-shell-command: bash -c "sudo -u test bash --noprofile --norc -euo pipefail '{0}'" + if: |- + always() + && (steps.step-36.outcome == 'success') + - id: step-39 + name: Test - wsl-bash should use test as default user with inline script usage + shell: wsl-bash {0} + run: |- + whoami + [ "$(whoami)" == 'test' ] + if: |- + always() + && (steps.step-38.outcome == 'success') + - id: step-40 + name: Delete wsl-bash + shell: cmd + run: DEL /F "${{ steps.step-38.outputs.wsl-shell-wrapper-path }}" + if: |- + always() + && (steps.step-38.outcome == 'success') + - id: step-41 + name: Set wsl-bash wrapper to use default user by default + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + if: |- + always() + && (steps.step-38.outcome == 'success') + - id: step-42 + name: Test - wsl-bash should use root as default user + shell: wsl-bash {0} + run: |- + whoami + [ "$(whoami)" == 'root' ] + if: |- + always() + && (steps.step-41.outcome == 'success') + - id: step-43 + name: Test - test user does already exist + shell: wsl-bash {0} + run: id -u test + if: |- + always() + && (steps.step-41.outcome == 'success') + - id: step-44 + name: Delete wsl-bash + shell: cmd + run: DEL /F "${{ steps.step-41.outputs.wsl-shell-wrapper-path }}" + if: |- + always() + && (steps.step-41.outcome == 'success') + - id: step-45 + name: Set wsl-bash wrapper to use existing user test by default with extra parameter + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + wsl-shell-user: test + if: |- + always() + && (steps.step-41.outcome == 'success') + - id: step-46 + name: Test - wsl-bash should use existing user test as default user with extra parameter + shell: wsl-bash {0} + run: |- + whoami + [ "$(whoami)" == 'test' ] + if: |- + always() + && (steps.step-45.outcome == 'success') + - id: step-47 + name: Test - test2 user does not exist + shell: wsl-bash {0} + run: '! id -u test2' + if: |- + always() + && (steps.step-45.outcome == 'success') + - id: step-48 + name: Delete wsl-bash + shell: cmd + run: DEL /F "${{ steps.step-45.outputs.wsl-shell-wrapper-path }}" + if: |- + always() + && (steps.step-45.outcome == 'success') + - id: step-49 + name: Set wsl-bash wrapper to use non-existing user test2 by default with extra parameter + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + wsl-shell-user: test2 + if: |- + always() + && (steps.step-45.outcome == 'success') + - id: step-50 + name: Test - wsl-bash should use auto-generated user test2 as default user + shell: wsl-bash {0} + run: |- + whoami + [ "$(whoami)" == 'test2' ] + if: |- + always() + && (steps.step-49.outcome == 'success') + - id: step-51 + name: Test - wsl-bash should use ad-hoc user test + shell: wsl-bash -u test {0} + run: |- + whoami + [ "$(whoami)" == 'test' ] + if: |- + always() + && (steps.step-49.outcome == 'success') + - id: step-52 + name: Test - wsl-bash should use ad-hoc user root + shell: wsl-bash -u root {0} + run: |- + whoami + [ "$(whoami)" == 'root' ] + if: |- + always() + && (steps.step-49.outcome == 'success') + - id: step-53 + name: Make a no-op execution of the action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + if: |- + always() + && (steps.step-49.outcome == 'success') + - id: step-54 + name: Test - wsl-bash should still use test2 as default user + shell: wsl-bash {0} + run: |- + whoami + [ "$(whoami)" == 'test2' ] + if: |- + always() + && (steps.step-53.outcome == 'success') + test_wsl-conf_on_initial_execution: + name: Test /etc/wsl.conf handling on initial execution for "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distribution: + - wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - wsl-id: Alpine + user-id: Alpine + match-pattern: '*Alpine*' + default-absent-tool: dos2unix + - wsl-id: kali-linux + user-id: kali-linux + match-pattern: '*Kali*' + default-absent-tool: dos2unix + - wsl-id: openSUSE-Leap-15.2 + user-id: openSUSE-Leap-15.2 + match-pattern: '*openSUSE*Leap*15.2*' + default-absent-tool: which + - wsl-id: Ubuntu + user-id: Ubuntu-22.04 + match-pattern: '*Ubuntu*22.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-16.04 + user-id: Ubuntu-16.04 + match-pattern: '*Ubuntu*16.04*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + wsl-conf: |- + [automount] + options = uid=1000 + - id: step-2 + name: Delete wsl-bash + shell: cmd + run: DEL /F "${{ steps.step-1.outputs.wsl-shell-wrapper-path }}" + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-3 + name: Install Bash on Alpine + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + additional-packages: bash + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-4 + name: Test - /etc/wsl.conf should exist + shell: wsl-bash {0} + run: |- + [ -f /etc/wsl.conf ] + cat /etc/wsl.conf + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-5 + name: Test - /mnt/c should be mounted with uid 1000 + shell: wsl-bash {0} + run: |- + ls -alh /mnt + [[ "$(stat -c %u /mnt/c)" == 1000 ]] + if: |- + always() + && (steps.step-1.outcome == 'success') + test_wsl-conf_on_subsequent_execution: + name: Test /etc/wsl.conf handling on subsequent execution for "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distribution: + - wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - wsl-id: Alpine + user-id: Alpine + match-pattern: '*Alpine*' + default-absent-tool: dos2unix + - wsl-id: kali-linux + user-id: kali-linux + match-pattern: '*Kali*' + default-absent-tool: dos2unix + - wsl-id: openSUSE-Leap-15.2 + user-id: openSUSE-Leap-15.2 + match-pattern: '*openSUSE*Leap*15.2*' + default-absent-tool: which + - wsl-id: Ubuntu + user-id: Ubuntu-22.04 + match-pattern: '*Ubuntu*22.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-16.04 + user-id: Ubuntu-16.04 + match-pattern: '*Ubuntu*16.04*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + - id: step-2 + name: Delete wsl-bash + shell: cmd + run: DEL /F "${{ steps.step-1.outputs.wsl-shell-wrapper-path }}" + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-3 + name: Install Bash on Alpine + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + additional-packages: bash + if: |- + always() + && (steps.step-1.outcome == 'success') + && (matrix.distribution.user-id == 'Alpine') + - id: step-4 + name: Test - /etc/wsl.conf should not exist + shell: wsl-bash {0} + run: '[ ! -f /etc/wsl.conf ]' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-5 + name: 'Test - C: should be mounted at /mnt/c' + shell: wsl-bash {0} + run: |- + mount + mount | grep 'C:.* on /mnt/c' + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-6 + name: Test - /mnt/c should be mounted with uid 0 + shell: wsl-bash {0} + run: |- + ls -alh /mnt + [[ "$(stat -c %u /mnt/c)" == 0 ]] + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-7 + name: Execute action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + wsl-conf: |- + [automount] + root = / + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-8 + name: Test - /etc/wsl.conf should exist + shell: wsl-bash {0} + run: |- + [ -f /etc/wsl.conf ] + cat /etc/wsl.conf + if: |- + always() + && (steps.step-7.outcome == 'success') + - id: step-9 + name: 'Test - C: should be mounted at /c' + shell: wsl-bash {0} + run: |- + mount + mount | grep 'C:.* on /c' + if: |- + always() + && (steps.step-7.outcome == 'success') + test_additional_packages: + name: Test additional packages for "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distribution: + - wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - wsl-id: Alpine + user-id: Alpine + match-pattern: '*Alpine*' + default-absent-tool: dos2unix + - wsl-id: kali-linux + user-id: kali-linux + match-pattern: '*Kali*' + default-absent-tool: dos2unix + - wsl-id: openSUSE-Leap-15.2 + user-id: openSUSE-Leap-15.2 + match-pattern: '*openSUSE*Leap*15.2*' + default-absent-tool: which + - wsl-id: Ubuntu + user-id: Ubuntu-22.04 + match-pattern: '*Ubuntu*22.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-16.04 + user-id: Ubuntu-16.04 + match-pattern: '*Ubuntu*16.04*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + additional-packages: ${{ matrix.distribution.default-absent-tool }} bash + - id: step-2 + name: Test - ${{ matrix.distribution.default-absent-tool }} should be installed + shell: wsl-bash {0} + run: ${{ matrix.distribution.default-absent-tool }} --version + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-3 + name: Test - bash should be installed + shell: wsl-bash {0} + run: bash -c true + if: |- + always() + && (steps.step-1.outcome == 'success') + test_multiple_usage_with_different_distributions: + name: Test multiple usage with different distributions ("${{ matrix.distributions.distribution1.user-id }}" / "${{ matrix.distributions.distribution2.user-id }}" / "${{ matrix.distributions.distribution3.user-id }}") on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distributions: + - distribution1: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + distribution3: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + - distribution1: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + distribution3: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - distribution1: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution3: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + - distribution1: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + distribution3: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - distribution1: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution3: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - distribution1: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + distribution3: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action for ${{ matrix.distributions.distribution1.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution1.user-id }} + - id: step-2 + name: Execute action for ${{ matrix.distributions.distribution2.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution2.user-id }} + - id: step-3 + name: Execute action for ${{ matrix.distributions.distribution3.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution3.user-id }} + set-as-default: false + - id: step-4 + name: Execute action for ${{ matrix.distributions.distribution1.user-id }} again + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution1.user-id }} + - id: step-5 + name: Test - the default distribution should be the last installed distribution with set-as-default true + shell: wsl-bash {0} + run: |- + cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8) + [[ "$(cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))" == *${{ matrix.distributions.distribution2.wsl-id }}\ \(Default\)* ]] + if: |- + always() + && (steps.step-4.outcome == 'success') + - id: step-6 + name: Test - wsl-bash should use the last installed distribution with set-as-default true + shell: wsl-bash {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution2.match-pattern }} ]] + if: |- + always() + && (steps.step-4.outcome == 'success') + test_multiple_usage_with_same_distribution: + name: Test multiple usage with "${{ matrix.distribution.user-id }}" distribution on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distribution: + - wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - wsl-id: Alpine + user-id: Alpine + match-pattern: '*Alpine*' + default-absent-tool: dos2unix + - wsl-id: kali-linux + user-id: kali-linux + match-pattern: '*Kali*' + default-absent-tool: dos2unix + - wsl-id: openSUSE-Leap-15.2 + user-id: openSUSE-Leap-15.2 + match-pattern: '*openSUSE*Leap*15.2*' + default-absent-tool: which + - wsl-id: Ubuntu + user-id: Ubuntu-22.04 + match-pattern: '*Ubuntu*22.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + - wsl-id: Ubuntu-16.04 + user-id: Ubuntu-16.04 + match-pattern: '*Ubuntu*16.04*' + default-absent-tool: dos2unix + distribution2: + - wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + exclude: + - environment: windows-2019 + distribution: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - environment: windows-2022 + distribution: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + - environment: windows-latest + distribution: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + include: + - environment: windows-2019 + distribution: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - environment: windows-2022 + distribution: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + - environment: windows-latest + distribution: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + additional-packages: bash + - id: step-2 + name: Update distribution + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + update: true + if: matrix.distribution.user-id != 'kali-linux' + - id: step-3 + name: Install default absent tool + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + additional-packages: ${{ matrix.distribution.default-absent-tool }} + - id: step-4 + name: Test - ${{ matrix.distribution.default-absent-tool }} should be installed + shell: wsl-bash {0} + run: ${{ matrix.distribution.default-absent-tool }} --version + if: |- + always() + && (steps.step-3.outcome == 'success') + - id: step-5 + name: Execute action for ${{ matrix.distribution2.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distribution2.user-id }} + if: |- + always() + && (steps.step-3.outcome == 'success') + - id: step-6 + name: Test - "${{ matrix.distribution2.user-id }}" should be the default distribution after installation + shell: wsl-bash {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distribution2.match-pattern }} ]] + if: |- + always() + && (steps.step-5.outcome == 'success') + - id: step-7 + name: Re-execute action + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + if: |- + always() + && (steps.step-5.outcome == 'success') + - id: step-8 + name: Test - "${{ matrix.distribution2.user-id }}" should still be the default distribution after re-running for "${{ matrix.distribution.user-id }}" + shell: wsl-bash {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distribution2.match-pattern }} ]] + if: |- + always() + && (steps.step-7.outcome == 'success') + - id: step-9 + name: Set as default + uses: ./ + with: + distribution: ${{ matrix.distribution.user-id }} + set-as-default: true + if: |- + always() + && (steps.step-7.outcome == 'success') + - id: step-10 + name: Test - "${{ matrix.distribution.user-id }}" should be the default distribution after re-running with set-as-default true + shell: wsl-bash {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distribution.match-pattern }} ]] + if: |- + always() + && (steps.step-9.outcome == 'success') + test_distribution_specific_wsl_bash_scripts: + name: Test distribution specific wsl-bash scripts on ${{ matrix.environment }} + runs-on: ${{ matrix.environment }} + needs: + - build + - check_yaml_consistency + strategy: + fail-fast: false + matrix: + environment: + - windows-2019 + - windows-2022 + - windows-latest + distributions: + - distribution1: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Alpine + user-id: Alpine + match-pattern: '*Alpine*' + default-absent-tool: dos2unix + distribution3: + wsl-id: kali-linux + user-id: kali-linux + match-pattern: '*Kali*' + default-absent-tool: dos2unix + distribution4: + wsl-id: openSUSE-Leap-15.2 + user-id: openSUSE-Leap-15.2 + match-pattern: '*openSUSE*Leap*15.2*' + default-absent-tool: which + distribution5: + wsl-id: Ubuntu + user-id: Ubuntu-20.04 + match-pattern: '*Ubuntu*20.04*' + default-absent-tool: dos2unix + distribution6: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + distribution7: + wsl-id: Ubuntu-16.04 + user-id: Ubuntu-16.04 + match-pattern: '*Ubuntu*16.04*' + default-absent-tool: dos2unix + - distribution1: + wsl-id: Debian + user-id: Debian + match-pattern: '*Debian*' + default-absent-tool: dos2unix + distribution2: + wsl-id: Alpine + user-id: Alpine + match-pattern: '*Alpine*' + default-absent-tool: dos2unix + distribution3: + wsl-id: kali-linux + user-id: kali-linux + match-pattern: '*Kali*' + default-absent-tool: dos2unix + distribution4: + wsl-id: openSUSE-Leap-15.2 + user-id: openSUSE-Leap-15.2 + match-pattern: '*openSUSE*Leap*15.2*' + default-absent-tool: which + distribution5: + wsl-id: Ubuntu + user-id: Ubuntu-22.04 + match-pattern: '*Ubuntu*22.04*' + default-absent-tool: dos2unix + distribution6: + wsl-id: Ubuntu-18.04 + user-id: Ubuntu-18.04 + match-pattern: '*Ubuntu*18.04*' + default-absent-tool: dos2unix + distribution7: + wsl-id: Ubuntu-16.04 + user-id: Ubuntu-16.04 + match-pattern: '*Ubuntu*16.04*' + default-absent-tool: dos2unix + steps: + - id: step-0 + name: Restore built artifacts from cache + uses: actions/cache@v2 + with: + path: |- + action.yml + build/distributions/ + key: ${{ github.run_id }} + - id: step-1 + name: Execute action for ${{ matrix.distributions.distribution1.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution1.user-id }} + - id: step-2 + name: Execute action for ${{ matrix.distributions.distribution2.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution2.user-id }} + additional-packages: bash + - id: step-3 + name: Execute action for ${{ matrix.distributions.distribution3.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution3.user-id }} + set-as-default: false + - id: step-4 + name: Execute action for ${{ matrix.distributions.distribution4.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution4.user-id }} + set-as-default: false + - id: step-5 + name: Execute action for ${{ matrix.distributions.distribution5.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution5.user-id }} + set-as-default: false + - id: step-6 + name: Execute action for ${{ matrix.distributions.distribution6.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution6.user-id }} + set-as-default: false + - id: step-7 + name: Execute action for ${{ matrix.distributions.distribution7.user-id }} + uses: ./ + with: + distribution: ${{ matrix.distributions.distribution7.user-id }} + set-as-default: false + - id: step-8 + name: Test - wsl-bash_${{ matrix.distributions.distribution1.user-id }} should use the correct distribution + shell: wsl-bash_Debian {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution1.match-pattern }} ]] + if: |- + always() + && (steps.step-1.outcome == 'success') + - id: step-9 + name: Test - wsl-bash_${{ matrix.distributions.distribution2.user-id }} should use the correct distribution + shell: wsl-bash_Alpine {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution2.match-pattern }} ]] + if: |- + always() + && (steps.step-2.outcome == 'success') + - id: step-10 + name: Test - wsl-bash_${{ matrix.distributions.distribution3.user-id }} should use the correct distribution + shell: wsl-bash_kali-linux {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution3.match-pattern }} ]] + if: |- + always() + && (steps.step-3.outcome == 'success') + - id: step-11 + name: Test - wsl-bash_${{ matrix.distributions.distribution4.user-id }} should use the correct distribution + shell: wsl-bash_openSUSE-Leap-15.2 {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution4.match-pattern }} ]] + if: |- + always() + && (steps.step-4.outcome == 'success') + - id: step-12 + name: Test - wsl-bash_${{ matrix.distributions.distribution5.user-id }} should use the correct distribution + shell: wsl-bash_Ubuntu-22.04 {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution5.match-pattern }} ]] + if: |- + always() + && (steps.step-5.outcome == 'success') + && (matrix.distributions.distribution5.user-id != 'Ubuntu-20.04') + - id: step-13 + name: Test - wsl-bash_${{ matrix.distributions.distribution5.user-id }} should use the correct distribution + shell: wsl-bash_Ubuntu-20.04 {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution5.match-pattern }} ]] + if: |- + always() + && (steps.step-5.outcome == 'success') + && (matrix.distributions.distribution5.user-id != 'Ubuntu-22.04') + - id: step-14 + name: Test - wsl-bash_${{ matrix.distributions.distribution6.user-id }} should use the correct distribution + shell: wsl-bash_Ubuntu-18.04 {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution6.match-pattern }} ]] + if: |- + always() + && (steps.step-6.outcome == 'success') + - id: step-15 + name: Test - wsl-bash_${{ matrix.distributions.distribution7.user-id }} should use the correct distribution + shell: wsl-bash_Ubuntu-16.04 {0} + run: |- + cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true) + [[ "$(cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \( -name '*release' -or -name 'issue*' \) -exec cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ] && cat /proc/version || true))" == ${{ matrix.distributions.distribution7.match-pattern }} ]] + if: |- + always() + && (steps.step-7.outcome == 'success') diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index c517072a..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,1402 +0,0 @@ -# Copyright 2020-2022 Björn Kautler -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: "Build and Test" -on: - "push": null - "pull_request": null - "schedule": - - cron: "0 0 * * *" -jobs: - "build": - name: "Build" - runs-on: "windows-latest" - steps: - - name: "Configure Git" - run: "git config --global core.autocrlf input" - - name: "Checkout" - uses: "actions/checkout@v2" - - name: "Build" - uses: "burrunan/gradle-cache-action@v1" - with: - "arguments": "build --info --stacktrace --scan" - "debug": "false" - "concurrent": "true" - "gradle-dependencies-cache-key": "buildSrc/**/Versions.kt" - - name: "Save built artifacts to cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - "test_invalid_distribution": - name: "Test \"${{ matrix.distribution.label }}\" distribution on ${{ matrix.environment\ - \ }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action" - name: "Execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - continue-on-error: true - - name: "Test - action should fail if an invalid distribution is given" - run: "if '${{ steps.execute_action.outcome }}' NEQ 'failure' exit 1\n" - shell: "cmd" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distribution": - - "id": "invalid" - "label": "invalid" - - "id": "" - "label": "" - - "id": null - "label": "null" - fail-fast: false - "test_default_distribution": - name: "Test default distribution on ${{ matrix.environment }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action" - name: "Execute action" - uses: "./" - with: - "update": "true" - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should be available as custom shell" - run: ":\n" - shell: "wsl-bash {0}" - - id: "wrapper_should_fail_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if the script fails (provocation)" - run: "false\n" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if the script fails (verification)" - run: "IF '${{ steps.wrapper_should_fail_provocation.outcome }}' NEQ 'failure'\ - \ EXIT /B 1\n" - shell: "cmd" - - id: "set_e_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if one of the commands fails (provocation)" - run: "false\n:\n" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if one of the commands fails (verification)" - run: "[ '${{ steps.set_e_provocation.outcome }}' == 'failure' ] || exit 1\n" - shell: "wsl-bash {0}" - - id: "set_u_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if an undefined variable is used (provocation)" - run: "$foo" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if an undefined variable is used (verification)" - run: "[ '${{ steps.set_u_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - id: "set_pipefail_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if any command in a pipe fails (provocation)" - run: "false | true" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if any command in a pipe fails (verification)" - run: "[ '${{ steps.set_pipefail_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - the default distribution should be correct" - run: "cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE\ - \ -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true |\ - \ iconv -f UTF-16LE -t UTF-8)\n[[ \"$(cat <(wsl.exe --list || true) <(wsl.exe\ - \ --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true)\ - \ <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))\" == *${{ matrix.distribution.wsl-id\ - \ }}\\ \\(Default\\)* ]]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distribution.match-pattern }} ]]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - multi-line commands should not be disturbed by CRLF line endings" - run: ": # this comment catches the CR if present\n! grep -q $'\\r' \"$0\" #\ - \ this comment catches the CR if present\n" - shell: "wsl-bash {0}" - - id: "no_script_file_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if no script file is given (provocation)" - run: ":\n" - shell: "wsl-bash" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if no script file is given (verification)" - run: "[ '${{ steps.no_script_file_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - id: "wrong_first_parameter_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if more than one parameter is given and first\ - \ is not -u (provocation)" - run: ":\n" - shell: "wsl-bash user {0}" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if more than one parameter is given and first\ - \ is not -u (verification)" - run: "[ '${{ steps.wrong_first_parameter_provocation.outcome }}' == 'failure'\ - \ ]\n" - shell: "wsl-bash {0}" - - id: "only_user_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if only user is given (provocation)" - run: ":\n" - shell: "wsl-bash -u {0}" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if only user is given (verification)" - run: "[ '${{ steps.only_user_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - id: "excess_argument_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if excess argument is given (provocation)" - run: ":\n" - shell: "wsl-bash -u user {0} foo" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if excess argument is given (verification)" - run: "[ '${{ steps.excess_argument_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - id: "script_file_does_not_exist_provocation" - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if given script file does not exist (provocation)" - run: ":\n" - shell: "wsl-bash -u user {0}foo" - continue-on-error: true - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - wsl-bash should fail if given script file does not exist (verification)" - run: "[ '${{ steps.script_file_does_not_exist_provocation.outcome }}' == 'failure'\ - \ ]\n" - shell: "wsl-bash {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distribution": - - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - fail-fast: false - "test": - name: "Test \"${{ matrix.distribution.user-id }}\" distribution on ${{ matrix.environment\ - \ }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action1" - name: "Execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "use-cache": "false" - - id: "no_default_bash_provocation" - if: "matrix.distribution.user-id == 'Alpine'" - name: "Test - wsl-bash should fail if bash is not present by default (provocation)" - run: ":\n" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (matrix.distribution.user-id == 'Alpine') && (steps.execute_action1.outcome\ - \ == 'success')" - name: "Test - wsl-bash should fail if bash is not present by default (verification)" - run: "wsl sh -euc \"[ '${{ steps.no_default_bash_provocation.outcome }}' = 'failure'\ - \ ]\"\n" - - if: "always() && (matrix.distribution.user-id == 'Alpine') && (steps.execute_action1.outcome\ - \ == 'success')" - name: "Delete wsl-bash" - run: "DEL /F \"${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}\"" - shell: "cmd" - - id: "execute_action2" - if: "always() && (matrix.distribution.user-id == 'Alpine') && (steps.execute_action1.outcome\ - \ == 'success')" - name: "Install Bash on Alpine" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "additional-packages": "bash" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should be available as custom shell" - run: ":\n" - shell: "wsl-bash {0}" - - id: "wrapper_should_fail_provocation" - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if the script fails (provocation)" - run: "false\n" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if the script fails (verification)" - run: "IF '${{ steps.wrapper_should_fail_provocation.outcome }}' NEQ 'failure'\ - \ EXIT /B 1\n" - shell: "cmd" - - id: "set_e_provocation" - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if one of the commands fails (provocation)" - run: "false\n:\n" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if one of the commands fails (verification)" - run: "[ '${{ steps.set_e_provocation.outcome }}' == 'failure' ] || exit 1\n" - shell: "wsl-bash {0}" - - id: "set_u_provocation" - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if an undefined variable is used (provocation)" - run: "$foo" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if an undefined variable is used (verification)" - run: "[ '${{ steps.set_u_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - id: "set_pipefail_provocation" - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if any command in a pipe fails (provocation)" - run: "false | true" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should fail if any command in a pipe fails (verification)" - run: "[ '${{ steps.set_pipefail_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - the default distribution should be correct" - run: "cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE\ - \ -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true |\ - \ iconv -f UTF-16LE -t UTF-8)\n[[ \"$(cat <(wsl.exe --list || true) <(wsl.exe\ - \ --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true)\ - \ <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))\" == *${{ matrix.distribution.wsl-id\ - \ }}\\ \\(Default\\)* ]]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash should use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distribution.match-pattern }} ]]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - multi-line commands should not be disturbed by CRLF line endings" - run: ": # this comment catches the CR if present\n! grep -q $'\\r' \"$0\" #\ - \ this comment catches the CR if present\n" - shell: "wsl-bash {0}" - - id: "default_absent_tool_absent_provocation" - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - ${{ matrix.distribution.default-absent-tool }} should not be installed\ - \ by default (provocation)" - run: "${{ matrix.distribution.default-absent-tool }} --version" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - ${{ matrix.distribution.default-absent-tool }} should not be installed\ - \ by default (verification)" - run: "[ '${{ steps.default_absent_tool_absent_provocation.outcome }}' == 'failure'\ - \ ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - bash should be installed by default" - run: "bash -c true" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - sh should be installed by default" - run: "sh -c true" - shell: "wsl-bash {0}" - - id: "wsl-sh_absent_provocation" - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-sh should not be present (provocation)" - run: ":\n" - shell: "wsl-sh {0}" - continue-on-error: true - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-sh should not be present (verification)" - run: "[ '${{ steps.wsl-sh_absent_provocation.outcome }}' == 'failure' ]\n" - shell: "wsl-bash {0}" - - id: "execute_action3" - name: "Add wsl-sh wrapper" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "wsl-shell-command": "sh -eu" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - wsl-sh should be present" - run: ":\n" - shell: "wsl-sh {0}" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - wsl-bash should use bash" - run: "ps -o pid='' -o comm='' | grep \"^\\s\\+$$\\s\\+\" | grep -o '\\S\\+$'\n\ - [ \"$(ps -o pid='' -o comm='' 2>/dev/null | grep \"^\\s\\+$$\\s\\+\" | grep\ - \ -o '\\S\\+$')\" == 'bash' ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - wsl-sh should use sh" - run: "ps -o pid='' -o comm='' | grep \"^\\s\\+$$\\s\\+\" | grep -o '\\S\\+$'\n\ - [ \"$(ps -o pid='' -o comm='' 2>/dev/null | grep \"^\\s\\+$$\\s\\+\" | grep\ - \ -o '\\S\\+$')\" = 'sh' ]\n" - shell: "wsl-sh {0}" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Delete wsl-bash" - run: "DEL /F \"${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}\"" - shell: "cmd" - - id: "wsl-bash_absent_provocation" - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - wsl-bash should not be present (provocation)" - run: ":\n" - shell: "wsl-bash {0}" - continue-on-error: true - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - wsl-bash should not be present (verification)" - run: "[ '${{ steps.wsl-bash_absent_provocation.outcome }}' = 'failure' ]\n" - shell: "wsl-sh {0}" - - id: "execute_action4" - name: "Re-add wsl-bash wrapper" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - - if: "always() && (steps.execute_action4.outcome == 'success')" - name: "Test - wsl-bash should be present" - run: ":\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action4.outcome == 'success')" - name: "Test - wsl-bash should use bash" - run: "ps -o pid='' -o comm='' | grep \"^\\s\\+$$\\s\\+\" | grep -o '\\S\\+$'\n\ - [ \"$(ps -o pid='' -o comm='' 2>/dev/null | grep \"^\\s\\+$$\\s\\+\" | grep\ - \ -o '\\S\\+$')\" == 'bash' ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action4.outcome == 'success')" - name: "Test - wsl-bash should use root as default user" - run: "whoami\n[ \"$(whoami)\" == 'root' ]\n" - shell: "wsl-bash {0}" - - name: "Add user test" - run: "useradd -m -p 4qBD5NWD3IkbU test\n" - shell: "wsl-bash {0}" - - id: "execute_action5" - name: "Set wsl-bash wrapper to use user test by default" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "additional-packages": "sudo" - "wsl-shell-command": "bash -c \"sudo -u test bash --noprofile --norc -euo\ - \ pipefail \"\\" - - if: "always() && (steps.execute_action5.outcome == 'success')" - name: "Test - wsl-bash should use test as default user" - run: "whoami\n[ \"$(whoami)\" == 'test' ]\n" - shell: "wsl-bash {0}" - - id: "execute_action6" - name: "Set wsl-bash wrapper to use user test by default with inline script usage" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "wsl-shell-command": "bash -c \"sudo -u test bash --noprofile --norc -euo\ - \ pipefail '{0}'\"" - - if: "always() && (steps.execute_action6.outcome == 'success')" - name: "Test - wsl-bash should use test as default user with inline script usage" - run: "whoami\n[ \"$(whoami)\" == 'test' ]\n" - shell: "wsl-bash {0}" - - name: "Delete wsl-bash" - run: "DEL /F \"${{ steps.execute_action6.outputs.wsl-shell-wrapper-path }}\"" - shell: "cmd" - - id: "execute_action7" - name: "Set wsl-bash wrapper to use default user by default" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - - if: "always() && (steps.execute_action7.outcome == 'success')" - name: "Test - wsl-bash should use root as default user" - run: "whoami\n[ \"$(whoami)\" == 'root' ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action7.outcome == 'success')" - name: "Test - test user does already exist" - run: "id -u test\n" - shell: "wsl-bash {0}" - - name: "Delete wsl-bash" - run: "DEL /F \"${{ steps.execute_action7.outputs.wsl-shell-wrapper-path }}\"" - shell: "cmd" - - id: "execute_action8" - name: "Set wsl-bash wrapper to use existing user test by default with extra\ - \ parameter" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "wsl-shell-user": "test" - - if: "always() && (steps.execute_action8.outcome == 'success')" - name: "Test - wsl-bash should use existing user test as default user with extra\ - \ parameter" - run: "whoami\n[ \"$(whoami)\" == 'test' ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action8.outcome == 'success')" - name: "Test - test2 user does not exist" - run: "! id -u test2\n" - shell: "wsl-bash {0}" - - name: "Delete wsl-bash" - run: "DEL /F \"${{ steps.execute_action8.outputs.wsl-shell-wrapper-path }}\"" - shell: "cmd" - - id: "execute_action9" - name: "Set wsl-bash wrapper to use non-existing user test2 by default with extra\ - \ parameter" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "wsl-shell-user": "test2" - - if: "always() && (steps.execute_action9.outcome == 'success')" - name: "Test - wsl-bash should use auto-generated user test2 as default user" - run: "whoami\n[ \"$(whoami)\" == 'test2' ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action9.outcome == 'success')" - name: "Test - wsl-bash should use ad-hoc user test" - run: "whoami\n[ \"$(whoami)\" == 'test' ]\n" - shell: "wsl-bash -u test {0}" - - if: "always() && (steps.execute_action9.outcome == 'success')" - name: "Test - wsl-bash should use ad-hoc user root" - run: "whoami\n[ \"$(whoami)\" == 'root' ]\n" - shell: "wsl-bash -u root {0}" - - id: "execute_action10" - name: "Make a no-op execution of the action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - - if: "always() && (steps.execute_action10.outcome == 'success')" - name: "Test - wsl-bash should still use test2 as default user" - run: "whoami\n[ \"$(whoami)\" == 'test2' ]\n" - shell: "wsl-bash {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distribution": - - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Alpine" - "user-id": "Alpine" - "match-pattern": "*Alpine*" - "default-absent-tool": "dos2unix" - - "wsl-id": "kali-linux" - "user-id": "kali-linux" - "match-pattern": "*Kali*" - "default-absent-tool": "dos2unix" - - "wsl-id": "openSUSE-Leap-15.2" - "user-id": "openSUSE-Leap-15.2" - "match-pattern": "*openSUSE*Leap*15.2*" - "default-absent-tool": "which" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-22.04" - "match-pattern": "*Ubuntu*22.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-16.04" - "user-id": "Ubuntu-16.04" - "match-pattern": "*Ubuntu*16.04*" - "default-absent-tool": "dos2unix" - fail-fast: false - "test_wsl-conf_on_initial_execution": - name: "Test /etc/wsl.conf handling on initial execution for \"${{ matrix.distribution.user-id\ - \ }}\" distribution on ${{ matrix.environment }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action1" - name: "Execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "wsl-conf": "[automount]\noptions = uid=1000\n" - - if: "always() && (matrix.distribution.user-id == 'Alpine') && (steps.execute_action1.outcome\ - \ == 'success')" - name: "Delete wsl-bash" - run: "DEL /F \"${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}\"" - shell: "cmd" - - id: "execute_action2" - if: "always() && (matrix.distribution.user-id == 'Alpine') && (steps.execute_action1.outcome\ - \ == 'success')" - name: "Install Bash on Alpine" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "additional-packages": "bash" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - /etc/wsl.conf should exist" - run: "[ -f /etc/wsl.conf ]\ncat /etc/wsl.conf\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - /mnt/c should be mounted with uid 1000" - run: "ls -alh /mnt\n[[ \"$(stat -c %u /mnt/c)\" == 1000 ]]\n" - shell: "wsl-bash {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distribution": - - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Alpine" - "user-id": "Alpine" - "match-pattern": "*Alpine*" - "default-absent-tool": "dos2unix" - - "wsl-id": "kali-linux" - "user-id": "kali-linux" - "match-pattern": "*Kali*" - "default-absent-tool": "dos2unix" - - "wsl-id": "openSUSE-Leap-15.2" - "user-id": "openSUSE-Leap-15.2" - "match-pattern": "*openSUSE*Leap*15.2*" - "default-absent-tool": "which" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-22.04" - "match-pattern": "*Ubuntu*22.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-16.04" - "user-id": "Ubuntu-16.04" - "match-pattern": "*Ubuntu*16.04*" - "default-absent-tool": "dos2unix" - fail-fast: false - "test_wsl-conf_on_subsequent_execution": - name: "Test /etc/wsl.conf handling on subsequent execution for \"${{ matrix.distribution.user-id\ - \ }}\" distribution on ${{ matrix.environment }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action1" - name: "Execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - - if: "always() && (matrix.distribution.user-id == 'Alpine') && (steps.execute_action1.outcome\ - \ == 'success')" - name: "Delete wsl-bash" - run: "DEL /F \"${{ steps.execute_action1.outputs.wsl-shell-wrapper-path }}\"" - shell: "cmd" - - id: "execute_action2" - if: "always() && (matrix.distribution.user-id == 'Alpine') && (steps.execute_action1.outcome\ - \ == 'success')" - name: "Install Bash on Alpine" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "additional-packages": "bash" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - /etc/wsl.conf should not exist" - run: "[ ! -f /etc/wsl.conf ]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - C: should be mounted at /mnt/c\n" - run: "mount\nmount | grep 'C:.* on /mnt/c'\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - /mnt/c should be mounted with uid 0" - run: "ls -alh /mnt\n[[ \"$(stat -c %u /mnt/c)\" == 0 ]]\n" - shell: "wsl-bash {0}" - - id: "execute_action3" - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "wsl-conf": "[automount]\nroot = /\n" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - /etc/wsl.conf should exist" - run: "[ -f /etc/wsl.conf ]\ncat /etc/wsl.conf\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - C: should be mounted at /c\n" - run: "mount\nmount | grep 'C:.* on /c'\n" - shell: "wsl-bash {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distribution": - - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Alpine" - "user-id": "Alpine" - "match-pattern": "*Alpine*" - "default-absent-tool": "dos2unix" - - "wsl-id": "kali-linux" - "user-id": "kali-linux" - "match-pattern": "*Kali*" - "default-absent-tool": "dos2unix" - - "wsl-id": "openSUSE-Leap-15.2" - "user-id": "openSUSE-Leap-15.2" - "match-pattern": "*openSUSE*Leap*15.2*" - "default-absent-tool": "which" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-22.04" - "match-pattern": "*Ubuntu*22.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-16.04" - "user-id": "Ubuntu-16.04" - "match-pattern": "*Ubuntu*16.04*" - "default-absent-tool": "dos2unix" - fail-fast: false - "test_additional_packages": - name: "Test additional packages for \"${{ matrix.distribution.user-id }}\" distribution\ - \ on ${{ matrix.environment }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action" - name: "Execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "additional-packages": "${{ matrix.distribution.default-absent-tool }} bash\n" - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - ${{ matrix.distribution.default-absent-tool }} should be installed" - run: "${{ matrix.distribution.default-absent-tool }} --version" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action.outcome == 'success')" - name: "Test - bash should be installed" - run: "bash -c true" - shell: "wsl-bash {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distribution": - - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Alpine" - "user-id": "Alpine" - "match-pattern": "*Alpine*" - "default-absent-tool": "dos2unix" - - "wsl-id": "kali-linux" - "user-id": "kali-linux" - "match-pattern": "*Kali*" - "default-absent-tool": "dos2unix" - - "wsl-id": "openSUSE-Leap-15.2" - "user-id": "openSUSE-Leap-15.2" - "match-pattern": "*openSUSE*Leap*15.2*" - "default-absent-tool": "which" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-22.04" - "match-pattern": "*Ubuntu*22.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-16.04" - "user-id": "Ubuntu-16.04" - "match-pattern": "*Ubuntu*16.04*" - "default-absent-tool": "dos2unix" - fail-fast: false - "test_multiple_usage_with_different_distributions": - name: "Test multiple usage with different distributions (\"${{ matrix.distributions.distribution1.user-id\ - \ }}\" / \"${{ matrix.distributions.distribution2.user-id }}\" / \"${{ matrix.distributions.distribution3.user-id\ - \ }}\") on ${{ matrix.environment }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action1" - name: "Execute action for ${{ matrix.distributions.distribution1.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution1.user-id }}" - - id: "execute_action2" - name: "Execute action for ${{ matrix.distributions.distribution2.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution2.user-id }}" - - id: "execute_action3" - name: "Execute action for ${{ matrix.distributions.distribution3.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution3.user-id }}" - "set-as-default": "false" - - id: "execute_action4" - name: "Execute action for ${{ matrix.distributions.distribution1.user-id }}\ - \ again" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution1.user-id }}" - - if: "always() && (steps.execute_action4.outcome == 'success')" - name: "Test - the default distribution should be the last installed distribution\ - \ with set-as-default true" - run: "cat <(wsl.exe --list || true) <(wsl.exe --list || true | iconv -f UTF-16LE\ - \ -t UTF-8) <(wslconfig.exe /list || true) <(wslconfig.exe /list || true |\ - \ iconv -f UTF-16LE -t UTF-8)\n[[ \"$(cat <(wsl.exe --list || true) <(wsl.exe\ - \ --list || true | iconv -f UTF-16LE -t UTF-8) <(wslconfig.exe /list || true)\ - \ <(wslconfig.exe /list || true | iconv -f UTF-16LE -t UTF-8))\" == *${{ matrix.distributions.distribution2.wsl-id\ - \ }}\\ \\(Default\\)* ]]\n" - shell: "wsl-bash {0}" - - if: "always() && (steps.execute_action4.outcome == 'success')" - name: "Test - wsl-bash should use the last installed distribution with set-as-default\ - \ true" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution2.match-pattern }} ]]\n" - shell: "wsl-bash {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distributions": - - "distribution1": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - - "distribution1": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "distribution1": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - - "distribution1": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "distribution1": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "distribution1": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - fail-fast: false - "test_multiple_usage_with_same_distribution": - name: "Test multiple usage with \"${{ matrix.distribution.user-id }}\" distribution\ - \ on ${{ matrix.environment }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action1" - name: "Execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "additional-packages": "bash" - - id: "execute_action2" - if: "matrix.distribution.user-id != 'kali-linux'" - name: "Update distribution" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "update": "true" - - id: "execute_action3" - name: "Install default absent tool" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "additional-packages": "${{ matrix.distribution.default-absent-tool }}" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - ${{ matrix.distribution.default-absent-tool }} should be installed" - run: "${{ matrix.distribution.default-absent-tool }} --version" - shell: "wsl-bash {0}" - - id: "execute_action4" - name: "Execute action for ${{ matrix.distribution2.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distribution2.user-id }}" - - if: "always() && (steps.execute_action4.outcome == 'success')" - name: "Test - \"${{ matrix.distribution2.user-id }}\" should be the default\ - \ distribution after installation" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distribution2.match-pattern }} ]]\n" - shell: "wsl-bash {0}" - - id: "execute_action5" - name: "Re-execute action" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - - if: "always() && (steps.execute_action5.outcome == 'success')" - name: "Test - \"${{ matrix.distribution2.user-id }}\" should still be the default\ - \ distribution after re-running for \"${{ matrix.distribution.user-id }}\"" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distribution2.match-pattern }} ]]\n" - shell: "wsl-bash {0}" - - id: "execute_action6" - name: "Set as default" - uses: "./" - with: - "distribution": "${{ matrix.distribution.user-id }}" - "set-as-default": "true" - - if: "always() && (steps.execute_action6.outcome == 'success')" - name: "Test - \"${{ matrix.distribution.user-id }}\" should be the default distribution\ - \ after re-running with set-as-default true" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distribution.match-pattern }} ]]\n" - shell: "wsl-bash {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distribution": - - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Alpine" - "user-id": "Alpine" - "match-pattern": "*Alpine*" - "default-absent-tool": "dos2unix" - - "wsl-id": "kali-linux" - "user-id": "kali-linux" - "match-pattern": "*Kali*" - "default-absent-tool": "dos2unix" - - "wsl-id": "openSUSE-Leap-15.2" - "user-id": "openSUSE-Leap-15.2" - "match-pattern": "*openSUSE*Leap*15.2*" - "default-absent-tool": "which" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-22.04" - "match-pattern": "*Ubuntu*22.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - - "wsl-id": "Ubuntu-16.04" - "user-id": "Ubuntu-16.04" - "match-pattern": "*Ubuntu*16.04*" - "default-absent-tool": "dos2unix" - "distribution2": - - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "exclude": - - "environment": "windows-2019" - "distribution": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "environment": "windows-2022" - "distribution": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - - "environment": "windows-latest" - "distribution": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "include": - - "environment": "windows-2019" - "distribution": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "environment": "windows-2022" - "distribution": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - - "environment": "windows-latest" - "distribution": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - fail-fast: false - "test_distribution_specific_wsl_bash_scripts": - name: "Test distribution specific wsl-bash scripts on ${{ matrix.environment }}" - needs: "build" - runs-on: "${{ matrix.environment }}" - steps: - - name: "Restore built artifacts from cache" - uses: "actions/cache@v2" - with: - "path": "action.yml\nbuild/distributions/\n" - "key": "${{ github.run_id }}" - - id: "execute_action1" - name: "Execute action for ${{ matrix.distributions.distribution1.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution1.user-id }}" - - id: "execute_action2" - name: "Execute action for ${{ matrix.distributions.distribution2.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution2.user-id }}" - "additional-packages": "bash" - - id: "execute_action3" - name: "Execute action for ${{ matrix.distributions.distribution3.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution3.user-id }}" - "set-as-default": "false" - - id: "execute_action4" - name: "Execute action for ${{ matrix.distributions.distribution4.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution4.user-id }}" - "set-as-default": "false" - - id: "execute_action5" - name: "Execute action for ${{ matrix.distributions.distribution5.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution5.user-id }}" - "set-as-default": "false" - - id: "execute_action6" - name: "Execute action for ${{ matrix.distributions.distribution6.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution6.user-id }}" - "set-as-default": "false" - - id: "execute_action7" - name: "Execute action for ${{ matrix.distributions.distribution7.user-id }}" - uses: "./" - with: - "distribution": "${{ matrix.distributions.distribution7.user-id }}" - "set-as-default": "false" - - if: "always() && (steps.execute_action1.outcome == 'success')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution1.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution1.match-pattern }} ]]\n" - shell: "wsl-bash_Debian {0}" - - if: "always() && (steps.execute_action2.outcome == 'success')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution2.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution2.match-pattern }} ]]\n" - shell: "wsl-bash_Alpine {0}" - - if: "always() && (steps.execute_action3.outcome == 'success')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution3.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution3.match-pattern }} ]]\n" - shell: "wsl-bash_kali-linux {0}" - - if: "always() && (steps.execute_action4.outcome == 'success')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution4.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution4.match-pattern }} ]]\n" - shell: "wsl-bash_openSUSE-Leap-15.2 {0}" - - if: "always() && (steps.execute_action5.outcome == 'success') && (matrix.distributions.distribution5.user-id\ - \ == 'Ubuntu-22.04')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution5.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution5.match-pattern }} ]]\n" - shell: "wsl-bash_Ubuntu-22.04 {0}" - - if: "always() && (steps.execute_action5.outcome == 'success') && (matrix.distributions.distribution5.user-id\ - \ == 'Ubuntu-20.04')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution5.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution5.match-pattern }} ]]\n" - shell: "wsl-bash_Ubuntu-20.04 {0}" - - if: "always() && (steps.execute_action6.outcome == 'success')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution6.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution6.match-pattern }} ]]\n" - shell: "wsl-bash_Ubuntu-18.04 {0}" - - if: "always() && (steps.execute_action7.outcome == 'success')" - name: "Test - wsl-bash_${{ matrix.distributions.distribution7.user-id }} should\ - \ use the correct distribution" - run: "cat <(lsb_release -a || true) <(uname -a || true) <([ -d /etc ] && find\ - \ /etc -maxdepth 1 -type f \\( -name '*release' -or -name 'issue*' \\) -exec\ - \ cat {} + || true) <([ -d /etc/products.d ] && find /etc/products.d -maxdepth\ - \ 1 -type f -name '*.prod' -exec cat {} + || true) <([ -f /proc/version ]\ - \ && cat /proc/version || true)\n[[ \"$(cat <(lsb_release -a || true) <(uname\ - \ -a || true) <([ -d /etc ] && find /etc -maxdepth 1 -type f \\( -name '*release'\ - \ -or -name 'issue*' \\) -exec cat {} + || true) <([ -d /etc/products.d ]\ - \ && find /etc/products.d -maxdepth 1 -type f -name '*.prod' -exec cat {}\ - \ + || true) <([ -f /proc/version ] && cat /proc/version || true))\" == ${{\ - \ matrix.distributions.distribution7.match-pattern }} ]]\n" - shell: "wsl-bash_Ubuntu-16.04 {0}" - strategy: - matrix: - "environment": - - "windows-2019" - - "windows-2022" - - "windows-latest" - "distributions": - - "distribution1": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Alpine" - "user-id": "Alpine" - "match-pattern": "*Alpine*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "kali-linux" - "user-id": "kali-linux" - "match-pattern": "*Kali*" - "default-absent-tool": "dos2unix" - "distribution4": - "wsl-id": "openSUSE-Leap-15.2" - "user-id": "openSUSE-Leap-15.2" - "match-pattern": "*openSUSE*Leap*15.2*" - "default-absent-tool": "which" - "distribution5": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-20.04" - "match-pattern": "*Ubuntu*20.04*" - "default-absent-tool": "dos2unix" - "distribution6": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - "distribution7": - "wsl-id": "Ubuntu-16.04" - "user-id": "Ubuntu-16.04" - "match-pattern": "*Ubuntu*16.04*" - "default-absent-tool": "dos2unix" - - "distribution1": - "wsl-id": "Debian" - "user-id": "Debian" - "match-pattern": "*Debian*" - "default-absent-tool": "dos2unix" - "distribution2": - "wsl-id": "Alpine" - "user-id": "Alpine" - "match-pattern": "*Alpine*" - "default-absent-tool": "dos2unix" - "distribution3": - "wsl-id": "kali-linux" - "user-id": "kali-linux" - "match-pattern": "*Kali*" - "default-absent-tool": "dos2unix" - "distribution4": - "wsl-id": "openSUSE-Leap-15.2" - "user-id": "openSUSE-Leap-15.2" - "match-pattern": "*openSUSE*Leap*15.2*" - "default-absent-tool": "which" - "distribution5": - "wsl-id": "Ubuntu" - "user-id": "Ubuntu-22.04" - "match-pattern": "*Ubuntu*22.04*" - "default-absent-tool": "dos2unix" - "distribution6": - "wsl-id": "Ubuntu-18.04" - "user-id": "Ubuntu-18.04" - "match-pattern": "*Ubuntu*18.04*" - "default-absent-tool": "dos2unix" - "distribution7": - "wsl-id": "Ubuntu-16.04" - "user-id": "Ubuntu-16.04" - "match-pattern": "*Ubuntu*16.04*" - "default-absent-tool": "dos2unix" - fail-fast: false \ No newline at end of file diff --git a/.github/workflows/validate-gradle-wrapper.main.kts b/.github/workflows/validate-gradle-wrapper.main.kts new file mode 100755 index 00000000..6af6b9f0 --- /dev/null +++ b/.github/workflows/validate-gradle-wrapper.main.kts @@ -0,0 +1,78 @@ +#!/usr/bin/env kotlin + +/* + * Copyright 2020-2023 Björn Kautler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:DependsOn("it.krzeminski:github-actions-kotlin-dsl:0.35.0") + +import it.krzeminski.githubactions.actions.actions.CheckoutV2 +import it.krzeminski.githubactions.actions.gradle.WrapperValidationActionV1 +import it.krzeminski.githubactions.domain.RunnerType.UbuntuLatest +import it.krzeminski.githubactions.domain.triggers.PullRequest +import it.krzeminski.githubactions.domain.triggers.Push +import it.krzeminski.githubactions.dsl.workflow +import it.krzeminski.githubactions.yaml.writeToFile + +workflow( + name = "Validate Gradle Wrapper", + on = listOf( + Push(), + PullRequest() + ), + sourceFile = __FILE__.toPath() +) { + job( + id = "validate_gradle_wrapper", + name = "Validate Gradle Wrapper", + runsOn = UbuntuLatest + ) { + run( + name = "Configure Git", + command = "git config --global core.autocrlf input" + ) + uses( + name = "Checkout", + action = CheckoutV2() + ) + uses( + name = "Validate Gradle Wrapper", + action = WrapperValidationActionV1() + ) + } +}.apply { + writeToFile() + __FILE__.resolveSibling(targetFileName).apply { + writeText( + """ + |# Copyright 2020-2023 Björn Kautler + |# + |# Licensed under the Apache License, Version 2.0 (the "License"); + |# you may not use this file except in compliance with the License. + |# You may obtain a copy of the License at + |# + |# http://www.apache.org/licenses/LICENSE-2.0 + |# + |# Unless required by applicable law or agreed to in writing, software + |# distributed under the License is distributed on an "AS IS" BASIS, + |# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + |# See the License for the specific language governing permissions and + |# limitations under the License. + | + ${readText().prependIndent("|")} + """.trimMargin() + ) + } +} diff --git a/.github/workflows/validate-gradle-wrapper.yaml b/.github/workflows/validate-gradle-wrapper.yaml new file mode 100644 index 00000000..6070267f --- /dev/null +++ b/.github/workflows/validate-gradle-wrapper.yaml @@ -0,0 +1,57 @@ +# Copyright 2020-2023 Björn Kautler +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file was generated using Kotlin DSL (.github/workflows/validate-gradle-wrapper.main.kts). +# If you want to modify the workflow, please change the Kotlin file and regenerate this YAML file. +# Generated with https://github.com/krzema12/github-workflows-kt + +name: Validate Gradle Wrapper +on: + push: {} + pull_request: {} +jobs: + check_yaml_consistency: + runs-on: ubuntu-latest + steps: + - id: step-0 + name: Check out + uses: actions/checkout@v3 + - id: step-1 + name: Set up Java in proper version + uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: zulu + cache: gradle + - id: step-2 + name: Execute script + run: rm '.github/workflows/validate-gradle-wrapper.yaml' && '.github/workflows/validate-gradle-wrapper.main.kts' + - id: step-3 + name: Consistency check + run: git diff --exit-code '.github/workflows/validate-gradle-wrapper.yaml' + validate_gradle_wrapper: + name: Validate Gradle Wrapper + runs-on: ubuntu-latest + needs: + - check_yaml_consistency + steps: + - id: step-0 + name: Configure Git + run: git config --global core.autocrlf input + - id: step-1 + name: Checkout + uses: actions/checkout@v2 + - id: step-2 + name: Validate Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/validate-gradle-wrapper.yml b/.github/workflows/validate-gradle-wrapper.yml deleted file mode 100644 index 6f1db6e3..00000000 --- a/.github/workflows/validate-gradle-wrapper.yml +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2020 Björn Kautler -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: Validate Gradle Wrapper - -on: - - push - - pull_request - -jobs: - validation: - name: Validate Gradle Wrapper - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 diff --git a/build.gradle.kts b/build.gradle.kts index 38a34a06..9f65ea6a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Björn Kautler + * Copyright 2020-2023 Björn Kautler * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ plugins { net.kautler.versions net.kautler.node - net.kautler.tests + net.kautler.github_actions net.kautler.readme net.kautler.publishing } diff --git a/buildSrc/src/main/kotlin/net/kautler/dao/GitHubWorkflow.kt b/buildSrc/src/main/kotlin/net/kautler/dao/GitHubWorkflow.kt deleted file mode 100644 index 9a340d75..00000000 --- a/buildSrc/src/main/kotlin/net/kautler/dao/GitHubWorkflow.kt +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Copyright 2020-2022 Björn Kautler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.kautler.dao - -import com.charleskorn.kaml.YamlInput -import com.charleskorn.kaml.YamlList -import com.charleskorn.kaml.YamlMap -import com.charleskorn.kaml.YamlNode -import com.charleskorn.kaml.YamlScalar -import kotlinx.serialization.Decoder -import kotlinx.serialization.Encoder -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialDescriptor -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.Serializer -import kotlinx.serialization.UnionKind.CONTEXTUAL -import kotlinx.serialization.builtins.MapSerializer -import kotlinx.serialization.builtins.list -import kotlinx.serialization.builtins.nullable -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.builtins.set -import kotlinx.serialization.decodeStructure -import net.kautler.dao.GitHubWorkflow.OnDetails.OnMapSerializer -import net.kautler.util.get -import net.kautler.util.getKey -import kotlin.reflect.full.memberProperties - -@Serializable -data class GitHubWorkflow( - val name: String? = null, - @Serializable(with = OnMapSerializer::class) - val on: Map, - val env: Map? = null, - val defaults: Defaults? = null, - val jobs: MutableMap -) { - sealed class OnDetails { - interface OnTypedEventDetails { - val types: List? - } - - interface OnBranchEventDetails { - val branches: List? - - @SerialName("branches-ignore") - val branchesIgnore: List? - } - - @Serializable - data class OnEventDetails( - override val types: List? = null - ) : OnDetails(), OnTypedEventDetails - - @Serializable - data class OnPushOrPullRequestEventDetails( - override val types: List? = null, - override val branches: List? = null, - override val branchesIgnore: List? = null, - val tags: List? = null, - @SerialName("tags-ignore") - val tagsIgnore: List? = null, - val paths: List? = null, - @SerialName("paths-ignore") - val pathsIgnore: List? = null - ) : OnDetails(), OnTypedEventDetails, OnBranchEventDetails - - @Serializable - data class OnWorkflowRunEventDetails( - override val types: List? = null, - val workflows: List? = null, - override val branches: List? = null, - override val branchesIgnore: List? = null - ) : OnDetails(), OnTypedEventDetails, OnBranchEventDetails - - @Serializable - data class OnScheduleDetails( - val schedules: List - ) : OnDetails() - - @Serializable - data class Schedule( - val cron: String - ) - - @Serializer(forClass = OnDetails::class) - companion object : KSerializer { - override val descriptor = - SerialDescriptor("net.kautler.dao.GitHubWorkflow.OnDetails", CONTEXTUAL) - - override fun deserialize(decoder: Decoder): OnDetails? { - check(decoder is YamlInput) { "This class can only be loaded using kaml" } - - val context = decoder.node - check(context is YamlMap) { "Expected a YamlMap as current context" } - - return decoder.decodeStructure(descriptor) { - this as YamlInput - when (context.getKey(node)) { - "push", "pull_request" -> decodeSerializableValue(OnPushOrPullRequestEventDetails.serializer()) - "workflow_run" -> decodeSerializableValue(OnWorkflowRunEventDetails.serializer()) - "schedule" -> OnScheduleDetails(decodeSerializableValue(Schedule.serializer().list)) - else -> decodeSerializableValue(OnEventDetails.serializer()) - } - } - } - - override fun serialize(encoder: Encoder, value: OnDetails?) { - when (value) { - is OnPushOrPullRequestEventDetails -> - encoder.encodeSerializableValue(OnPushOrPullRequestEventDetails.serializer(), value) - - is OnWorkflowRunEventDetails -> - encoder.encodeSerializableValue(OnWorkflowRunEventDetails.serializer(), value) - - is OnScheduleDetails -> - encoder.encodeSerializableValue(Schedule.serializer().list, value.schedules) - - is OnEventDetails -> - encoder.encodeSerializableValue(OnEventDetails.serializer(), value) - } - } - } - - @Serializer(forClass = Map::class) - class OnMapSerializer( - private val keySerializer: KSerializer, - private val valueSerializer: KSerializer - ) : KSerializer> { - override val descriptor = - SerialDescriptor("net.kautler.dao.GitHubWorkflow.on", CONTEXTUAL) - - override fun deserialize(decoder: Decoder): Map { - check(decoder is YamlInput) { "This class can only be loaded using kaml" } - - val context = decoder.node - check(context is YamlMap) { "Expected a YamlMap as current context" } - - return when (val onValueNode: YamlNode = context["on"]!!) { - is YamlScalar -> decoder.decodeStructure(String.serializer().descriptor) { - this as YamlInput - mapOf(decodeString() to null) - } - - is YamlList -> decoder.decodeStructure(String.serializer().list.descriptor) { - check(onValueNode.items.all { it is YamlScalar }) { "Invalid on value list content" } - this as YamlInput - decodeSerializableValue(String.serializer().list) - .map { it to null } - .toMap() - } - - is YamlMap -> decoder.decodeSerializableValue(MapSerializer(keySerializer, valueSerializer)) - - else -> error("Unexpected type for on value: ${onValueNode::class}") - } - } - - override fun serialize(encoder: Encoder, value: Map) { - when { - (value.size == 1) && value.values.all { it == null } -> - encoder.encodeString(value.entries.first().key) - - (value.size > 1) && value.values.all { it == null } -> - encoder.encodeSerializableValue(String.serializer().set, value.keys) - - else -> encoder.encodeSerializableValue(MapSerializer(keySerializer, valueSerializer), value) - } - } - } - } - - @Serializable - data class Defaults( - val run: RunDefaults? = null - ) - - @Serializable - data class RunDefaults( - val shell: String? = null, - @SerialName("working-directory") - val workingDirectory: String? = null - ) - - @Serializable - data class Job( - val name: String? = null, - @Serializable(with = NeedsSerializer::class) - val needs: List? = null, - @Serializable(with = RunsOnSerializer::class) - @SerialName("runs-on") - val runsOn: List, - val outputs: Map? = null, - val env: Map? = null, - val defaults: Defaults? = null, - @SerialName("if") - val ifCondition: String? = null, - val steps: List, - @SerialName("timeout-minutes") - val timeoutMinutes: Long? = null, - val strategy: Strategy? = null, - @SerialName("continue-on-error") - val continueOnError: Boolean? = null, - @Serializable(with = ContainerSerializer::class) - val container: Container? = null, - val services: Map? = null - ) { - @Serializer(forClass = List::class) - class NeedsSerializer(private val elementSerializer: KSerializer) : KSerializer> { - override val descriptor = - SerialDescriptor("net.kautler.dao.GitHubWorkflow.Job.needs", CONTEXTUAL) - - override fun deserialize(decoder: Decoder): List { - check(decoder is YamlInput) { "This class can only be loaded using kaml" } - - val context = decoder.node - check(context is YamlMap) { "Expected a YamlMap as current context" } - - return when (val needsValueNode: YamlNode = context["needs"]!!) { - is YamlScalar -> decoder.decodeStructure(elementSerializer.descriptor) { - this as YamlInput - listOf(decodeString()) - } - - is YamlList -> decoder.decodeStructure(elementSerializer.list.descriptor) { - check(needsValueNode.items.all { it is YamlScalar }) { "Invalid needs value list content" } - this as YamlInput - decodeSerializableValue(elementSerializer.list) - } - - else -> error("Unexpected type for needs value: ${needsValueNode::class}") - } - } - - override fun serialize(encoder: Encoder, value: List) { - if (value.size == 1) { - encoder.encodeString(value.first()) - } else { - encoder.encodeSerializableValue(elementSerializer.list, value) - } - } - } - - @Serializer(forClass = List::class) - class RunsOnSerializer(private val elementSerializer: KSerializer) : KSerializer> { - override val descriptor = - SerialDescriptor("net.kautler.dao.GitHubWorkflow.Job.runsOn", CONTEXTUAL) - - override fun deserialize(decoder: Decoder): List { - check(decoder is YamlInput) { "This class can only be loaded using kaml" } - - val context = decoder.node - check(context is YamlMap) { "Expected a YamlMap as current context" } - - return when (val runsOnValueNode: YamlNode = context["runs-on"]!!) { - is YamlScalar -> decoder.decodeStructure(elementSerializer.descriptor) { - this as YamlInput - listOf(decodeString()) - } - - is YamlList -> decoder.decodeStructure(elementSerializer.list.descriptor) { - check(runsOnValueNode.items.all { it is YamlScalar }) { "Invalid runs-on value list content" } - this as YamlInput - decodeSerializableValue(elementSerializer.list) - } - - else -> error("Unexpected type for runs-on value: ${runsOnValueNode::class}") - } - } - - override fun serialize(encoder: Encoder, value: List) { - if (value.size == 1) { - encoder.encodeString(value.first()) - } else { - encoder.encodeSerializableValue(elementSerializer.list, value) - } - } - } - - @Serializer(forClass = Container::class) - object ContainerSerializer : KSerializer { - override val descriptor = - SerialDescriptor("net.kautler.dao.GitHubWorkflow.Job.container", CONTEXTUAL) - - override fun deserialize(decoder: Decoder): Container { - check(decoder is YamlInput) { "This class can only be loaded using kaml" } - - val context = decoder.node - check(context is YamlMap) { "Expected a YamlMap as current context" } - - return when (val containerValueNode: YamlNode = context["container"]!!) { - is YamlScalar -> decoder.decodeStructure(String.serializer().descriptor) { - this as YamlInput - Container(decodeString()) - } - - is YamlMap -> decoder.decodeSerializableValue(Container.serializer()) - - else -> error("Unexpected type for container value: ${containerValueNode::class}") - } - } - - override fun serialize(encoder: Encoder, value: Container) { - if (Container::class.memberProperties.filter { it.name != "image" }.all { it.get(value) == null }) { - encoder.encodeString(value.image) - } else { - encoder.encodeSerializableValue(Container.serializer(), value) - } - } - } - } - - @Serializable - data class Step( - val id: String? = null, - @SerialName("if") - val ifCondition: String? = null, - val name: String? = null, - val uses: String? = null, - val run: String? = null, - val shell: String? = null, - @SerialName("working-directory") - val workingDirectory: String? = null, - val with: Map? = null, - val env: Map? = null, - @SerialName("continue-on-error") - val continueOnError: Boolean? = null, - @SerialName("timeout-minutes") - val timeoutMinutes: Long? = null - ) - - @Serializable - data class Strategy( - val matrix: Map? = null, - @SerialName("fail-fast") - val failFast: Boolean? = null, - @SerialName("max-parallel") - val maxParallel: Long? = null - ) { - sealed class MatrixValue { - class MatrixVariable( - val value: List - ) : MatrixValue() - - class MatrixIncludeOrExclude( - val value: List> - ) : MatrixValue() - - @Serializer(forClass = MatrixValue::class) - companion object : KSerializer { - override val descriptor = - SerialDescriptor("net.kautler.dao.GitHubWorkflow.MatrixValue", CONTEXTUAL) - - override fun deserialize(decoder: Decoder): MatrixValue { - check(decoder is YamlInput) { "This class can only be loaded using kaml" } - - val context = decoder.node - check(context is YamlMap) { "Expected a YamlMap as current context" } - - return decoder.decodeStructure(descriptor) { - this as YamlInput - when (context.getKey(node)) { - "include", "exclude" -> MatrixIncludeOrExclude( - decodeSerializableValue( - MapSerializer(String.serializer(), MatrixLeaf).list - ) - ) - else -> MatrixVariable(decodeSerializableValue(MatrixLeaf.list)) - } - } - } - - override fun serialize(encoder: Encoder, value: MatrixValue) { - when (value) { - is MatrixVariable -> encoder.encodeSerializableValue( - MatrixLeaf.list, - value.value - ) - - is MatrixIncludeOrExclude -> encoder.encodeSerializableValue( - MapSerializer(String.serializer(), MatrixLeaf).list, - value.value - ) - } - } - } - } - - sealed class MatrixLeaf { - class MatrixMapLeaf( - val value: Map - ) : MatrixLeaf() - - class MatrixStringLeaf( - val value: String - ) : MatrixLeaf() - - @Serializer(forClass = MatrixLeaf::class) - companion object : KSerializer { - override val descriptor = - SerialDescriptor("net.kautler.dao.GitHubWorkflow.MatrixValue", CONTEXTUAL) - - override fun deserialize(decoder: Decoder): MatrixLeaf { - check(decoder is YamlInput) { "This class can only be loaded using kaml" } - - return decoder.decodeStructure(descriptor) { - this as YamlInput - when (node) { - is YamlScalar -> decodeStructure(String.serializer().descriptor) { - this as YamlInput - MatrixStringLeaf(decodeString()) - } - - is YamlMap -> MatrixMapLeaf( - decodeSerializableValue( - MapSerializer(String.serializer(), MatrixLeaf.nullable) - ) - ) - - else -> error("Unexpected type for context node: ${node::class}") - } - } - } - - override fun serialize(encoder: Encoder, value: MatrixLeaf) { - when (value) { - is MatrixMapLeaf -> encoder.encodeSerializableValue( - MapSerializer(String.serializer(), MatrixLeaf.nullable), - value.value - ) - - is MatrixStringLeaf -> encoder.encodeSerializableValue( - String.serializer(), - value.value - ) - } - } - } - } - } - - @Serializable - data class Container( - val image: String, - val env: Map? = null, - val ports: List? = null, - val volumes: List? = null, - val options: String? = null - ) -} diff --git a/buildSrc/src/main/kotlin/net/kautler/github_actions.gradle.kts b/buildSrc/src/main/kotlin/net/kautler/github_actions.gradle.kts new file mode 100644 index 00000000..acc6a4bb --- /dev/null +++ b/buildSrc/src/main/kotlin/net/kautler/github_actions.gradle.kts @@ -0,0 +1,64 @@ +/* + * Copyright 2020-2023 Björn Kautler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.kautler + +import groovy.lang.Closure + +plugins { + `java-base` +} + +val compilerClasspath by configurations.creating { + isCanBeConsumed = false +} + +val scriptClasspath by configurations.creating { + isCanBeConsumed = false +} + +dependencies { + compilerClasspath(kotlin("compiler", "1.8.0")) + compilerClasspath(kotlin("scripting-compiler", "1.8.0")) + add(scriptClasspath.name, kotlin("main-kts", "1.8.0"), closureOf { + isTransitive = false + } as Closure) +} + +val preprocessWorkflows by tasks.registering +file(".github/workflows") + .listFiles { _, name -> name.endsWith(".main.kts") }!! + .forEach { workflowScript -> + val workflowName = workflowScript.name.removeSuffix(".main.kts") + val camelCasedWorkflowName = workflowName.replace("""-\w""".toRegex()) { + it.value.substring(1).capitalize() + }.capitalize() + val preProcessWorkflow = tasks.register("preProcess${camelCasedWorkflowName}Workflow") { + inputs.file(workflowScript) + outputs.file(workflowScript.resolveSibling("$workflowName.yaml")) + javaLauncher.set(javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(17)) + }) + classpath(compilerClasspath) + mainClass.set("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler") + args("-no-stdlib", "-no-reflect") + args("-classpath", scriptClasspath.asPath) + args("-script", workflowScript.absolutePath) + } + preprocessWorkflows { + dependsOn(preProcessWorkflow) + } + } diff --git a/buildSrc/src/main/kotlin/net/kautler/tests.gradle.kts b/buildSrc/src/main/kotlin/net/kautler/tests.gradle.kts deleted file mode 100644 index 757b4d70..00000000 --- a/buildSrc/src/main/kotlin/net/kautler/tests.gradle.kts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020-2022 Björn Kautler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.kautler - -import com.charleskorn.kaml.Yaml -import com.charleskorn.kaml.YamlConfiguration -import com.charleskorn.kaml.YamlException -import net.kautler.dao.GitHubWorkflow - -tasks.register("preProcessTestWorkflow") { - val input = file(".github/workflows/template/test.yml") - val output = file(".github/workflows/test.yml") - - inputs.file(input).withPropertyName("test workflow template") - outputs.file(output).withPropertyName("test workflow file") - - doLast { - runCatching { - with(Yaml(configuration = YamlConfiguration(encodeDefaults = false))) { - val serializer = GitHubWorkflow.serializer() - val workflow = parse(serializer, input.readText()) - workflow.jobs.remove("includes") - stringify(serializer, workflow) - .also { - output.writeText( - """ - |# Copyright 2020-2022 Björn Kautler - |# - |# Licensed under the Apache License, Version 2.0 (the "License"); - |# you may not use this file except in compliance with the License. - |# You may obtain a copy of the License at - |# - |# http://www.apache.org/licenses/LICENSE-2.0 - |# - |# Unless required by applicable law or agreed to in writing, software - |# distributed under the License is distributed on an "AS IS" BASIS, - |# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - |# See the License for the specific language governing permissions and - |# limitations under the License. - | - ${it.prependIndent("|")} - """.trimMargin() - ) - } - } - }.onFailure { - // work-around for https://github.com/charleskorn/kaml/issues/36 - if (it is YamlException) { - println("Exception Location: ${it.location}") - } - throw it - } - } -} diff --git a/buildSrc/src/main/kotlin/net/kautler/util/YamlMapExtension.kt b/buildSrc/src/main/kotlin/net/kautler/util/YamlMapExtension.kt index 62584642..7b90c5ab 100644 --- a/buildSrc/src/main/kotlin/net/kautler/util/YamlMapExtension.kt +++ b/buildSrc/src/main/kotlin/net/kautler/util/YamlMapExtension.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-2022 Björn Kautler + * Copyright 2020-2023 Björn Kautler * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,11 +26,3 @@ operator fun YamlMap.get(key: String) = .asSequence() .find { (it.key as? YamlScalar)?.content == key } ?.value as T? - -fun YamlMap.getKey(value: YamlNode) = - entries - .asSequence() - .find { it.value == value } - ?.key - ?.let { it as? YamlScalar } - ?.content diff --git a/readme/README_template.md b/readme/README_template.md index b59fc530..a2dd9867 100644 --- a/readme/README_template.md +++ b/readme/README_template.md @@ -363,7 +363,7 @@ License ------- ``` -Copyright 2020-2022 Björn Kautler +Copyright 2020-2023 Björn Kautler Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From a00ad19d28a01876ca11fed9aa970ae414a9d1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Tue, 24 Jan 2023 02:38:27 +0100 Subject: [PATCH 3/4] Use wsl.exe where possible On newer Windows versions wslconfig.exe is deprecated. Instead wsl.exe got new options that can do the same work. Now it is dynamically determined whether the available wsl.exe already supports the new option or whether wslconfig.exe has to be used --- .../github/action/setup_wsl/SetupWsl.kt | 109 ++++++++++-------- 1 file changed, 63 insertions(+), 46 deletions(-) diff --git a/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt b/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt index 4bbcbf70..066ec4a9 100644 --- a/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt +++ b/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt @@ -60,6 +60,36 @@ import startGroup as coreStartGroup import warning as coreWarning import which as ioWhich +val wslHelp = GlobalScope.async(start = LAZY) { + val stdoutBuilder = StringBuilder() + val stdoutBuilderUtf16Le = StringBuilder() + val stderrBuilder = StringBuilder() + val stderrBuilderUtf16Le = StringBuilder() + exec( + commandLine = "wsl", + args = arrayOf("--help"), + options = jsObject { + ignoreReturnCode = true + outStream = NullWritable() + errStream = NullWritable() + listeners = jsObject { + stdout = { + stdoutBuilder.append(it) + stdoutBuilderUtf16Le.append(it.toString("UTF-16LE")) + } + stderr = { + stderrBuilder.append(it) + stderrBuilderUtf16Le.append(it.toString("UTF-16LE")) + } + } + } + ).await() + stdoutBuilder.append(stdoutBuilderUtf16Le) + stdoutBuilder.append(stderrBuilder) + stdoutBuilder.append(stderrBuilderUtf16Le) + stdoutBuilder.toString() +} + val distribution by lazy { val distributionId = coreGetInput("distribution", jsObject { required = true @@ -74,10 +104,10 @@ val distribution by lazy { val wslId = GlobalScope.async(start = LAZY) { if (coreIsDebug()) { - exec( - commandLine = "wslconfig", - args = arrayOf("/list") - ).await() + executeWslCommand( + wslArguments = arrayOf("--list"), + wslconfigArguments = arrayOf("/list") + ) } distribution.wslId } @@ -266,6 +296,23 @@ suspend fun main() { } } +suspend fun executeWslCommand( + wslArguments: Array, + wslconfigArguments: Array? = null +) { + if (wslHelp().contains(wslArguments.first())) { + exec( + commandLine = "wsl", + args = wslArguments + ).await() + } else if (wslconfigArguments != null) { + exec( + commandLine = "wslconfig", + args = wslconfigArguments + ).await() + } +} + suspend fun group(name: String, fn: suspend () -> T): T { coreStartGroup(name) try { @@ -279,45 +326,15 @@ suspend fun verifyWindowsEnvironment() { check(process.platform == "win32") { "platform '${process.platform}' is not supported by this action, please verify your 'runs-on' setting" } - check(ioWhich("wslconfig").await().isNotBlank()) { + check(ioWhich("wsl").await().isNotBlank() || ioWhich("wslconfig").await().isNotBlank()) { "This Windows environment does not have WSL enabled, please verify your 'runs-on' setting" } } suspend fun installDistribution() { - val stdoutBuilder = StringBuilder() - val stdoutBuilderUtf16Le = StringBuilder() - val stderrBuilder = StringBuilder() - val stderrBuilderUtf16Le = StringBuilder() - exec( - commandLine = "wsl", - args = arrayOf("--help"), - options = jsObject { - ignoreReturnCode = true - outStream = NullWritable() - errStream = NullWritable() - listeners = jsObject { - stdout = { - stdoutBuilder.append(it) - stdoutBuilderUtf16Le.append(it.toString("UTF-16LE")) - } - stderr = { - stderrBuilder.append(it) - stderrBuilderUtf16Le.append(it.toString("UTF-16LE")) - } - } - } - ).await() - stdoutBuilder.append(stdoutBuilderUtf16Le) - stdoutBuilder.append(stderrBuilder) - stdoutBuilder.append(stderrBuilderUtf16Le) - if (stdoutBuilder.toString().contains("--set-default-version")) { - exec( - commandLine = "wsl", - args = arrayOf("--set-default-version", "1") - ).await() - } - + executeWslCommand( + wslArguments = arrayOf("--set-default-version", "1") + ) exec( commandLine = """"${path.join(distributionDirectory(), distribution.installerFile)}"""", args = arrayOf("install", "--root"), @@ -335,17 +352,17 @@ suspend fun createWslConf() { "sh", "-c", "echo '$wslConf' >/etc/wsl.conf" ) ).await() - exec( - commandLine = "wslconfig", - args = arrayOf("/terminate", wslId()) - ).await() + executeWslCommand( + wslArguments = arrayOf("--terminate", wslId()), + wslconfigArguments = arrayOf("/terminate", wslId()) + ) } suspend fun setDistributionAsDefault() { - exec( - commandLine = "wslconfig", - args = arrayOf("/setdefault", wslId()) - ).await() + executeWslCommand( + wslArguments = arrayOf("--set-default", wslId()), + wslconfigArguments = arrayOf("/setdefault", wslId()) + ) } suspend fun writeWslShellWrapper() { From c6e8c2adf73adf268e62e5151ad1d6086318e3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Tue, 24 Jan 2023 10:28:36 +0100 Subject: [PATCH 4/4] Rename archives to .zip to make extraction work on old PowerShell versions (#43) --- .../net/kautler/github/action/setup_wsl/SetupWsl.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt b/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt index 066ec4a9..d4ec38ea 100644 --- a/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt +++ b/src/main/kotlin/net/kautler/github/action/setup_wsl/SetupWsl.kt @@ -52,6 +52,7 @@ import getInput as coreGetInput import isDebug as coreIsDebug import isFeatureAvailable as cacheIsFeatureAvailable import mkdirP as ioMkdirP +import mv as ioMv import restoreCache as cacheRestoreCache import saveCache as cacheSaveCache import setFailed as coreSetFailed @@ -177,13 +178,13 @@ val distributionDirectory = GlobalScope.async(start = LAZY) { } val distributionDownload = toolCacheDownloadTool("${distribution.downloadUrl()}").await() - var extractedDistributionDirectory = toolCacheExtractZip(distributionDownload).await() + var extractedDistributionDirectory = extractZip(distributionDownload) if (!existsSync(path.join(extractedDistributionDirectory, distribution.installerFile))) { extractedDistributionDirectory = readdirSync(extractedDistributionDirectory, jsObject<`T$35`>()) .asFlow() .filter { it.contains("""(?, wslconfigArguments: Array? = null