Skip to content

Commit 67a9463

Browse files
authored
Merge pull request mutagen-io#313 from mutagen-io/ci-enhancements
ci: add validations in preparation for pull requests
2 parents cbeabfa + dcb2709 commit 67a9463

File tree

7 files changed

+213
-57
lines changed

7 files changed

+213
-57
lines changed

.github/workflows/ci.yml

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,52 +6,37 @@ on: [push, pull_request]
66

77
# Define the workflow jobs.
88
jobs:
9-
versioning:
10-
name: Versioning
9+
verification:
10+
name: Commit Verification
1111
runs-on: ubuntu-latest
12+
if: github.event_name == 'pull_request'
1213
steps:
1314
- uses: actions/checkout@v2
14-
- uses: actions/setup-go@v2
1515
with:
16-
go-version: '^1.17'
17-
- run: go version
18-
- name: "Analyze version information and release status"
19-
id: analyze
16+
fetch-depth: 0
17+
- uses: actions/setup-node@v2
18+
with:
19+
node-version: '16'
20+
- run: npm install --global @commitlint/cli
21+
- name: "Perform commit verification"
2022
run: |
21-
# Determine whether or not this is a release build.
22-
RELEASE="${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}"
23-
24-
# Determine version target information for Go. If this is a release,
25-
# then we'll use the tag, otherwise we'll use the raw commit digest.
26-
if [ "${RELEASE}" = "true" ]; then
27-
TARGET="${GITHUB_REF#refs/tags/}"
28-
else
29-
TARGET="${GITHUB_SHA}"
30-
fi
23+
# Determine the target commit range.
24+
export VERIFY_COMMIT_START="${{ github.event.pull_request.base.sha }}"
25+
export VERIFY_COMMIT_END="${{ github.event.pull_request.head.sha }}"
3126
32-
# Determine the sidecar image tags.
33-
SIDECAR_TAGS="$(go run scripts/ci/sidecar_tags.go)"
34-
35-
# Set outputs.
36-
echo ::set-output name=release::${RELEASE}
37-
echo ::set-output name=target::${TARGET}
38-
echo ::set-output name=sidecar_tags::${SIDECAR_TAGS}
39-
outputs:
40-
release: ${{ steps.analyze.outputs.release }}
41-
target: ${{ steps.analyze.outputs.target }}
42-
sidecar_tags: ${{ steps.analyze.outputs.sidecar_tags }}
27+
# Perform verification.
28+
scripts/ci/verify.sh
4329
macos:
4430
name: macOS
4531
runs-on: macos-11
46-
needs: [versioning]
4732
steps:
4833
- uses: actions/checkout@v2
4934
- uses: actions/setup-go@v2
5035
with:
5136
go-version: '^1.17'
52-
- run: go version
5337
- name: "Install sha256sum"
5438
run: brew install coreutils
39+
- run: scripts/ci/setup_go.sh
5540
- run: scripts/ci/setup_ssh.sh
5641
- run: scripts/ci/setup_partitions_darwin.sh
5742
- run: scripts/ci/analyze.sh
@@ -62,7 +47,7 @@ jobs:
6247
MACOS_CODESIGN_CERTIFICATE_AND_KEY: ${{ secrets.MACOS_CODESIGN_CERTIFICATE_AND_KEY }}
6348
MACOS_CODESIGN_CERTIFICATE_AND_KEY_PASSWORD: ${{ secrets.MACOS_CODESIGN_CERTIFICATE_AND_KEY_PASSWORD }}
6449
- run: scripts/ci/notarize.sh
65-
if: ${{ needs.versioning.outputs.release == 'true' }}
50+
if: github.ref_type == 'tag'
6651
env:
6752
MACOS_NOTARIZE_APPLE_ID: ${{ secrets.MACOS_NOTARIZE_APPLE_ID }}
6853
MACOS_NOTARIZE_APP_SPECIFIC_PASSWORD: ${{ secrets.MACOS_NOTARIZE_APP_SPECIFIC_PASSWORD }}
@@ -88,8 +73,7 @@ jobs:
8873
- uses: actions/setup-go@v2
8974
with:
9075
go-version: '^1.17'
91-
- run: docker version
92-
- run: go version
76+
- run: scripts/ci/setup_go.sh
9377
- run: scripts/ci/setup_ssh.sh
9478
- run: scripts/ci/setup_docker.sh
9579
- run: scripts/ci/analyze.sh
@@ -104,8 +88,8 @@ jobs:
10488
- uses: actions/setup-go@v2
10589
with:
10690
go-version: '^1.17'
107-
- run: docker version
108-
- run: go version
91+
- run: scripts/ci/setup_go.sh
92+
shell: bash
10993
- run: scripts/ci/setup_docker.sh
11094
shell: bash
11195
- run: diskpart /s scripts\ci\setup_partitions_windows.txt
@@ -118,25 +102,54 @@ jobs:
118102
- run: scripts/ci/build.sh
119103
shell: bash
120104
sidecar:
121-
name: Sidecar
105+
name: Sidecar (Non-release)
106+
runs-on: ubuntu-latest
107+
if: github.ref_type != 'tag'
108+
steps:
109+
- uses: actions/checkout@v2
110+
- uses: actions/setup-go@v2
111+
with:
112+
go-version: '^1.17'
113+
- uses: docker/setup-qemu-action@v1
114+
- uses: docker/setup-buildx-action@v1
115+
- name: "Determine sidecar tags"
116+
id: tags
117+
run: echo ::set-output name=tags::$(go run scripts/ci/sidecar_tags.go)
118+
- uses: docker/build-push-action@v2
119+
with:
120+
file: images/sidecar/linux/Dockerfile
121+
tags: ${{ steps.tags.outputs.tags }}
122+
platforms: |
123+
linux/386
124+
linux/amd64
125+
linux/arm/v6
126+
linux/arm/v7
127+
linux/arm64/v8
128+
linux/ppc64le
129+
sidecar_release:
130+
name: Sidecar (Release)
122131
runs-on: ubuntu-latest
123-
needs: [versioning, macos, linux, windows]
132+
if: github.ref_type == 'tag'
133+
needs: [macos, linux, windows]
124134
steps:
125135
- uses: actions/checkout@v2
136+
- uses: actions/setup-go@v2
137+
with:
138+
go-version: '^1.17'
126139
- uses: docker/setup-qemu-action@v1
127140
- uses: docker/setup-buildx-action@v1
128141
- uses: docker/login-action@v1
129-
if: ${{ needs.versioning.outputs.release == 'true' }}
130142
with:
131143
username: ${{ secrets.SIDECAR_DEPLOYMENT_USER }}
132144
password: ${{ secrets.SIDECAR_DEPLOYMENT_TOKEN }}
145+
- name: "Determine sidecar tags"
146+
id: tags
147+
run: echo ::set-output name=tags::$(go run scripts/ci/sidecar_tags.go)
133148
- uses: docker/build-push-action@v2
134149
with:
135-
build-args: |
136-
TARGET=${{ needs.versioning.outputs.target }}
137-
context: images/sidecar/linux
138-
tags: ${{ needs.versioning.outputs.sidecar_tags }}
139-
push: ${{ needs.versioning.outputs.release == 'true' }}
150+
file: images/sidecar/linux/Dockerfile
151+
tags: ${{ steps.tags.outputs.tags }}
152+
push: true
140153
platforms: |
141154
linux/386
142155
linux/amd64
@@ -147,8 +160,8 @@ jobs:
147160
release:
148161
name: Release
149162
runs-on: ubuntu-latest
150-
needs: [versioning, macos, linux, windows, sidecar]
151-
if: ${{ needs.versioning.outputs.release == 'true' }}
163+
if: github.ref_type == 'tag'
164+
needs: [macos, linux, windows, sidecar_release]
152165
steps:
153166
- uses: actions/download-artifact@v2
154167
with:

