Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: add CI with GitHub Actions #1

Merged
merged 1 commit into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: CI

on:
push:
branches:
- '*'
pull_request:

jobs:
report:
needs:
- lint-aux
- extract-changelog
- rustfmt
- clippy
- build-and-test
- build-no_std
- package-crate
# 'always()' is needed because GitHub treats a skipped job (due to a failed
# dependency) a success.
if: always()
runs-on: ubuntu-22.04
steps:
- name: Report status
env:
NEEDS_JSON: ${{ toJson(needs) }}
# Make sure all dependencies succeeded.
run: jq --exit-status 'all(.result == "success")' <<< "$NEEDS_JSON"

lint-aux:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install lint utilities
run: sudo npm install -g markdownlint-cli
- name: Install Rust
run: ./ci/install-rust.sh stable --profile minimal
- run: ./ci/lint-aux.sh

extract-changelog:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: ./ci/install-rust.sh stable --profile minimal
- run: ./ci/extract-changelog.sh
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: version-changelog
path: version-changelog
if-no-files-found: error

rustfmt:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: ./ci/install-rust.sh stable --profile minimal -c rustfmt
- run: cargo fmt --all -- --check

clippy:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends libmpfr-dev
- name: Install Rust
run: ./ci/install-rust.sh stable --profile minimal -c clippy
- run: ./ci/clippy.sh

build-and-test:
runs-on: ubuntu-22.04
strategy:
matrix:
include:
- rust-version: msrv
- rust-version: stable
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y --no-install-recommends gcc-multilib libmpfr-dev libmpfr-dev:i386
- name: Install Rust
run: |
./ci/install-rust.sh "${{ matrix.rust-version }}" --profile minimal \
-t x86_64-unknown-linux-gnu \
-t i586-unknown-linux-gnu
- run: ./ci/build-and-test.sh

build-no_std:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: ./ci/install-rust.sh stable --profile minimal -t x86_64-unknown-none
- run: cargo build -p fpmath --target x86_64-unknown-none

package-crate:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install Rust
run: ./ci/install-rust.sh stable --profile minimal
- run: ./ci/package-crate.sh
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: packaged-crate
path: output
if-no-files-found: error
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# fpmath

