diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..db185c1d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +{ + "name": "CmdLine dev container", + "dockerComposeFile": [ + "../dev/docker-compose.yml" + ], + "service": "cmdline-dev", + "workspaceFolder": "/app", + "extensions": [ + "ms-dotnettools.csharp", + "josefpihrt-vscode.roslynator", + "formulahendry.dotnet-test-explorer", + "fernandoescolar.vscode-solution-explorer", + "eamodio.gitlens", + "ms-vscode.powershell", + "shd101wyy.markdown-preview-enhanced" + ], + "remoteUser": "developer", + "shutdownAction": "stopCompose" +} \ No newline at end of file diff --git a/dev/Dockerfile b/dev/Dockerfile new file mode 100644 index 00000000..ae1fde8d --- /dev/null +++ b/dev/Dockerfile @@ -0,0 +1,27 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 + +# Install missing 'ps' command that some VS Code extensions depend on: +RUN apt-get update +RUN apt-get install -y procps + +RUN groupadd -g 1000 -r devloper && \ + useradd -u 1000 -r -g devloper -m -s $(which bash) devloper +# Option '-m' to create home directory (see https://askubuntu.com/a/393470) +# Option '-s' to set shell for this user (see comment in https://askubuntu.com/a/393470) +# Option '-r' creates a system user which does not expire +# (see https://linuxize.com/post/how-to-create-users-in-linux-using-the-useradd-command/) + +# Create working directory. Ownership will be changed in entrypoint.sh which +# executes *after* the volume has been mounted. +RUN mkdir /app + +# Copy entrypoint script into container, make it executable, then execute it: +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] + +# Install dotnet-outdated (see https://github.com/dotnet-outdated/dotnet-outdated) +RUN runuser -l devloper -c "dotnet tool install --global dotnet-outdated-tool" +# runuser installs it as if the non-root user was installing it. This makes +# it available to that non-root user +ENV PATH "$PATH:/home/devloper/.dotnet/tools" \ No newline at end of file diff --git a/dev/docker-compose.yaml b/dev/docker-compose.yaml new file mode 100644 index 00000000..083ff108 --- /dev/null +++ b/dev/docker-compose.yaml @@ -0,0 +1,21 @@ +version: '3.7' + +services: + cmdline-dev: + build: + context: . + working_dir: /app + volumes: + - "..:/app" + depends_on: + - database + command: > + bash -c "pwsh /app/dev/init.ps1 && sleep infinity" + + database: + image: mcr.microsoft.com/mssql/server + environment: + - ACCEPT_EULA=Y + - SA_PASSWORD=PassWord42 + ports: + - 7610:1433 \ No newline at end of file diff --git a/dev/entrypoint.sh b/dev/entrypoint.sh new file mode 100644 index 00000000..d698241a --- /dev/null +++ b/dev/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# Change ownership of all directories and files in the mounted volume, i.e. +# what has been mapped from the host: +chown -R devloper:devloper /app + +# Finally invoke what has been specified as CMD in Dockerfile or command in docker-compose: +"$@" \ No newline at end of file diff --git a/dev/init.ps1 b/dev/init.ps1 new file mode 100644 index 00000000..7d067474 --- /dev/null +++ b/dev/init.ps1 @@ -0,0 +1,27 @@ +#requires -PSEdition Core +# Additional steps to initialize the development container + +# Install sqlserver module so we can use 'Invoke-Sqlcmd' +Install-Module sqlserver -Confirm:$False -Force + +# Create new database +# Source for the retry logic: +# https://stackoverflow.com/a/47712807/411428 +$attempts=20 +$sleepInSeconds=3 +do +{ + try + { + Invoke-Sqlcmd -ServerInstance "database,1433" -Username SA -Password PassWord42 -Query "CREATE DATABASE [mahi-cmdline]"; + Write-Host "Database mahi-cmdline created successfully." + break; + } + catch [Exception] + { + #Write-Host $_.Exception.Message + Write-Host "Retrying..." + } + $attempts-- + if ($attempts -gt 0) { Start-Sleep $sleepInSeconds } +} while ($attempts -gt 0) \ No newline at end of file