images/sidecar/linux/Dockerfile

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,26 @@ FROM golang:1.17-alpine3.14 AS builder
55
# avoid the need for gcc on certain architectures).
66
ENV CGO_ENABLED=0
77

8-
# Define an argument to specify the entrypoint version target.
9-
ARG TARGET
10-
11-
# Build the sidecar entrypoint. We have to use the shell form of RUN in order to
12-
# access the TARGET argument.
13-
RUN go get github.com/mutagen-io/mutagen/cmd/mutagen-sidecar@${TARGET}
8+
# Copy the Mutagen source code into the container and set the code directory as
9+
# our default working location.
10+
RUN ["mkdir", "/mutagen"]
11+
COPY ["go.mod", "go.sum", "/mutagen/"]
12+
COPY ["cmd", "/mutagen/cmd/"]
13+
COPY ["pkg", "/mutagen/pkg/"]
14+
WORKDIR /mutagen
15+
16+
# Build the sidecar entrypoint and agent binaries.
17+
RUN ["go", "build", "./cmd/mutagen-sidecar"]
18+
RUN ["go", "build", "./cmd/mutagen-agent"]
1419

1520
# Switch to a vanilla Alpine base for the final image.
1621
FROM alpine:3.14
1722

18-
# Copy the sidecar entrypoint from the builder.
19-
COPY --from=builder ["/go/bin/mutagen-sidecar", "/usr/bin/mutagen-sidecar"]
23+
# Copy the sidecar entrypoint and agent binaries from the builder. For the
24+
# agent, use its installation mechanism to move it to the correct location.
25+
COPY --from=builder ["/mutagen/mutagen-sidecar", "/usr/bin/mutagen-sidecar"]
26+
COPY --from=builder ["/mutagen/mutagen-agent", "/mutagen-agent"]
27+
RUN ["/mutagen-agent", "install"]
2028