[![GitHub Actions Status](https://github.com/eduardosm/rust-fpmath/workflows/CI/badge.svg)](https://github.com/eduardosm/rust-fpmath/actions)
![MSRV](https://img.shields.io/badge/rustc-1.70+-lightgray.svg)

fpmath is a pure-Rust floating point library that implements math functions for
`f32` and `f64`.

Expand Down
34 changes: 34 additions & 0 deletions ci/build-and-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -euo pipefail

. ci/utils.sh

export RUSTDOCFLAGS="-D warnings"

begin_group "Fetch dependencies"
cargo fetch --locked
end_group

begin_group "Build"
cargo build --workspace --all-targets --frozen
end_group

begin_group "Doc"
cargo doc --workspace --frozen
end_group

begin_group "Generate test data"
./run-all-test-data-gen.sh
end_group

begin_group "Test x86_64"
cargo test --workspace --target x86_64-unknown-linux-gnu --frozen
end_group

begin_group "Test i586 debug"
cargo test --workspace --target i586-unknown-linux-gnu --frozen
end_group

begin_group "Test i586 release"
cargo test --workspace --target i586-unknown-linux-gnu --release --frozen
end_group
12 changes: 12 additions & 0 deletions ci/clippy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail

. ci/utils.sh

begin_group "Fetch dependencies"
cargo fetch --locked
end_group

begin_group "Run clippy"
cargo clippy --workspace --all-targets --frozen -- -D warnings
end_group
25 changes: 25 additions & 0 deletions ci/extract-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail

. ci/utils.sh

trim_empty_lines() {
awk 'NF { x = 1 } x' | tac | awk 'NF { x = 1 } x' | tac
}

version="$(crate_version fpmath)"
version="${version%-pre}"

input_file="CHANGELOG.md"
output_file="version-changelog"

# shellcheck disable=SC2016
awk_script='/^##[^#]/ { if (x) { exit }; if ($2 == ver) { x = 1; next } } x'
awk -v ver="$version" "$awk_script" "$input_file" | trim_empty_lines > "$output_file"

if [ ! -s "$output_file" ]; then
echo "Changelog for version $version is empty"
exit 1
fi

echo "Extracted changelog for version $version"
12 changes: 12 additions & 0 deletions ci/install-rust.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail

rust_version="$(cat "ci/rust-versions/${1}.txt")"
shift

echo "Installing Rust $rust_version"
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain "$rust_version" "$@"

if [ -n "${GITHUB_PATH+x}" ]; then
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
fi
73 changes: 73 additions & 0 deletions ci/lint-aux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -euo pipefail

. ci/utils.sh

begin_group "Check crate version"

crate="fpmath"
version="$(crate_version "$crate")"

if [[ ! "$version" =~ ^[0-9]\.[0-9]\.[0-9](-pre)?$ ]]; then
echo "Invalid version for $crate"
exit 1
fi

if [[ "$version" = *-pre ]]; then
publish_ok="$(crate_metadata "$crate" | jq '.publish == []')"
else
publish_ok="$(crate_metadata "$crate" | jq '.publish == null')"
fi
if [ "$publish_ok" != "true" ]; then
echo "Invalid publish for $crate"
exit 1
fi

changelog_date="$(awk -v ver="${version%-pre}" '/^## / { if ($2 == ver) print $3 }' CHANGELOG.md)"
if [[ "$version" = *-pre ]]; then
if [ "$changelog_date" != "(unreleased)" ]; then
echo "Invalid date in changelog for version $version"
exit 1
fi
else
if [[ ! "$changelog_date" =~ \([0-9]{4}-[0-9]{2}-[0-9]{2}\) ]]; then
echo "Invalid date in changelog for version $version"
exit 1
fi
fi

end_group

begin_group "Check MSRV consistency"

msrv="$(cat ci/rust-versions/msrv.txt)"
msrv="${msrv%.*}"

if [[ "$(grep img.shields.io/badge/rustc README.md)" != *"rustc-$msrv+-lightgray.svg"* ]]; then
echo "Incorrect MSRV in README.md"
exit 1
fi

crates=(
"dev-mpfr"
"fpmath"
"fpmath-tests"
"generator"
)

for crate in "${crates[@]}"; do
if [ "$(crate_metadata "$crate" | jq -r '.rust_version')" != "$msrv" ]; then
echo "Incorrect rust-version for $crate"
exit 1
fi
done

end_group

begin_group "Check shell scripts with shellcheck"
find . -type f -name "*.sh" -not -path "./.git/*" -print0 | xargs -0 shellcheck
end_group

begin_group "Check markdown documents with markdownlint"
find . -type f -name "*.md" -not -path "./.git/*" -print0 | xargs -0 markdownlint
end_group
33 changes: 33 additions & 0 deletions ci/package-crate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail

. ci/utils.sh

mkdir checkout
find . -mindepth 1 -maxdepth 1 -not -name checkout -print0 | xargs -0 mv -t checkout
cd checkout

pkgs_dir="$(pwd)/../packages"
out_dir="../output"

begin_group "Fetch dependencies"
cargo fetch --locked
end_group

begin_group "Vendor dependencies"
mkdir ../.cargo
cargo vendor --frozen "$pkgs_dir" > ../.cargo/config.toml
end_group

mkdir "$out_dir"

crate="fpmath"
version="$(crate_version "$crate")"

begin_group "Package $crate"
cargo package -p "$crate" --frozen
tar -xf "target/package/$crate-$version.crate" -C "$pkgs_dir"
pkg_checksum="$(sha256sum "target/package/$crate-$version.crate" | awk '{print $1}')"
echo "{\"files\":{},\"package\":\"$pkg_checksum\"}" > "$pkgs_dir/$crate-$version/.cargo-checksum.json"
cp -t "$out_dir" "target/package/$crate-$version.crate"
end_group
1 change: 1 addition & 0 deletions ci/rust-versions/msrv.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.70.0
1 change: 1 addition & 0 deletions ci/rust-versions/stable.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.81.0
47 changes: 47 additions & 0 deletions ci/utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# shellcheck shell=bash

echo_stderr() {
echo "$@" >&2
}

begin_group() {
if [ $# -ne 1 ]; then
echo_stderr "Invalid use of $0"
exit 1
fi
echo "::group::$1"
}

# shellcheck disable=SC2120
end_group() {
if [ $# -ne 0 ]; then
echo_stderr "Invalid use of $0"
exit 1
fi
echo "::endgroup::"
}

crate_metadata() {
if [ $# -ne 1 ]; then
echo_stderr "Invalid use of $0"
exit 1
fi
crate="$1"
cargo metadata --format-version 1 --locked --no-deps | jq -r "
[ .packages[] | select(.name == \"$crate\") ] |
if length == 1 then
first
else
error(\"expected exactly one package named $crate\")
end
"
}

crate_version() {
if [ $# -ne 1 ]; then
echo_stderr "Invalid use of $0"
exit 1
fi
crate="$1"
crate_metadata "$crate" | jq -r '.version'
}