From 1e65107798f8828eef9479acd768519da51cc537 Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Tue, 14 Nov 2023 09:10:30 -0600 Subject: [PATCH 1/4] Document version numbers --- README.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.markdown b/README.markdown index a73b4cd..821ccee 100644 --- a/README.markdown +++ b/README.markdown @@ -2,8 +2,8 @@ This Docker image provides a Haskell development environment with the following tools: -- [GHCup](https://www.haskell.org/ghcup/) -- [GHC](https://www.haskell.org/ghc/) -- [Cabal](https://www.haskell.org/cabal/) -- [Stack](https://docs.haskellstack.org/en/stable/) -- [HLS](https://haskell-language-server.readthedocs.io/en/latest/) +- [GHCup](https://www.haskell.org/ghcup/) version 0.1.20.0 +- [GHC](https://www.haskell.org/ghc/) version 9.8.1, 9.6.3, or 9.4.7 +- [Cabal](https://www.haskell.org/cabal/) version 3.10.2.0 +- [Stack](https://docs.haskellstack.org/en/stable/) version 2.13.1 +- [HLS](https://haskell-language-server.readthedocs.io/en/latest/) version 2.4.0.0 From 8227749ab28facb8fa9d88fbfa4d9cd2940cdb5c Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Tue, 14 Nov 2023 09:16:45 -0600 Subject: [PATCH 2/4] Format YAML as JSON --- .github/dependabot.yaml | 18 ++-- .github/workflows/workflow.yaml | 152 ++++++++++++++++++++------------ aws/image.yaml | 59 ++++++------- aws/manifest.yaml | 53 +++++------ 4 files changed, 159 insertions(+), 123 deletions(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 253bcb7..21b7b48 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -1,6 +1,12 @@ -version: 2 -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: daily +{ + "version": 2, + "updates": [ + { + "package-ecosystem": "github-actions", + "directory": "/", + "schedule": { + "interval": "daily" + } + } + ] +} diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index 4644890..54104a5 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -1,56 +1,96 @@ -name: Workflow -on: push -jobs: - image: - strategy: - fail-fast: false - matrix: - include: - - { arch: amd64, ghc: 9.4.7 } - - { arch: amd64, ghc: 9.6.3 } - - { arch: amd64, ghc: 9.8.1 } - - { arch: arm64, ghc: 9.4.7 } - - { arch: arm64, ghc: 9.6.3 } - - { arch: arm64, ghc: 9.8.1 } - runs-on: ubuntu-latest - steps: - - - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-region: ${{ secrets.AWS_DEFAULT_REGION }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - - uses: aws-actions/aws-codebuild-run-build@v1 - with: - project-name: docker-haskell-${{ matrix.arch }} - buildspec-override: aws/image.yaml - env-vars-for-codebuild: GHC_VERSION - env: - GHC_VERSION: ${{ matrix.ghc }} - - manifest: - needs: image - strategy: - matrix: - ghc: - - 9.4.7 - - 9.6.3 - - 9.8.1 - runs-on: ubuntu-latest - steps: - - - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-region: ${{ secrets.AWS_DEFAULT_REGION }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - - uses: aws-actions/aws-codebuild-run-build@v1 - with: - project-name: docker-haskell-amd64 - buildspec-override: aws/manifest.yaml - env-vars-for-codebuild: GHC_VERSION,LATEST - env: - GHC_VERSION: ${{ matrix.ghc }} - LATEST: ${{ github.ref == 'refs/heads/main' }} +{ + "name": "Workflow", + "on": "push", + "jobs": { + "image": { + "strategy": { + "fail-fast": false, + "matrix": { + "include": [ + { + "arch": "amd64", + "ghc": "9.4.7" + }, + { + "arch": "amd64", + "ghc": "9.6.3" + }, + { + "arch": "amd64", + "ghc": "9.8.1" + }, + { + "arch": "arm64", + "ghc": "9.4.7" + }, + { + "arch": "arm64", + "ghc": "9.6.3" + }, + { + "arch": "arm64", + "ghc": "9.8.1" + } + ] + } + }, + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "aws-actions/configure-aws-credentials@v4", + "with": { + "aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}", + "aws-region": "${{ secrets.AWS_DEFAULT_REGION }}", + "aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}" + } + }, + { + "uses": "aws-actions/aws-codebuild-run-build@v1", + "with": { + "project-name": "docker-haskell-${{ matrix.arch }}", + "buildspec-override": "aws/image.yaml", + "env-vars-for-codebuild": "GHC_VERSION" + }, + "env": { + "GHC_VERSION": "${{ matrix.ghc }}" + } + } + ] + }, + "manifest": { + "needs": "image", + "strategy": { + "matrix": { + "ghc": [ + "9.4.7", + "9.6.3", + "9.8.1" + ] + } + }, + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "aws-actions/configure-aws-credentials@v4", + "with": { + "aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}", + "aws-region": "${{ secrets.AWS_DEFAULT_REGION }}", + "aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}" + } + }, + { + "uses": "aws-actions/aws-codebuild-run-build@v1", + "with": { + "project-name": "docker-haskell-amd64", + "buildspec-override": "aws/manifest.yaml", + "env-vars-for-codebuild": "GHC_VERSION,LATEST" + }, + "env": { + "GHC_VERSION": "${{ matrix.ghc }}", + "LATEST": "${{ github.ref == 'refs/heads/main' }}" + } + } + ] + } + } +} diff --git a/aws/image.yaml b/aws/image.yaml index b6cbda7..8ac87b0 100644 --- a/aws/image.yaml +++ b/aws/image.yaml @@ -1,31 +1,28 @@ -version: 0.2 -env: - secrets-manager: - DOCKER_PASSWORD: docker-hub-read-only:DOCKER_PASSWORD - DOCKER_USERNAME: docker-hub-read-only:DOCKER_USERNAME - variables: - AWS_REGION: us-east-1 - # These values are simply the defaults. They are typically overriden by the - # workflow in `.github/workflows/workflow.yaml`. - GHC_VERSION: 9.8.1 -phases: - build: - commands: - - - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin - - - server=public.ecr.aws/acilearning - - - aws ecr-public get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$server" - - - case $( uname -m ) in ( aarch64 ) arch=arm64 ;; ( x86_64 ) arch=amd64 ;; ( * ) exit 1 ;; esac - - - echo "$arch" - - - tag="$server/haskell:$GHC_VERSION-$CODEBUILD_RESOLVED_SOURCE_VERSION-$arch" - - - echo "$tag" - - - docker build --build-arg GHC_VERSION="$GHC_VERSION" --tag "$tag" . - - - docker push "$tag" +{ + "version": 0.2, + "env": { + "secrets-manager": { + "DOCKER_PASSWORD": "docker-hub-read-only:DOCKER_PASSWORD", + "DOCKER_USERNAME": "docker-hub-read-only:DOCKER_USERNAME" + }, + "variables": { + "AWS_REGION": "us-east-1", + "GHC_VERSION": "9.8.1" + } + }, + "phases": { + "build": { + "commands": [ + "echo \"$DOCKER_PASSWORD\" | docker login --username \"$DOCKER_USERNAME\" --password-stdin", + "server=public.ecr.aws/acilearning", + "aws ecr-public get-login-password --region \"$AWS_REGION\" | docker login --username AWS --password-stdin \"$server\"", + "case $( uname -m ) in ( aarch64 ) arch=arm64 ;; ( x86_64 ) arch=amd64 ;; ( * ) exit 1 ;; esac", + "echo \"$arch\"", + "tag=\"$server/haskell:$GHC_VERSION-$CODEBUILD_RESOLVED_SOURCE_VERSION-$arch\"", + "echo \"$tag\"", + "docker build --build-arg GHC_VERSION=\"$GHC_VERSION\" --tag \"$tag\" .", + "docker push \"$tag\"" + ] + } + } +} diff --git a/aws/manifest.yaml b/aws/manifest.yaml index 2443b5f..5dabd74 100644 --- a/aws/manifest.yaml +++ b/aws/manifest.yaml @@ -1,30 +1,23 @@ -version: 0.2 -env: - variables: - AWS_REGION: us-east-1 - # These values are simply the defaults. They are typically overriden by - # the workflow in `.github/workflows/workflow.yaml`. - GHC_VERSION: 9.8.1 - LATEST: 'false' -phases: - build: - commands: - - - server=public.ecr.aws/acilearning - - - aws ecr-public get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$server" - - - tag="$server/haskell:$GHC_VERSION-$CODEBUILD_RESOLVED_SOURCE_VERSION" - - - echo "$tag" - - - docker manifest create "$tag" "$tag-amd64" "$tag-arm64" - - - docker manifest push "$tag" - - - if test "$LATEST" = 'true'; - then latest="$server/haskell:$GHC_VERSION"; - echo "$latest"; - docker manifest create "$latest" "$tag-amd64" "$tag-arm64"; - docker manifest push "$latest"; - fi +{ + "version": 0.2, + "env": { + "variables": { + "AWS_REGION": "us-east-1", + "GHC_VERSION": "9.8.1", + "LATEST": "false" + } + }, + "phases": { + "build": { + "commands": [ + "server=public.ecr.aws/acilearning", + "aws ecr-public get-login-password --region \"$AWS_REGION\" | docker login --username AWS --password-stdin \"$server\"", + "tag=\"$server/haskell:$GHC_VERSION-$CODEBUILD_RESOLVED_SOURCE_VERSION\"", + "echo \"$tag\"", + "docker manifest create \"$tag\" \"$tag-amd64\" \"$tag-arm64\"", + "docker manifest push \"$tag\"", + "if test \"$LATEST\" = 'true'; then latest=\"$server/haskell:$GHC_VERSION\"; echo \"$latest\"; docker manifest create \"$latest\" \"$tag-amd64\" \"$tag-arm64\"; docker manifest push \"$latest\"; fi" + ] + } + } +} From b3d9e234d3b88c2c0f0d9bae56d2f3b5c00d5716 Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Tue, 14 Nov 2023 09:17:50 -0600 Subject: [PATCH 3/4] Pretty print JSON --- .github/dependabot.yaml | 6 +-- .github/workflows/workflow.yaml | 76 ++++++++++++++++----------------- aws/image.yaml | 4 +- aws/manifest.yaml | 4 +- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 21b7b48..88d861d 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -1,12 +1,12 @@ { - "version": 2, "updates": [ { - "package-ecosystem": "github-actions", "directory": "/", + "package-ecosystem": "github-actions", "schedule": { "interval": "daily" } } - ] + ], + "version": 2 } diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index 54104a5..7818729 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -1,8 +1,28 @@ { - "name": "Workflow", - "on": "push", "jobs": { "image": { + "runs-on": "ubuntu-latest", + "steps": [ + { + "uses": "aws-actions/configure-aws-credentials@v4", + "with": { + "aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}", + "aws-region": "${{ secrets.AWS_DEFAULT_REGION }}", + "aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}" + } + }, + { + "env": { + "GHC_VERSION": "${{ matrix.ghc }}" + }, + "uses": "aws-actions/aws-codebuild-run-build@v1", + "with": { + "buildspec-override": "aws/image.yaml", + "env-vars-for-codebuild": "GHC_VERSION", + "project-name": "docker-haskell-${{ matrix.arch }}" + } + } + ], "strategy": { "fail-fast": false, "matrix": { @@ -33,7 +53,10 @@ } ] } - }, + } + }, + "manifest": { + "needs": "image", "runs-on": "ubuntu-latest", "steps": [ { @@ -45,20 +68,18 @@ } }, { + "env": { + "GHC_VERSION": "${{ matrix.ghc }}", + "LATEST": "${{ github.ref == 'refs/heads/main' }}" + }, "uses": "aws-actions/aws-codebuild-run-build@v1", "with": { - "project-name": "docker-haskell-${{ matrix.arch }}", - "buildspec-override": "aws/image.yaml", - "env-vars-for-codebuild": "GHC_VERSION" - }, - "env": { - "GHC_VERSION": "${{ matrix.ghc }}" + "buildspec-override": "aws/manifest.yaml", + "env-vars-for-codebuild": "GHC_VERSION,LATEST", + "project-name": "docker-haskell-amd64" } } - ] - }, - "manifest": { - "needs": "image", + ], "strategy": { "matrix": { "ghc": [ @@ -67,30 +88,9 @@ "9.8.1" ] } - }, - "runs-on": "ubuntu-latest", - "steps": [ - { - "uses": "aws-actions/configure-aws-credentials@v4", - "with": { - "aws-access-key-id": "${{ secrets.AWS_ACCESS_KEY_ID }}", - "aws-region": "${{ secrets.AWS_DEFAULT_REGION }}", - "aws-secret-access-key": "${{ secrets.AWS_SECRET_ACCESS_KEY }}" - } - }, - { - "uses": "aws-actions/aws-codebuild-run-build@v1", - "with": { - "project-name": "docker-haskell-amd64", - "buildspec-override": "aws/manifest.yaml", - "env-vars-for-codebuild": "GHC_VERSION,LATEST" - }, - "env": { - "GHC_VERSION": "${{ matrix.ghc }}", - "LATEST": "${{ github.ref == 'refs/heads/main' }}" - } - } - ] + } } - } + }, + "name": "Workflow", + "on": "push" } diff --git a/aws/image.yaml b/aws/image.yaml index 8ac87b0..7d27da1 100644 --- a/aws/image.yaml +++ b/aws/image.yaml @@ -1,5 +1,4 @@ { - "version": 0.2, "env": { "secrets-manager": { "DOCKER_PASSWORD": "docker-hub-read-only:DOCKER_PASSWORD", @@ -24,5 +23,6 @@ "docker push \"$tag\"" ] } - } + }, + "version": 0.2 } diff --git a/aws/manifest.yaml b/aws/manifest.yaml index 5dabd74..bb3b301 100644 --- a/aws/manifest.yaml +++ b/aws/manifest.yaml @@ -1,5 +1,4 @@ { - "version": 0.2, "env": { "variables": { "AWS_REGION": "us-east-1", @@ -19,5 +18,6 @@ "if test \"$LATEST\" = 'true'; then latest=\"$server/haskell:$GHC_VERSION\"; echo \"$latest\"; docker manifest create \"$latest\" \"$tag-amd64\" \"$tag-arm64\"; docker manifest push \"$latest\"; fi" ] } - } + }, + "version": 0.2 } From cb8f64b27005d2d76426457eb7b9dff064c8dcb4 Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Tue, 14 Nov 2023 09:38:17 -0600 Subject: [PATCH 4/4] Add some usage instructions --- README.markdown | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/README.markdown b/README.markdown index 821ccee..b1feb18 100644 --- a/README.markdown +++ b/README.markdown @@ -7,3 +7,52 @@ This Docker image provides a Haskell development environment with the following - [Cabal](https://www.haskell.org/cabal/) version 3.10.2.0 - [Stack](https://docs.haskellstack.org/en/stable/) version 2.13.1 - [HLS](https://haskell-language-server.readthedocs.io/en/latest/) version 2.4.0.0 + +## Usage + +This Docker image supports both AMD64 (`x86_64`) and ARM64 (`aarch64`) architectures. + +To get started, select one of the supported versions of GHC. +The Docker image is available at `public.ecr.aws/acilearning/haskell:$GHC`. +For example, to use GHC 9.8.1 you would use the image `public.ecr.aws/acilearning/haskell:9.8.1`. + +Note that the image tag can and often is updated with newer tools. +To pin a specific version, add the commit hash to the end of the tag. +The format is `public.ecr.aws/acilearning/haskell:$GHC-$COMMIT`. +For example, to use GHC 9.8.1 at a specific commit you would use the image `public.ecr.aws/acilearning/haskell:9.8.1-3a8c34f81332de06c4c2239e144a63dfd11de9f0`. +This is recommended for reproducible builds. + +## Development Container + +This Docker image is designed to be used as a [Development Container](https://containers.dev/). + +Here is an example `.devcontainer.json` file: + +``` json +{ + "customizations": { "vscode": { "extensions": [ "haskell.haskell" ] } }, + "dockerComposeFile": "compose.yaml", + "postCreateCommand": "cabal update", + "postStartCommand": "git config --global --add safe.directory \"$PWD\"", + "service": "devcontainer", + "workspaceFolder": "/workspace" +} +``` + +And the corresponding `compose.yaml` file: + +``` yaml +services: + devcontainer: + command: sleep infinity + image: public.ecr.aws/acilearning/haskell:9.8.1-3a8c34f81332de06c4c2239e144a63dfd11de9f0 + init: true + volumes: [ .:/workspace ] + working_dir: /workspace +``` + +Depending on your specific scenario, you may want to create volumes one or more of the following directories: + +- Cabal's cache: `/home/vscode/.cache/cabal` +- Cabal's state: `/home/vscode/.local/state/cabal` (can be an external volume shared between projects) +- Stack's share: `/home/vscode/.local/share/stack`