2129
# Create the parent directory for volume mount points.
2230
RUN ["mkdir", "/volumes"]

scripts/ci/analyze.sh

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,26 @@
44
# fail, so we track the exit status of each command instead of using set -e.
55
FAILURE=0
66

7+
# Verify that code is formatted and simplified according to Go standards. We
8+
# skip this check on Windows due to gofmt normalizing Go code to LF endings (and
9+
# thus generating an enormous and pointless diff).
10+
if [[ "$(go env GOOS)" != "windows" ]]; then
11+
gofmt -s -l -d . | tee gofmt.log
12+
if [[ -s gofmt.log ]]; then
13+
FAILURE=1
14+
fi
15+
rm gofmt.log
16+
fi
17+
718
# Perform static analysis.
819
go vet ./pkg/... || FAILURE=1
920
go vet ./cmd/... || FAILURE=1
1021
go vet ./scripts/... || FAILURE=1
1122

12-
# TODO: Add gofmt -s support.
13-
# TODO: Add golint (https://github.com/golang/lint).
14-
# TODO: Add ineffassign (https://github.com/gordonklaus/ineffassign).
15-
# TODO: Add misspell (https://github.com/client9/misspell).
23+
# TODO: Add spell checking. The https://github.com/client9/misspell tool is what
24+
# we've used historically (via Go Report Card), but it seems like it's no longer
25+
# maintained and it's installation is a little non-trivial.
26+
1627
# TODO: Add custom code/comment structure validation.
1728

1829
# Done.

