From 0f8556c43afa90302ca65cbf418925654be382bd Mon Sep 17 00:00:00 2001 From: Shiloh Heurich Date: Tue, 27 Feb 2024 15:36:20 -0500 Subject: [PATCH] CI Overhaul --- .ci/publish_linux.sh | 27 ---------- .ci/publish_windows.ps1 | 28 ----------- .dockerignore | 5 +- .github/workflows/checks.yml | 65 +++++++++++------------- .github/workflows/go-cross.yml | 30 ++++++----- .github/workflows/release.yml | 92 ++++++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 48 +++++------------- .travis.yml | 89 -------------------------------- Dockerfile.release | 29 +++++++++++ README.md | 6 ++- lint.sh | 11 ++++ mods.sh | 18 +++++++ test.sh | 22 ++++++++ 13 files changed, 233 insertions(+), 237 deletions(-) delete mode 100644 .ci/publish_linux.sh delete mode 100644 .ci/publish_windows.ps1 create mode 100644 .github/workflows/release.yml delete mode 100644 .travis.yml create mode 100644 Dockerfile.release create mode 100755 lint.sh create mode 100755 mods.sh create mode 100755 test.sh diff --git a/.ci/publish_linux.sh b/.ci/publish_linux.sh deleted file mode 100644 index 6b5d0f5e..00000000 --- a/.ci/publish_linux.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -set -e - -docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" - -BASE_NAMES=(pebble pebble-challtestsrv) -for BASE_NAME in "${BASE_NAMES[@]}"; do - IMAGE_NAME="letsencrypt/${BASE_NAME}" - - echo "Updating docker ${IMAGE_NAME} image..." - - # create docker image - docker build -t "${IMAGE_NAME}:temp" -f "docker/${BASE_NAME}/linux.Dockerfile" . - - # push images - if [ -n "${TRAVIS_TAG}" ]; then - echo "Try to publish image: ${IMAGE_NAME}:${TRAVIS_TAG}" - docker tag "${IMAGE_NAME}:temp" "${IMAGE_NAME}:${TRAVIS_TAG}" - docker push "${IMAGE_NAME}:${TRAVIS_TAG}" - - echo "Try to publish rolling image: ${IMAGE_NAME}:latest" - docker tag "${IMAGE_NAME}:${TRAVIS_TAG}" "${IMAGE_NAME}:latest" - docker push "${IMAGE_NAME}:latest" - fi -done - -echo "Published" diff --git a/.ci/publish_windows.ps1 b/.ci/publish_windows.ps1 deleted file mode 100644 index b48c082f..00000000 --- a/.ci/publish_windows.ps1 +++ /dev/null @@ -1,28 +0,0 @@ -$ErrorActionPreference = 'Stop' -if ($env:APPVEYOR_REPO_TAG -ne "true") { - "Skipping publishing because this is not a tagged commit" -} else { - "Publishing the tagged commit..." - - $ErrorActionPreference = 'SilentlyContinue' - docker login -u="$env:DOCKER_USER" -p="$env:DOCKER_PASS" - $ErrorActionPreference = 'Stop' - - $basenames = @("pebble", "pebble-challtestsrv") - foreach ($basename in $basenames) { - $image_name = "letsencrypt/$basename" - $tag = "$env:APPVEYOR_REPO_TAG_NAME-nanoserver-sac2016" - - "Updating docker $basename image ..." - - docker build -t="$image_name`:temp" -f="docker/$basename/windows.Dockerfile" . - - "Try to publish image: $image_name`:$tag" - docker tag "$image_name`:temp" "$image_name`:$tag" - docker push "$image_name`:$tag" - - "Try to publish rolling image: $image_name`:nanoserver-sac2016" - docker tag "$image_name`:temp" "$image_name`:nanoserver-sac2016" - docker push "$image_name`:nanoserver-sac2016" - } -} diff --git a/.dockerignore b/.dockerignore index e8d3e41e..a0643715 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,2 @@ -.git -pebble.exe -pebble +/pebble +/pebble.exe diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6d623182..476f3a88 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -1,53 +1,46 @@ -name: Checks - +name: Go Checks +# Run on push to main and any pull request. on: push: branches: - main pull_request: - permissions: + checks: write # Allow write access to checks to allow annotation of code in the PR. contents: read pull-requests: read - +env: + GO_VERSION: stable + GOLANGCI_LINT_VERSION: v1.56.2 jobs: - - checks: - name: Check Process + go-lint-checks: runs-on: ubuntu-latest - env: - GO_VERSION: oldstable - GOLANGCI_LINT_VERSION: v1.56.2 - CGO_ENABLED: 0 - steps: - - - name: Check out code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - fetch-depth: 0 - - - name: Set up Go - uses: actions/setup-go@v5 + go-version: ${{ env.GO_VERSION }} + - name: Run GolangCI-Lint + uses: golangci/golangci-lint-action@v4 + with: + # skip cache because of flaky behaviors + skip-build-cache: true + skip-pkg-cache: true + version: ${{ env.GOLANGCI_LINT_VERSION }} + go-mod-checks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - - - name: Check and get dependencies + - name: Check if go.mod is tidy run: | go mod tidy - git diff --exit-code go.mod - git diff --exit-code go.sum - - - name: vendoring - run: go mod vendor - - - name: vendoring diff - run: git diff --exit-code vendor/ - - # https://golangci-lint.run/usage/install#other-ci - - name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }} + git diff --exit-code go.mod go.sum || + (echo "::error::go.mod and go.sum need to be tidy" && exit 1) + - name: Check if vendor directory is up to date run: | - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION} - golangci-lint run - - + go mod vendor + git diff --exit-code vendor || + (echo "::error::vendor directory needs to be updated" && exit 1) diff --git a/.github/workflows/go-cross.yml b/.github/workflows/go-cross.yml index e28cc18a..89e9b7b8 100644 --- a/.github/workflows/go-cross.yml +++ b/.github/workflows/go-cross.yml @@ -1,38 +1,36 @@ -name: Go Matrix +name: Go Build Matrix on: push: branches: - main pull_request: - permissions: contents: read pull-requests: read - jobs: - cross: - name: Build + name: Build on ${{ matrix.os }} with Go ${{ matrix.go-version }} runs-on: ${{ matrix.os }} env: CGO_ENABLED: 0 - strategy: matrix: - go-version: [ oldstable, stable ] - os: [ubuntu-latest, macos-latest, windows-latest] - + app: + - pebble + - pebble-challtestsrv + go-version: + - oldstable + - stable + os: + - ubuntu-latest + - macos-latest + - windows-latest steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} - - - name: Build pebble - run: go build -v -ldflags "-s -w" -trimpath -o pebble ./cmd/pebble - - - name: Build pebble-challtestsrv - run: go build -v -ldflags "-s -w" -trimpath -o pebble-challtestsrv ./cmd/pebble-challtestsrv + - name: Build ${{ matrix.app }} + run: go build -v ./cmd/${{ matrix.app}} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..a8e6cef8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,92 @@ +name: Build Release +# Run on release tags only. +on: + push: + tags: + - v* +permissions: + contents: read + packages: write # Allow docker/build-push-action to publish to GitHub Container Registry + pull-requests: read +env: + DOCKER_PLATFORMS: linux/amd64, linux/arm64, windows/amd64 +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + app: + - pebble + - pebble-challtestsrv + go-arch: + - amd64 + - arm64 + go-os: + - darwin + - linux + - windows + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + check-latest: true + go-version-file: go.mod + - name: Build ${{ matrix.app }} for ${{ matrix.go-os }}/${{ matrix.go-arch }} + env: + CGO_ENABLED: 0 + GOARCH: ${{ matrix.go-arch }} + GOOS: ${{ matrix.go-os }} + LDFLAGS: -s -w + run: | + go build \ + -ldflags="${LDFLAGS}" \ + -o /tmp/dist/${{ matrix.go-os }}/${{ matrix.go-arch }}/ \ + -trimpath \ + -v \ + ./cmd/${{ matrix.app }} + - name: Display ${{ matrix.app }} artifacts + run: ls -lR /tmp/dist + - name: Store ${{ matrix.app }} artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.app }}-${{ matrix.go-os }}-${{ matrix.go-arch }} + path: /tmp/dist + docker: + needs: + - build + runs-on: ubuntu-latest + strategy: + matrix: + app: + - pebble + - pebble-challtestsrv + steps: + - name: Download ${{ matrix.app }} artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + path: ./dist + pattern: ${{ matrix.app }}-*-* + - name: Display ${{ matrix.app }} artifacts + run: ls -lR ./dist + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push ${{ github.repository }}/${{ matrix.app }} for ${{ env.DOCKER_PLATFORMS }} + uses: docker/build-push-action@v5 + with: + build-args: APP=${{ matrix.app }} + build-contexts: dist-files=./dist + cache-from: type=gha + cache-to: type=gha,mode=max + file: Dockerfile.release + platforms: ${{ env.DOCKER_PLATFORMS }} + push: true + tags: ghcr.io/${{ github.repository }}/${{ matrix.app }}:${{ github.sha }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5c1ac6f5..bb73b2b9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,70 +1,46 @@ name: Tests - on: push: branches: - main pull_request: - permissions: contents: read pull-requests: read - jobs: - test-linux: - name: Test on Linux + name: Run tests on Linux runs-on: ubuntu-latest - env: - GO_VERSION: oldstable steps: - - name: Setup /etc/hosts run: | echo "127.0.0.1 example.letsencrypt.org" | sudo tee -a /etc/hosts echo "127.0.0.1 elpmaxe.letsencrypt.org" | sudo tee -a /etc/hosts - # https://github.com/marketplace/actions/checkout - name: Check out code uses: actions/checkout@v4 - with: - fetch-depth: 0 - # https://github.com/marketplace/actions/setup-go-environment - name: Set up Go uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} - - - name: apt install + go-version-file: go.mod + - name: Install packages run: sudo apt-get install snapd python3-acme python3-josepy - - - name: snap install + - name: Setup snap run: sudo snap install core && sudo snap refresh core - - - name: snap install certbot + - name: Install certbot run: sudo snap install --classic certbot && sudo ln -s /snap/bin/certbot /usr/bin/certbot - - - name: go install tools - run: go install golang.org/x/tools/cmd/cover@latest - - - name: go install goveralls - run: go install github.com/mattn/goveralls@latest - - name: go install pebble run: go install -v -race ./... - - name: launch pebble run: GORACE="halt_on_error=1" PEBBLE_WFE_NONCEREJECT=0 pebble & - - # Run project unit tests (with the race detector enabled and atomic coverage profile collection) - - name: unittests - run: go test -v -race -covermode=atomic -coverprofile=coverage.out ./... - -# # Upload collected coverage profile to goveralls -# - name: goveralls -# run: goveralls -coverprofile=coverage.out -service=github - # Perform a test issuance with chisel2.py - name: chisel run: REQUESTS_CA_BUNDLE=./test/certs/pebble.minica.pem python ./test/chisel2.py example.letsencrypt.org elpmaxe.letsencrypt.org + # Run project unit tests (with the race detector enabled and atomic coverage profile collection) + - name: unittests + run: go test -v -race -covermode=atomic -coverprofile=profile.cov ./... + # Upload collected coverage profile to goveralls + - uses: shogo82148/actions-goveralls@v1 + with: + path-to-profile: profile.cov diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3dc1c19a..00000000 --- a/.travis.yml +++ /dev/null @@ -1,89 +0,0 @@ -language: go - -sudo: true -dist: focal -addons: - hosts: - - example.letsencrypt.org - - elpmaxe.letsencrypt.org - -cache: - directories: - - $GOPATH/pkg/mod - -go: - - "1.21.x" - -services: - - docker - -before_install: - # snap for installing cerbot, python3-acme and python3-josepy for chisel2.py - - sudo apt-get install snapd python3-acme python3-josepy - - sudo snap install core - - sudo snap refresh core - - sudo snap install --classic certbot - - sudo ln -s /snap/bin/certbot /usr/bin/certbot - -# Override the base install phase so that the project can be installed using -# `-mod=vendor` to use the vendored dependencies -install: - # Install `golangci-lint` using their installer script - - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.56.2 - # Install tools without `GO111MODULE` enabled so that we - # don't download Pebble's deps and just put the tools in our - # gobin. - - GO111MODULE=off go get github.com/mattn/goveralls - - GO111MODULE=off go get github.com/letsencrypt/boulder/test/load-generator - - go mod tidy - - git diff --exit-code go.mod - - git diff --exit-code go.sum - - go mod download - - go mod vendor - - git diff --exit-code vendor/ - - go install -v -race -mod=vendor ./... - - GOOS=darwin GOARCH=arm64 go install -v -mod=vendor ./... - -before_script: - - GORACE="halt_on_error=1" PEBBLE_WFE_NONCEREJECT=0 pebble & - -script: - # Vet Go source code using the linter config (see .golang-ci.yml) - - golangci-lint run - # Run project unit tests (with the race detector enabled and atomic - # coverage profile collection) - - go test -mod=vendor -v -race -covermode=atomic -coverprofile=coverage.out ./... - # Upload collected coverage profile to goveralls - - goveralls -coverprofile=coverage.out -service=travis-ci - # Perform a test issuance with chisel2.py - - pip install -r test/requirements.txt - - REQUESTS_CA_BUNDLE=./test/certs/pebble.minica.pem python ./test/chisel2.py example.letsencrypt.org elpmaxe.letsencrypt.org - # Run the load-generator briefly - note, because Pebble isn't using the - # load-generator's mock DNS server none of the issuances will succeed. This - # step is performed just to shake out data races with concurrent requests. - - load-generator -config ./test/config/load-generator-config.json > /dev/null - -before_deploy: - - mkdir -p deploy - - cp $(go env GOPATH)/bin/pebble deploy/pebble_linux-amd64 - - cp $(go env GOPATH)/bin/pebble-challtestsrv deploy/pebble-challtestsrv_linux-amd64 - - cp $(go env GOPATH)/bin/darwin_arm64/pebble deploy/pebble_darwin-arm64 - - cp $(go env GOPATH)/bin/darwin_arm64/pebble-challtestsrv deploy/pebble-challtestsrv_darwin-arm64 - -deploy: - - provider: script - script: bash .ci/publish_linux.sh - skip_cleanup: true - on: - repo: letsencrypt/pebble - tags: true - - provider: releases - name: Pebble $TRAVIS_TAG - api_key: $GITHUB_AUTH_TOKEN - file_glob: true - file: deploy/* - skip_cleanup: true - draft: true - on: - repo: letsencrypt/pebble - tags: true diff --git a/Dockerfile.release b/Dockerfile.release new file mode 100644 index 00000000..e73b5c64 --- /dev/null +++ b/Dockerfile.release @@ -0,0 +1,29 @@ +# syntax=docker/dockerfile:1 + +# The build argument `APP` is used to select the appropriate binary +# for the target OS. +# The binary specified by `APP` must exist in the `dist-files` stage. +ARG APP=${APP:-pebble} + +# Set the base image dynamically based on the target OS +FROM --platform=${TARGETPLATFORM} alpine AS linux-base +FROM --platform=${TARGETPLATFORM} mcr.microsoft.com/windows/nanoserver:ltsc2022 AS windows-base + +# Use build arguments to select the appropriate binary for Linux +FROM linux-base AS linux +ARG APP +ARG TARGETOS +ARG TARGETARCH +COPY --from=dist-files /${TARGETOS}/${TARGETARCH}/${APP} /app +CMD ["/app"] + +# Use build arguments to select the appropriate binary for Windows +FROM windows-base AS windows +ARG APP +ARG TARGETOS +ARG TARGETARCH +COPY --from=dist-files /${TARGETOS}/${TARGETARCH}/${APP}.exe /app.exe +CMD ["/app.exe"] + +# Final stage: dynamically select between Linux and Windows stages based on TARGETOS argument +FROM ${TARGETOS} AS final diff --git a/README.md b/README.md index 645468d1..0567e892 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # Pebble -[![Build Status](https://travis-ci.org/letsencrypt/pebble.svg?branch=master)](https://travis-ci.org/letsencrypt/pebble) -[![Coverage Status](https://coveralls.io/repos/github/letsencrypt/pebble/badge.svg?branch=cpu-goveralls)](https://coveralls.io/github/letsencrypt/pebble?branch=cpu-goveralls) +[![Checks](https://github.com/letsencrypt/pebble/actions/workflows/checks.yml/badge.svg)](https://github.com/letsencrypt/pebble/actions/workflows/checks.yml) +[![Tests](https://github.com/letsencrypt/pebble/actions/workflows/tests.yml/badge.svg)](https://github.com/letsencrypt/pebble/actions/workflows/tests.yml) + +[![Coverage Status](https://coveralls.io/repos/github/letsencrypt/pebble/badge.svg)](https://coveralls.io/github/letsencrypt/pebble) [![Go Report Card](https://goreportcard.com/badge/github.com/letsencrypt/pebble)](https://goreportcard.com/report/github.com/letsencrypt/pebble) A miniature version of [Boulder](https://github.com/letsencrypt/boulder), Pebble diff --git a/lint.sh b/lint.sh new file mode 100755 index 00000000..55ef2e9b --- /dev/null +++ b/lint.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# Fail on error, undefined, and uninitialized variables +set -eu + +# Self-check with shellcheck +shellcheck "$0" + +# Run golangci-lint with the default configuration +# but disable GOWORK to only check local go.mod +GOWORK=off golangci-lint run diff --git a/mods.sh b/mods.sh new file mode 100755 index 00000000..ec602973 --- /dev/null +++ b/mods.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# Fail on error, undefined, and uninitialized variables +set -eu + +# Self-check with shellcheck +shellcheck "$0" + +# Disable GOWORK for local-only module maintenance +export GOWORK=off + +# Tidy up the go.mod file and vendored dependencies. +# Check for changes to the go.mod and go.sum files or the vendor directory. +go mod tidy -v -x +git diff --exit-code go.mod +git diff --exit-code go.sum +go mod vendor +git diff --exit-code vendor diff --git a/test.sh b/test.sh new file mode 100755 index 00000000..e9c62980 --- /dev/null +++ b/test.sh @@ -0,0 +1,22 @@ +#!/bin/sh -x +# This script runs standalone tests. + +# Fail on error, undefined, and uninitialized variables +set -eu + +# Self-check with shellcheck +shellcheck "$0" + +# Set Go build tags from command line arguments, if any. +TAGS=${*:-''} + +# Run the Go tests with coverage and race detection. +# Enable cgo and disable Go workspaces. +export CGO_ENABLED=1 +export GOWORK=off +go test \ + -coverprofile=profile.cov \ + -race \ + -tags="${TAGS}" \ + -v \ + ./...