diff --git a/.github/workflows/crate-check.yml b/.github/workflows/crate-check.yml new file mode 100644 index 0000000000..09744b68dc --- /dev/null +++ b/.github/workflows/crate-check.yml @@ -0,0 +1,52 @@ +name: crate-check + +on: + push: + branches: + - master + pull_request: + branches: + - master + paths: + - "**/Cargo.toml" + - ".github/workflows/crate-check.yml" + +jobs: + check: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Get commit range (push) + if: ${{ github.event_name == 'push' }} + run: | + echo "COMMIT_RANGE=$GITHUB_SHA" >> $GITHUB_ENV + + - name: Get commit range (pull_request) + if: ${{ github.event_name == 'pull_request' }} + run: | + echo "COMMIT_RANGE=${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV + + - name: Setup Rust + shell: bash + run: | + source ci/rust-version.sh stable + rustup default $rust_stable + + - name: Install toml-cli + shell: bash + run: | + cargo install toml-cli + + - run: | + ci/check-crates.sh + + error_reporting: + needs: + - check + if: failure() && github.event_name == 'push' + uses: ./.github/workflows/error-reporting.yml + secrets: + WEBHOOK: ${{ secrets.SLACK_ERROR_REPORTING_WEBHOOK }} diff --git a/ci/check-crates.sh b/ci/check-crates.sh new file mode 100755 index 0000000000..3248ebfb96 --- /dev/null +++ b/ci/check-crates.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash + +# input: +# env: +# - CRATE_TOKEN +# - COMMIT_RANGE + +if [[ -z $COMMIT_RANGE ]]; then + echo "COMMIT_RANGE should be provided" + exit 1 +fi + +if ! command -v toml &>/dev/null; then + echo "not found toml-cli" + cargo install toml-cli +fi + +declare skip_patterns=( + "Cargo.toml" + "programs/sbf" +) + +declare -A verified_crate_owners=( + ["solana-grimes"]=1 +) + +# get Cargo.toml from git diff +readarray -t files <<<"$(git diff "$COMMIT_RANGE" --diff-filter=AM --name-only | grep Cargo.toml)" +printf "%s\n" "${files[@]}" + +error_count=0 +for file in "${files[@]}"; do + read -r crate_name package_publish workspace < <(toml get "$file" . | jq -r '(.package.name | tostring)+" "+(.package.publish | tostring)+" "+(.workspace | tostring)') + echo "=== $crate_name ($file) ===" + + if [[ $package_publish = 'false' ]]; then + echo -e "⏩ skip (package_publish: $package_publish)\n" + continue + fi + + if [[ "$workspace" != "null" ]]; then + echo -e "⏩ skip (is a workspace root)\n" + continue + fi + + for skip_pattern in "${skip_patterns[@]}"; do + if [[ $file =~ ^$skip_pattern ]]; then + echo -e "⏩ skip (match skip patterns)\n" + continue 2 + fi + done + + result="$(cargo owner --list -q "$crate_name" --token "$CRATE_TOKEN" 2>&1)" + if [[ $result =~ ^error ]]; then + if [[ $result == *"Not Found"* ]]; then + ((error_count++)) + echo "❌ new crate $crate_name not found on crates.io. you can either + +1. mark it as not for publication in its Cargo.toml + + [package] + ... + publish = false + +or + +2. make a dummy publication with these steps: + + a. Create a empty crate locally with this template + + [package] + name = \"\" + version = \"0.0.1\" + description = \"\" + authors = [\"Solana Maintainers \"] + repository = \"https://github.com/solana-labs/solana\" + license = \"Apache-2.0\" + homepage = \"https://solana.com/\" + documentation = \"https://docs.rs/\" + edition = \"2021\" + + b. cargo publish --token +" + else + ((error_count++)) + echo "❌ $result" + fi + else + readarray -t owners <<<"$result" + + verified_owner_count=0 + unverified_owner_count=0 + for owner in "${owners[@]}"; do + if [[ -z $owner ]]; then + continue + fi + owner_id="$(echo "$owner" | awk '{print $1}')" + if [[ ${verified_crate_owners[$owner_id]} ]]; then + ((verified_owner_count++)) + echo "✅ $owner" + else + ((unverified_owner_count++)) + echo "❌ $owner" + fi + done + + if [[ ($unverified_owner_count -gt 0) ]]; then + ((error_count++)) + echo "error: found unverified owner(s)" + elif [[ ($verified_owner_count -le 0) ]]; then + ((error_count++)) + echo "error: there are no verified owners" + fi + fi + echo "" +done + +if [ "$error_count" -eq 0 ]; then + echo "success" + exit 0 +else + exit 1 +fi