name: CI
on:
schedule:
- cron: '0 0 * * 0'
push:
branches:
- master
- staging
- trying
tags:
- 'v[0-9]+.[0-9]+.[0-9]+**'
pull_request:
jobs:
rustfmt:
name: Rustfmt
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up `stable-x86_64-unknown-linux-gnu`
uses: actions-rs/toolchain@v1
with:
toolchain: stable-x86_64-unknown-linux-gnu
default: true
profile: minimal
components: rustfmt
- name: cargo-fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
build:
strategy:
fail-fast: false
matrix:
job-name:
- stable-x86_64-pc-windows-msvc
- stable-x86_64-apple-darwin
- stable-x86_64-unknown-linux-gnu
include:
- { job-name: stable-x86_64-pc-windows-msvc , exe-suffix: .exe, os: windows-2019 }
- { job-name: stable-x86_64-apple-darwin , exe-suffix: '' , os: macos-10.15 }
- { job-name: stable-x86_64-unknown-linux-gnu, exe-suffix: '' , os: ubuntu-20.04 }
env:
NIGHTLY_TOOLCHAIN: nightly-2021-08-10
name: ${{ matrix.job-name }}
runs-on: ${{ matrix.os }}
steps:
- name: Disable `core.autocrlf`
run: git config --global core.autocrlf false
if: matrix.os == 'windows-2019'
- name: Checkout
uses: actions/checkout@v2
- name: Set up `stable`
id: install-toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
default: true
profile: minimal
components: clippy
- name: Set up `${{ env.NIGHTLY_TOOLCHAIN }}`
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.NIGHTLY_TOOLCHAIN }}
profile: minimal
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Resolve `cargo-udeps ^0.1`
id: resolve-versions
run: |
python - cargo-udeps@^0.1 <<'EOF'
from argparse import ArgumentParser
import json
import urllib.request
import re
CRATE_SPEC = re.compile(r'\A([a-zA-Z0-9_-]+)@\^([0-9]+)\.([0-9]+)\Z')
def main() -> None:
parser = ArgumentParser()
parser.add_argument('specs', metavar='PSEUDO_SPECS', type=CrateSpec, nargs='+')
print('\n'.join(map(resolve, parser.parse_args().specs)))
class CrateSpec:
def __init__(self, s: str):
if not (m := CRATE_SPEC.match(s)):
raise RuntimeError(f'the version must be `{CRATE_SPEC.pattern}`')
self.package_name = m.group(1)
self.version_req_major = int(m.group(2))
self.version_req_minor = int(m.group(3))
def resolve(spec: CrateSpec) -> str:
with urllib.request.urlopen(f'https://crates.io/api/v1/crates/{spec.package_name}') as res:
versions = json.load(res)['versions']
matched = set()
for version in versions:
major, minor, patch_pre_build = version['num'].split('.')
major, minor = (int(major), int(minor))
if ((major, spec.version_req_major) == (0, 0) and minor == spec.version_req_minor or major == spec.version_req_major and minor >= spec.version_req_minor) and patch_pre_build.isdecimal():
matched.add((minor, int(patch_pre_build)))
if not matched:
raise RuntimeError(f'No such package: `{spec.package_name} ^{spec.version_req_major}.{spec.version_req_minor}`')
minor, patch = max(matched)
return f'::set-output name={spec.package_name}::{spec.version_req_major}.{minor}.{patch}'
if __name__ == '__main__':
main()
EOF
shell: bash
- name: Cache for cargo-udeps
uses: actions/cache@v2
with:
path: |
~/.cargo/.crates.toml
~/.cargo/.crates2.json
~/.cargo/bin/cargo-udeps${{ matrix.exe-suffix }}
key: build-crates-${{ matrix.job-name }}-${{ steps.resolve-versions.outputs.cargo-udeps }}
- name: Cache for build cache
uses: actions/cache@v2
with:
path: |
~/.cargo/git
~/.cargo/registry
./target
key: build-build-${{ matrix.job-name }}-${{ steps.install-toolchain.outputs.rustc_hash }}-${{ hashFiles('./Cargo.*') }}
- name: Install cargo-udeps v${{ steps.resolve-versions.outputs.cargo-udeps }}
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-udeps --version '=${{ steps.resolve-versions.outputs.cargo-udeps }}'
- name: cargo-clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets -- -D warnings
- name: cargo-test
uses: actions-rs/cargo@v1
with:
command: test
args: --no-fail-fast
env:
RUST_BACKTRACE: full
- name: cargo-udeps
uses: actions-rs/cargo@v1
with:
command: udeps
args: --all-targets
toolchain: ${{ env.NIGHTLY_TOOLCHAIN }}
upload-archives:
strategy:
fail-fast: false
matrix:
target-triple:
- x86_64-pc-windows-msvc
- x86_64-apple-darwin
- x86_64-unknown-linux-gnu
include:
- { target-triple: x86_64-pc-windows-msvc , host-triple: x86_64-pc-windows-msvc , os: windows-2019 }
- { target-triple: x86_64-apple-darwin , host-triple: x86_64-apple-darwin , os: macos-10.15 }
- { target-triple: x86_64-unknown-linux-gnu, host-triple: x86_64-unknown-linux-gnu, os: ubuntu-20.04 }
name: Upload (${{ matrix.target-triple }})
runs-on: ${{ matrix.os }}
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Disable `core.autocrlf`
run: git config --global core.autocrlf false
if: matrix.os == 'windows-2019'
- name: Checkout
uses: actions/checkout@v2
- name: 'Set up `stable-${{ matrix.host-triple }}` (target: `${{ matrix.target-triple }}`)'
uses: actions-rs/toolchain@v1
with:
toolchain: stable-${{ matrix.host-triple }}
target: ${{ matrix.target-triple }}
default: true
profile: minimal
- name: cargo-install
uses: actions-rs/cargo@v1
with:
command: install
args: --path . --target ${{ matrix.target-triple }} -v --locked
- name: Create an asset
id: asset
run: |
BIN_TARGET=cargo-executable-payload
if ${{ contains(matrix.target-triple, 'pc-windows') }}; then
DOT_EXE=.exe
fi
ASSET_STEM="$BIN_TARGET-${GITHUB_REF#refs/tags/}-${{ matrix.target-triple }}"
git archive -o "./$ASSET_STEM.tar" --prefix "$ASSET_STEM/" HEAD
tar -xf "./$ASSET_STEM.tar"
mv "$HOME/.cargo/bin/$BIN_TARGET$DOT_EXE" "./$ASSET_STEM/"
if ${{ contains(matrix.target-triple, 'pc-windows') }}; then
ASSET="$ASSET_STEM.zip"
7z a "$ASSET" "./$ASSET_STEM"
zipinfo "./$ASSET"
else
ASSET="$ASSET_STEM.tar.gz"
tar -czvf "./$ASSET" "./$ASSET_STEM"
fi
echo "::set-output name=asset::$ASSET"
shell: bash
- name: Upload the artifact
uses: actions/upload-artifact@v2
with:
name: assets
path: ${{ steps.asset.outputs.asset }}
upload-release-notes:
name: Upload the release notes
runs-on: ubuntu-20.04
if: ${{ startsWith(github.ref, 'refs/tags/') }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Prepare release notes
run: |
from pathlib import Path
PATH = Path('./CHANGELOG.md')
output = ''
if PATH.exists():
with open(PATH) as file:
changelog = file.read()
inside_subsection = False
for line in changelog.splitlines():
is_h2 = line.startswith('## ')
if not inside_subsection and is_h2:
inside_subsection = True
elif inside_subsection and not is_h2:
output += line + '\n'
elif inside_subsection:
break
with open('./release-notes.md', 'w') as file:
file.write(f'{output.strip()}\n')
shell: python
- name: Upload the release notes
uses: actions/upload-artifact@v2
with:
name: release-notes
path: release-notes.md
release:
name: GitHub Release
runs-on: ubuntu-20.04
needs: [rustfmt, build, upload-archives, upload-release-notes]
steps:
- name: Download the assets
uses: actions/download-artifact@v2
with:
name: assets
path: ./assets
- name: Download the release notes
uses: actions/download-artifact@v2
with:
name: release-notes
path: .
- name: GH Release
uses: softprops/action-gh-release@v1
with:
body_path: ./release-notes.md
files: ./assets/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}