Make Linux Plugin workflow (grpc/grpc-web)
The Make Linux Plugin workflow from grpc/grpc-web, explained and optimized by Latchkey.
- C
- CI health grade
- 69/100
- Health score
- 1
- Job per trigger
- 2
- Fixes in the optimized version
In short
- CI health: C (fair)
- The optimized version below adds run de-duplication and job timeouts.
What it does
This is the Make Linux Plugin workflow from the grpc/grpc-web repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Make Linux Plugin
on:
push:
paths:
- .github/workflows/make-plugin-linux.yml
pull_request:
paths:
- .github/workflows/make-plugin-linux.yml
workflow_dispatch:
inputs:
version_number:
description: 'Version number'
required: true
default: '2.x.x'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-22.04-arm]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Compute VERSION_NUMBER
run: |
INPUT_VERSION="${{ github.event.inputs.version_number }}"
if [ -n "$INPUT_VERSION" ]; then
VERSION="$INPUT_VERSION"
else
VERSION="$GITHUB_REF_NAME"
fi
VERSION="${VERSION//\//-}"
echo "VERSION_NUMBER=$VERSION" >> "$GITHUB_ENV"
echo "Computed VERSION_NUMBER=$VERSION"
- name: Compute ARCH suffix and artifact name
id: meta
run: |
ARCH=$(uname -m)
case "$ARCH" in
aarch64|arm64)
ARCH_SUFFIX="aarch64"
;;
x86_64|amd64)
ARCH_SUFFIX="x86_64"
;;
*)
echo "Unsupported architecture: $ARCH" >&2
exit 1
;;
esac
ARTIFACT="protoc-gen-grpc-web-${VERSION_NUMBER}-linux-${ARCH_SUFFIX}"
echo "ARTIFACT=$ARTIFACT" >> "$GITHUB_ENV"
echo "artifact=$ARTIFACT" >> "$GITHUB_OUTPUT"
echo "Will produce artifact: $ARTIFACT"
- name: Install Bazelisk (Bazel)
run: |
sudo apt-get update
sudo apt-get install -y unzip zip
ARCH=$(uname -m)
case "$ARCH" in
aarch64|arm64)
BAZELISK_URL="https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-arm64"
;;
x86_64|amd64)
BAZELISK_URL="https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64"
;;
*)
echo "Unsupported architecture for Bazelisk: $ARCH" >&2
exit 1
;;
esac
echo "Downloading Bazelisk from $BAZELISK_URL"
sudo curl -L -o /usr/local/bin/bazelisk "$BAZELISK_URL"
sudo chmod +x /usr/local/bin/bazelisk
# Also provide `bazel` symlink for tools that expect it
sudo ln -sf /usr/local/bin/bazelisk /usr/local/bin/bazel
bazelisk version
- name: Build protoc-gen-grpc-web with Bazel (older glibc baseline)
run: |
# Partially static link libstdc++/libgcc to reduce GLIBCXX constraints
bazelisk build \
--linkopt=-static-libstdc++ \
--linkopt=-static-libgcc \
//javascript/net/grpc/web/generator:protoc-gen-grpc-web
- name: Move artifact
run: |
mv bazel-bin/javascript/net/grpc/web/generator/protoc-gen-grpc-web \
./${ARTIFACT}
- name: Generate sha256
run: |
openssl dgst -sha256 -r -out ${ARTIFACT}.sha256 \
${ARTIFACT}
- name: Verify sha256
run: sha256sum -c ${ARTIFACT}.sha256
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ steps.meta.outputs.artifact }}
path: protoc-gen-grpc-web*The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Make Linux Plugin
on:
push:
paths:
- .github/workflows/make-plugin-linux.yml
pull_request:
paths:
- .github/workflows/make-plugin-linux.yml
workflow_dispatch:
inputs:
version_number:
description: 'Version number'
required: true
default: '2.x.x'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-22.04-arm]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Compute VERSION_NUMBER
run: |
INPUT_VERSION="${{ github.event.inputs.version_number }}"
if [ -n "$INPUT_VERSION" ]; then
VERSION="$INPUT_VERSION"
else
VERSION="$GITHUB_REF_NAME"
fi
VERSION="${VERSION//\//-}"
echo "VERSION_NUMBER=$VERSION" >> "$GITHUB_ENV"
echo "Computed VERSION_NUMBER=$VERSION"
- name: Compute ARCH suffix and artifact name
id: meta
run: |
ARCH=$(uname -m)
case "$ARCH" in
aarch64|arm64)
ARCH_SUFFIX="aarch64"
;;
x86_64|amd64)
ARCH_SUFFIX="x86_64"
;;
*)
echo "Unsupported architecture: $ARCH" >&2
exit 1
;;
esac
ARTIFACT="protoc-gen-grpc-web-${VERSION_NUMBER}-linux-${ARCH_SUFFIX}"
echo "ARTIFACT=$ARTIFACT" >> "$GITHUB_ENV"
echo "artifact=$ARTIFACT" >> "$GITHUB_OUTPUT"
echo "Will produce artifact: $ARTIFACT"
- name: Install Bazelisk (Bazel)
run: |
sudo apt-get update
sudo apt-get install -y unzip zip
ARCH=$(uname -m)
case "$ARCH" in
aarch64|arm64)
BAZELISK_URL="https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-arm64"
;;
x86_64|amd64)
BAZELISK_URL="https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64"
;;
*)
echo "Unsupported architecture for Bazelisk: $ARCH" >&2
exit 1
;;
esac
echo "Downloading Bazelisk from $BAZELISK_URL"
sudo curl -L -o /usr/local/bin/bazelisk "$BAZELISK_URL"
sudo chmod +x /usr/local/bin/bazelisk
# Also provide `bazel` symlink for tools that expect it
sudo ln -sf /usr/local/bin/bazelisk /usr/local/bin/bazel
bazelisk version
- name: Build protoc-gen-grpc-web with Bazel (older glibc baseline)
run: |
# Partially static link libstdc++/libgcc to reduce GLIBCXX constraints
bazelisk build \
--linkopt=-static-libstdc++ \
--linkopt=-static-libgcc \
//javascript/net/grpc/web/generator:protoc-gen-grpc-web
- name: Move artifact
run: |
mv bazel-bin/javascript/net/grpc/web/generator/protoc-gen-grpc-web \
./${ARTIFACT}
- name: Generate sha256
run: |
openssl dgst -sha256 -r -out ${ARTIFACT}.sha256 \
${ARTIFACT}
- name: Verify sha256
run: sha256sum -c ${ARTIFACT}.sha256
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ steps.meta.outputs.artifact }}
path: protoc-gen-grpc-web*
What changed
- Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
Left runs-on as written on the build job: matrix.os mixes Linux with arm64, which Latchkey does not run. Point only the Linux legs at Latchkey, for example with a matrix include entry that sets the runner.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
- Network fetches
This workflow runs 1 job (2 with the matrix expanded) per trigger. 1 of the 2 runs on a standard GitHub-hosted Linux x64 runner, which in a private repository bills $0.006 a minute against $0.0025 on latchkey-small, 58% lower; in a public repository like this one it is free. 1 of the 2 runs on arm64, which Latchkey does not offer, so that one stays where it is. Estimate the monthly difference with your own run counts.
Actions used in this workflow
- actions/checkout
- actions/upload-artifact