scripts/ci/commitlint/config.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"rules": {
3+
"header-max-length": [2, "always", 72],
4+
5+
"type-case": [2, "always", "lower-case"],
6+
"type-empty": [2, "never"],
7+
"type-enum": [
8+
2,
9+
"always",
10+
[
11+
"cli",
12+
"agent",
13+
"daemon",
14+
"sidecar",
15+
"core",
16+
"forward",
17+
"sync",
18+
"test",
19+
"tools",
20+
"git",
21+
"ci",
22+
"build",
23+
"docs",
24+
"deps",
25+
"style",
26+
"version"
27+
]
28+
],
29+
30+
"scope-empty": [2, "always"],
31+
32+
"subject-empty": [2, "never"],
33+
"subject-full-stop": [2, "never"],
34+
35+
"body-leading-blank": [2, "always"],
36+
"body-max-line-length": [2, "always", 72],
37+
"body-empty": [2, "never"],
38+
"body-case": [2, "always", "sentence-case"],
39+
40+
"footer-leading-blank": [2, "always"],
41+
"footer-max-line-length": [2, "always", 72]
42+
}
43+
}

scripts/ci/setup_docker.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# Exit immediately on failure.
44
set -e
55

6+
# Print Docker version information.
7+
docker version
8+
69
# Determine the operating system.
710
MUTAGEN_OS_NAME="$(go env GOOS)"
811

scripts/ci/setup_go.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
3+
# Exit immediately on failure.
4+
set -e
5+
6+
# Print the Go version.
7+
go version
8+
9+
# Pre-download Go modules.
10+
go mod download

scripts/ci/verify.sh

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/bin/bash
2+
3+
# Exit immediately on failure.
4+
set -e
5+
6+
# Print status information.
7+
echo "Performing commit verification"
8+
echo
9+
10+
# Track that we actually perform some sort of verification, because we don't
11+
# have an elegant way to verify that git rev-list succeeds when being used via
12+
# process substitution.
13+
PERFORMED_VERIFICATION="false"
14+
15+
# Loop over the relevant commits.
16+
while read commit; do
17+
# Print status information.
18+
echo "> Verifying ${commit}"
19+
20+
# Validate the commit message format.
21+
if git show --format="format:%B" --no-patch "${commit}" | commitlint --config scripts/ci/commitlint/config.json; then
22+
echo "Commit message is valid"
23+
else
24+
echo "Invalid commit message!"
25+
exit 1
26+
fi
27+
28+
# Verify that the expected sign-off is present.
29+
EXPECTED_SIGNOFF="$(git show "${commit}" --format="format:Signed-off-by: %an <%ae>" --no-patch)"
30+
if git show --summary "${commit}" | grep -q "${EXPECTED_SIGNOFF}"; then
31+
echo "Found valid sign-off"
32+
else
33+
echo "Missing sign-off!"
34+
exit 1
35+
fi
36+
37+
# Verify that a cryptographic signature is present.
38+
# TODO: It may be worth trying to corresponding GPG keys from GitHub to
39+
# verify that they match the commit author, but that's going to be tricky.
40+
# We'll also have to consider the possibility that the signatures were made
41+
# with OpenSSH keys, and I'm not sure how to import those for Git-based
42+
# verification. For now, we can just check the verified label on the GitHub
43+
# web interface.
44+
if [[ ! -z "$(git show --format="format:%GK" --no-patch "${commit}")" ]]; then
45+
echo "Found cryptographic signature"
46+
else
47+
echo "Missing or invalid cryptographic signature!"
48+
exit 1
49+
fi
50+
51+
# TODO: Perform spell checking on the commit message. This might be tricky
52+
# if there are technical or code terms in the message.
53+
54+
# Record that some verification was performed.
55+
PERFORMED_VERIFICATION="true"
56+
57+
# Output a separator line.
58+
echo
59+
done < <(git rev-list "${VERIFY_COMMIT_START}...${VERIFY_COMMIT_END}")
60+
61+
# Enforce that at least one commit was verified.
62+
if [[ "${PERFORMED_VERIFICATION}" == "false" ]]; then
63+
echo "No verification performed!"
64+
exit 1
65+
fi
66+
67+
# Print status information.
68+
echo "Commit verification succeeded!"

0 commit comments

Comments
 (0)