name: "PR - Test Updated Templates" on: pull_request: permissions: contents: read jobs: detect-changes: runs-on: ubuntu-latest outputs: templates: ${{ steps.filter.outputs.changes }} steps: - uses: dorny/paths-filter@v3 id: filter with: filters: | alpine: ./**/alpine/** anaconda: ./**/anaconda/** anaconda-postgres: ./**/anaconda-postgres/** cpp: ./**/cpp/** cpp-mariadb: ./**/cpp-mariadb/** debian: ./**/debian/** docker-outside-of-docker: ./**/docker-outside-of-docker/** docker-outside-of-docker-compose: ./**/docker-outside-of-docker-compose/** docker-in-docker: ./**/docker-in-docker/** dotnet: ./**/dotnet/** dotnet-fsharp: ./**/dotnet-fsharp/** dotnet-mssql: ./**/dotnet-mssql/** dotnet-postgres: ./**/dotnet-postgres/** go: ./**/go/** go-postgres: ./**/go-postgres/** java: ./**/java/** java-postgres: ./**/java-postgres/** javascript-node: ./**/javascript-node/** javascript-node-mongo: ./**/javascript-node-mongo/** javascript-node-postgres: ./**/javascript-node-postgres/** jekyll: ./**/jekyll/** kubernetes-helm-minikube: ./**/kubernetes-helm-minikube/** markdown: ./**/markdown/** miniconda: ./**/miniconda/** miniconda-postgres: ./**/miniconda-postgres/** php: ./**/php/** php-mariadb: ./**/php-mariadb/** postgres: ./**/postgres/** powershell: ./**/powershell/** python: ./**/python/** ruby: ./**/ruby/** ruby-rails-postgres: ./**/ruby-rails-postgres/** rust: ./**/rust/** rust-postgres: ./**/rust-postgres/** typescript-node: ./**/typescript-node/** ubuntu: ./**/ubuntu/** universal: ./**/universal/** test: needs: [detect-changes] runs-on: ubuntu-latest continue-on-error: true strategy: matrix: templates: ${{ fromJSON(needs.detect-changes.outputs.templates) }} steps: - uses: actions/checkout@v5 - name: "Install latest devcontainer CLI" run: npm install -g @devcontainers/cli - name: "Generating tests for '${{ matrix.templates }}'" run: echo "${{ matrix.templates }}" - name: Configure template run: | set -e cd src/${{ matrix.templates }} # Configure templates only if `devcontainer-template.json` contains the `options` property. optionProp=( $(jq -r '.options' devcontainer-template.json) ) if [ "${optionProp}" != "" ] && [ "${optionProp}" != "null" ] ; then options=( $(jq -r '.options | keys[]' devcontainer-template.json) ) if [ "${options[0]}" != "" ] && [ "${options[0]}" != "null" ] ; then echo "(!) Configuring template options within 'src/${{ matrix.templates }}' folder" for option in "${options[@]}" do option_key="\${templateOption:$option}" option_value=$(jq -r ".options | .${option} | .default" devcontainer-template.json) if [ "${option_value}" = "" ] || [ "${option_value}" = "null" ] ; then echo "Template '${{ matrix.templates }}' is missing a default value for option '${option}'" exit 1 fi echo "(!) Replacing '${option_key}' with '${option_value}'" option_value_escaped=$(sed -e 's/[]\/$*.^[]/\\&/g' <<<"${option_value}") find ./ -type f -print0 | xargs -0 sed -i "s/${option_key}/${option_value_escaped}/g" done fi fi - name: Run Smoke Test run: | template_id="${{ matrix.templates }}" src_dir="test/${template_id}" if [ ! -d "$(pwd)/${src_dir}" ] ; then echo "Template '${{ matrix.templates }}' is missing a test folder" exit 1 fi dest_dir="src/${template_id}/test-project" mkdir -p ${dest_dir} shopt -s dotglob cp -Rp ${src_dir}/* ${dest_dir} cp test/test-utils/test-utils.sh ${dest_dir} echo "Building dev container" id_label="test-container=${template_id}" devcontainer up --id-label ${id_label} --workspace-folder "src/${template_id}/" # Fake out existence of extensions, VS Code Server to validate extensions echo "(*) Stubbing out extensions and VS Code Server..." # Configuring path for 'devcontainer.json' dev_container_relative_path="src/${template_id}" dev_container_json_name=".devcontainer.json" if [ -d "$(pwd)/${dev_container_relative_path}/.devcontainer" ] ; then dev_container_relative_path="${dev_container_relative_path}/.devcontainer" dev_container_json_name="devcontainer.json" fi mkdir -p "/tmp/${dev_container_relative_path}" cp -f "$(pwd)/${dev_container_relative_path}/${dev_container_json_name}" "/tmp/${dev_container_relative_path}/" dev_container_tmp="/tmp/${dev_container_relative_path}/${dev_container_json_name}" sed -i'.bak' -e "s/\\/\\/.*/ /g" "${dev_container_tmp}" # Fetching extensions list defined in 'devcontainer.json' extensions="$(jq '.extensions' --compact-output "${dev_container_tmp}" | tr -d '[' | tr -d ']' | tr ',' '\n' 2>/dev/null || echo -n '')" # Stubbing extensions list for the tests validation with checkExtension() devcontainer exec --workspace-folder "src/${template_id}/" --id-label ${id_label} /bin/sh -c "\ mkdir -p \$HOME/.vscode-server/bin \$HOME/.vscode-server/extensions \ && cd \$HOME/.vscode-server/extensions \ && if [ \"${extensions}\" != '' ]; then echo \"${extensions}\" | xargs -n 1 mkdir -p; fi \ && find \$HOME/.vscode-server/ -type d" echo "Running Smoke Test" devcontainer exec --workspace-folder "src/${template_id}/" --id-label ${id_label} /bin/sh -c 'set -e && if [ -f "test-project/test.sh" ]; then cd test-project && if [ "$(id -u)" = "0" ]; then chmod +x test.sh; else sudo chmod +x test.sh; fi && ./test.sh; else ls -a; fi' # Clean up docker rm -f $(docker container ls -f "label=${id_label}" -q)