diff --git a/.gitallowed b/.gitallowed new file mode 100644 index 0000000..76bb1a8 --- /dev/null +++ b/.gitallowed @@ -0,0 +1 @@ +id-token: write diff --git a/.github/config/settings.yml b/.github/config/settings.yml new file mode 100644 index 0000000..05dbcda --- /dev/null +++ b/.github/config/settings.yml @@ -0,0 +1 @@ +TAG_FORMAT: "v${version}" diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..4a87436 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,46 @@ +######################################################################### +# Dependabot configuration file +######################################################################### + +version: 2 + +updates: + - package-ecosystem: "github-actions" + # Workflow files stored in the + # default location of `.github/workflows` + directory: "/" + schedule: + interval: "weekly" + day: "friday" + time: "18:00" # UTC + open-pull-requests-limit: 20 + commit-message: + prefix: "Upgrade: [dependabot] - " + + ################################### + # NPM workspace ################## + ################################### + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "friday" + time: "18:00" + open-pull-requests-limit: 20 + versioning-strategy: increase + commit-message: + prefix: "Upgrade: [dependabot] - " + + ################################### + # Poetry ######################### + ################################### + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + day: "friday" + time: "18:00" + open-pull-requests-limit: 20 + versioning-strategy: increase + commit-message: + prefix: "Upgrade: [dependabot] - " diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..203df63 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,59 @@ +## Summary + +**Remove items from this list if they are not relevant. Remove this line once this has been done** + +- Routine Change +- :exclamation: Breaking Change +- :robot: Operational or Infrastructure Change +- :sparkles: New Feature +- :warning: Potential issues that might be caused by this change + +### Details + +Add any summary information of what is in the change. **Remove this line if you have nothing to add.** + +## Pull Request Naming + +Pull requests should be named using the following format: + +```text +Tag: [AEA-NNNN] - Short description +``` + +Tag can be one of: + +- `Fix` - for a bug fix. (Patch release) +- `Update` - either for a backwards-compatible enhancement or for a rule change that adds reported problems. (Patch release) +- `New` - implemented a new feature. (Minor release) +- `Breaking` - for a backwards-incompatible enhancement or feature. (Major release) +- `Docs` - changes to documentation only. (Patch release) +- `Build` - changes to build process only. (No release) +- `Upgrade` - for a dependency upgrade. (Patch release) +- `Chore` - for refactoring, adding tests, etc. (anything that isn't user-facing). (Patch release) + +If the current release is x.y.z then +- a patch release increases z by 1 +- a minor release increases y by 1 +- a major release increases x by 1 + +Correct tagging is necessary for our automated versioning and release process. + +The description of your pull request will be used as the commit message for the merge, and also be included in the changelog. Please ensure that your title is sufficiently descriptive. + +### Rerunning Checks + +If you need to rename your pull request, you can restart the checks by either: + +- Closing and reopening the pull request +- pushing an empty commit + ```bash + git commit --allow-empty -m 'trigger build' + git push + ``` +- Amend your last commit and force push to the branch + ```bash + git commit --amend --no-edit + git push --force + ``` + +Rerunning the checks from within the pull request will not use the updated title. diff --git a/.github/workflows/build_multi_arch_image.yml b/.github/workflows/build_multi_arch_image.yml new file mode 100644 index 0000000..b7737e7 --- /dev/null +++ b/.github/workflows/build_multi_arch_image.yml @@ -0,0 +1,90 @@ +name: Build and push docker image + +on: + workflow_call: + +jobs: + + build_image: + permissions: + id-token: write + runs-on: ${{ matrix.runner }} + strategy: + matrix: + include: + - arch: amd64 + runner: ubuntu-22.04 + - arch: arm64 + runner: ubuntu-22.04-arm + steps: + - name: Checkout code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + with: + fetch-depth: 0 + + # use setup-node rather than asdf so that it works multi-arch + - name: setup node + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f + with: + node-version-file: .tool-versions + - name: make install + run: | + make install-node + + - name: Build container + run: | + make build-base-image + docker tag ghcr.io/nhsdigital/eps-devcontainer-base:latest ghcr.io/nhsdigital/eps-devcontainers:latest-${{ matrix.arch }} + docker save "ghcr.io/nhsdigital/eps-devcontainers:latest-${{ matrix.arch }}" -o eps-devcontainer-base-latest-${{ matrix.arch }}.img + env: + GH_TOKEN: ${{ github.token }} + ARCHITECTURE: ${{ matrix.arch }} + - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f + name: Upload docker images + with: + name: eps-devcontainer-base-latest-${{ matrix.arch }}.img + path: | + eps-devcontainer-base-latest-${{ matrix.arch }}.img + + publish_image: + needs: build_image + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write + attestations: write + id-token: write + steps: + - name: Free Disk Space for Docker + uses: endersonmenezes/free-disk-space@e6ed9b02e683a3b55ed0252f1ee469ce3b39a885 + with: + remove_android: true + remove_dotnet: true + remove_haskell: true + remove_tool_cache: true + rm_cmd: "rm" + remove_packages: "azure-cli google-cloud-cli microsoft-edge-stable google-chrome-stable firefox postgresql* temurin-* *llvm* mysql* dotnet-sdk-*" + remove_packages_one_command: true + - name: Download amd64 images + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 + with: + name: eps-devcontainer-base-latest-amd64.img + - name: Download arm64 images + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 + with: + name: eps-devcontainer-base-latest-arm64.img + - name: Load and push multi-arch image + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + echo "loading images" + docker load -i eps-devcontainer-base-latest-amd64.img + docker load -i eps-devcontainer-base-latest-arm64.img + echo "pushing images" + docker push ghcr.io/nhsdigital/eps-devcontainers:latest-amd64 + docker push ghcr.io/nhsdigital/eps-devcontainers:latest-arm64 + echo "creating manifest" + docker manifest create ghcr.io/nhsdigital/eps-devcontainers:latest \ + --amend ghcr.io/nhsdigital/eps-devcontainers:latest-amd64 \ + --amend ghcr.io/nhsdigital/eps-devcontainers:latest-arm64 + echo "pushing manifest" + docker manifest push ghcr.io/nhsdigital/eps-devcontainers:latest diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..d693dfe --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,96 @@ +name: pull_request + +on: + pull_request: + branches: [main] + +env: + BRANCH_NAME: ${{ github.event.pull_request.head.ref }} + +jobs: + dependabot-auto-approve-and-merge: + needs: quality_checks + uses: NHSDigital/eps-common-workflows/.github/workflows/dependabot-auto-approve-and-merge.yml@2b3ddfd1e59daf9905522d0140c6cd08e2547432 + secrets: + AUTOMERGE_APP_ID: ${{ secrets.AUTOMERGE_APP_ID }} + AUTOMERGE_PEM: ${{ secrets.AUTOMERGE_PEM }} + + get_asdf_version: + runs-on: ubuntu-22.04 + outputs: + asdf_version: ${{ steps.asdf-version.outputs.version }} + tag_format: ${{ steps.load-config.outputs.TAG_FORMAT }} + steps: + - name: Checkout code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + + - name: Get asdf version + id: asdf-version + run: echo "version=$(awk '!/^#/ && NF {print $1; exit}' .tool-versions.asdf)" >> "$GITHUB_OUTPUT" + - name: Load config value + id: load-config + run: | + TAG_FORMAT=$(yq '.TAG_FORMAT' .github/config/settings.yml) + echo "TAG_FORMAT=$TAG_FORMAT" >> "$GITHUB_OUTPUT" + + quality_checks: + uses: NHSDigital/eps-common-workflows/.github/workflows/quality-checks.yml@trivy + needs: [get_asdf_version] + with: + asdfVersion: ${{ needs.get_asdf_version.outputs.asdf_version }} + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + pr_title_format_check: + uses: NHSDigital/eps-common-workflows/.github/workflows/pr_title_check.yml@2b3ddfd1e59daf9905522d0140c6cd08e2547432 + + get_issue_number: + runs-on: ubuntu-22.04 + needs: quality_checks + outputs: + issue_number: ${{ steps.get_issue_number.outputs.result }} + version: ${{ steps.get_issue_number.outputs.version_number }} + + steps: + - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd + name: get issue number + id: get_issue_number + with: + script: | + if (context.issue.number) { + // Return issue number if present + return context.issue.number; + } else { + // Otherwise return issue number from commit + return ( + await github.rest.repos.listPullRequestsAssociatedWithCommit({ + commit_sha: context.sha, + owner: context.repo.owner, + repo: context.repo.repo, + }) + ).data[0].number; + } + result-encoding: string + + get_commit_id: + runs-on: ubuntu-22.04 + outputs: + commit_id: ${{ steps.commit_id.outputs.commit_id }} + sha_short: ${{ steps.commit_id.outputs.sha_short }} + + steps: + - name: Checkout code + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + with: + ref: ${{ env.BRANCH_NAME }} + + - name: Get Commit ID + id: commit_id + run: | + # echo "commit_id=${{ github.sha }}" >> "$GITHUB_ENV" + echo "commit_id=${{ github.sha }}" >> "$GITHUB_OUTPUT" + echo "sha_short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + + + package_docker_image: + uses: ./.github/workflows/build_multi_arch_image.yml diff --git a/Makefile b/Makefile index 0fc362a..cf96122 100644 --- a/Makefile +++ b/Makefile @@ -17,9 +17,10 @@ install-hooks: install-python install-hooks: build-base-image: generate-language-version-files CONTAINER_NAME=$(CONTAINER_NAME) \ - devcontainer build \ + npx devcontainer build \ --workspace-folder ./src/base/ \ --push false \ + --platform linux/${ARCHITECTURE} \ --image-name "${IMAGE_NAME}" generate-language-version-files: @@ -31,3 +32,11 @@ scan-base-image: --ignorefile .trivyignore.yaml \ --exit-code 1 \ --format table ${IMAGE_NAME} + +lint: lint-githubactions + +test: + echo "Not implemented" + +lint-githubactions: + actionlint diff --git a/scripts/generate_language_version_files.sh b/scripts/generate_language_version_files.sh index b10626f..1e523ae 100755 --- a/scripts/generate_language_version_files.sh +++ b/scripts/generate_language_version_files.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +# Get the current directory of the script +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LANGUAGE_VERSIONS_DIR="${SCRIPT_DIR}/../src/base/.devcontainer/language_versions" + # Define repositories to fetch .tool-versions from REPOS=( "NHSDigital/electronic-prescription-service-clinical-prescription-tracker" @@ -30,12 +34,13 @@ REPOS=( # Define output files -NODEJS_FILE="/workspaces/eps-devcontainers/src/base/.devcontainer/language_versions/nodejs-versions.txt" -PYTHON_FILE="/workspaces/eps-devcontainers/src/base/.devcontainer/language_versions/python-versions.txt" -JAVA_FILE="/workspaces/eps-devcontainers/src/base/.devcontainer/language_versions/java-versions.txt" -TERRAFORM_FILE="/workspaces/eps-devcontainers/src/base/.devcontainer/language_versions/terraform-versions.txt" -GOLANG_FILE="/workspaces/eps-devcontainers/src/base/.devcontainer/language_versions/golang-versions.txt" -ALL_LANGUAGES_FILE="/workspaces/eps-devcontainers/src/base/.devcontainer/language_versions/language-versions.txt" +mkdir -p "${LANGUAGE_VERSIONS_DIR}" +NODEJS_FILE="${LANGUAGE_VERSIONS_DIR}/nodejs-versions.txt" +PYTHON_FILE="${LANGUAGE_VERSIONS_DIR}/python-versions.txt" +JAVA_FILE="${LANGUAGE_VERSIONS_DIR}/java-versions.txt" +TERRAFORM_FILE="${LANGUAGE_VERSIONS_DIR}/terraform-versions.txt" +GOLANG_FILE="${LANGUAGE_VERSIONS_DIR}/golang-versions.txt" +ALL_LANGUAGES_FILE="${LANGUAGE_VERSIONS_DIR}/language-versions.txt" # Clear existing files true > "$NODEJS_FILE" true > "$PYTHON_FILE" diff --git a/src/base/.devcontainer/scripts/root_install.sh b/src/base/.devcontainer/scripts/root_install.sh index fd3a1ae..0c0d632 100755 --- a/src/base/.devcontainer/scripts/root_install.sh +++ b/src/base/.devcontainer/scripts/root_install.sh @@ -1,29 +1,26 @@ #!/usr/bin/env bash set -e - -# Install essential packages first -apt-get update -apt-get install -y \ - curl \ - wget \ - git \ - sudo \ - unzip -apt-get clean -rm -rf /var/lib/apt/lists/* +export DEBIAN_FRONTEND=noninteractive # Add amd64 architecture if on arm64 if [ "$TARGETARCH" == "arm64" ] || [ "$TARGETARCH" == "aarch64" ]; then + echo "Adding amd64 architecture support" dpkg --add-architecture amd64 + + # Update sources.list to include amd64 repositories + echo "Configuring sources.list for amd64 and arm64" + sed -i.bak '/^deb / s|http://ports.ubuntu.com/ubuntu-ports|[arch=arm64] http://ports.ubuntu.com/ubuntu-ports|' /etc/apt/sources.list + # shellcheck disable=SC2129 + echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu jammy main universe" >> /etc/apt/sources.list + echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu jammy-updates main universe" >> /etc/apt/sources.list + echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu jammy-security main universe" >> /etc/apt/sources.list fi -# uninstall unnecessary packages -apt-get remove -y \ - python3 -# install necessary libraries for asdf and language runtimes +echo "Running apt-get update" apt-get update -export DEBIAN_FRONTEND=noninteractive -apt-get -y dist-upgrade + +# install necessary libraries for asdf and language runtimes +echo "Installing necessary packages" apt-get -y install --no-install-recommends htop vim curl git build-essential \ libffi-dev libssl-dev libxml2-dev libxslt1-dev libjpeg8-dev libbz2-dev \ zlib1g-dev unixodbc unixodbc-dev libsecret-1-0 libsecret-1-dev libsqlite3-dev \ @@ -34,33 +31,36 @@ apt-get -y install --no-install-recommends htop vim curl git build-essential \ # install aws stuff # Download correct AWS CLI for arch +echo "Installing aws cli" if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" == "aarch64" ]; then - wget -O /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip"; \ + wget -O /tmp/awscliv2.zip --no-verbose "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" else - wget -O /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"; \ + wget -O /tmp/awscliv2.zip --no-verbose "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" fi - unzip /tmp/awscliv2.zip -d /tmp/aws-cli + unzip -q /tmp/awscliv2.zip -d /tmp/aws-cli /tmp/aws-cli/aws/install rm /tmp/awscliv2.zip rm -rf /tmp/aws-cli # Download correct SAM CLI for arch +echo "Installing aws-sam cli" if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" = "aarch64" ]; then - wget -O /tmp/aws-sam-cli.zip "https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-arm64.zip"; \ + wget -O /tmp/aws-sam-cli.zip --no-verbose "https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-arm64.zip" else - wget -O /tmp/aws-sam-cli.zip "https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip"; \ + wget -O /tmp/aws-sam-cli.zip --no-verbose "https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip" fi - unzip /tmp/aws-sam-cli.zip -d /tmp/aws-sam-cli + unzip -q /tmp/aws-sam-cli.zip -d /tmp/aws-sam-cli /tmp/aws-sam-cli/install rm /tmp/aws-sam-cli.zip rm -rf /tmp/aws-sam-cli # Install ASDF +echo "Installing asdf" ASDF_VERSION=$(awk '!/^#/ && NF {print $1; exit}' /tmp/.tool-versions.asdf) if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" == "aarch64" ]; then - wget -O /tmp/asdf.tar.gz "https://github.com/asdf-vm/asdf/releases/download/v${ASDF_VERSION}/asdf-v${ASDF_VERSION}-linux-arm64.tar.gz"; \ + wget -O /tmp/asdf.tar.gz --no-verbose "https://github.com/asdf-vm/asdf/releases/download/v${ASDF_VERSION}/asdf-v${ASDF_VERSION}-linux-arm64.tar.gz" else - wget -O /tmp/asdf.tar.gz "https://github.com/asdf-vm/asdf/releases/download/v${ASDF_VERSION}/asdf-v${ASDF_VERSION}-linux-amd64.tar.gz"; \ + wget -O /tmp/asdf.tar.gz --no-verbose "https://github.com/asdf-vm/asdf/releases/download/v${ASDF_VERSION}/asdf-v${ASDF_VERSION}-linux-amd64.tar.gz" fi tar -xzf /tmp/asdf.tar.gz -C /tmp mkdir -p /usr/bin diff --git a/src/base/.devcontainer/scripts/vscode_install.sh b/src/base/.devcontainer/scripts/vscode_install.sh index 0349116..838353a 100755 --- a/src/base/.devcontainer/scripts/vscode_install.sh +++ b/src/base/.devcontainer/scripts/vscode_install.sh @@ -42,9 +42,9 @@ while IFS= read -r version; do done < /tmp/python-versions.txt # Read Java versions from file and install -while IFS= read -r version; do - asdf install java "$version" -done < /tmp/java-versions.txt +# while IFS= read -r version; do +# asdf install java "$version" +# done < /tmp/java-versions.txt # Read Terraform versions from file and install while IFS= read -r version; do