check-crates.sh 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #!/usr/bin/env bash
  2. # input:
  3. # env:
  4. # - CRATE_TOKEN
  5. # - COMMIT_RANGE
  6. if [[ -z $COMMIT_RANGE ]]; then
  7. echo "COMMIT_RANGE should be provided"
  8. exit 1
  9. fi
  10. if ! command -v toml &>/dev/null; then
  11. echo "not found toml-cli"
  12. cargo install toml-cli
  13. fi
  14. declare skip_patterns=(
  15. "Cargo.toml"
  16. "programs/sbf"
  17. )
  18. declare -A verified_crate_owners=(
  19. ["anza-team"]=1
  20. )
  21. # get Cargo.toml from git diff
  22. readarray -t files <<<"$(git diff "$COMMIT_RANGE" --diff-filter=AM --name-only | grep Cargo.toml)"
  23. printf "%s\n" "${files[@]}"
  24. error_count=0
  25. for file in "${files[@]}"; do
  26. read -r crate_name package_publish workspace < <(toml get "$file" . | jq -r '(.package.name | tostring)+" "+(.package.publish | tostring)+" "+(.workspace | tostring)')
  27. echo "=== $crate_name ($file) ==="
  28. if [[ $package_publish = 'false' ]]; then
  29. echo -e "⏩ skip (package_publish: $package_publish)\n"
  30. continue
  31. fi
  32. if [[ "$workspace" != "null" ]]; then
  33. echo -e "⏩ skip (is a workspace root)\n"
  34. continue
  35. fi
  36. for skip_pattern in "${skip_patterns[@]}"; do
  37. if [[ $file =~ ^$skip_pattern ]]; then
  38. echo -e "⏩ skip (match skip patterns)\n"
  39. continue 2
  40. fi
  41. done
  42. # crates.io will reject publication if certain fields are not populated
  43. # https://doc.rust-lang.org/cargo/reference/publishing.html#before-publishing-a-new-crate
  44. IFS=$'\t' read -r lic licf desc home repo < <(toml get "$file" . | jq -r "
  45. (.package.license | tojson)\
  46. +\"\t\"+(.package.license_file | tojson)\
  47. +\"\t\"+(.package.description | tojson)\
  48. +\"\t\"+(.package.homepage | tojson)\
  49. +\"\t\"+(.package.repository | tojson)\
  50. ")
  51. declare missing_metadata=()
  52. if [ "$lic" = "null" ] && [ "$licf" = "null" ]; then
  53. missing_metadata+=( "license" )
  54. else
  55. echo "✅ license"
  56. fi
  57. if [ "$desc" = "null" ]; then
  58. missing_metadata+=( "description" )
  59. else
  60. echo "✅ description"
  61. fi
  62. if [ "$home" = "null" ]; then
  63. missing_metadata+=( "homepage" )
  64. else
  65. echo "✅ homepage"
  66. fi
  67. if [ "$repo" = "null" ]; then
  68. missing_metadata+=( "repository" )
  69. else
  70. echo "✅ repository"
  71. fi
  72. if [ ${#missing_metadata[@]} -ne 0 ]; then
  73. echo "❌ $crate_name is missing the following metadata fields: ${missing_metadata[*]}"
  74. exit 1
  75. fi
  76. response=$(curl -s https://crates.io/api/v1/crates/"$crate_name"/owners)
  77. errors=$(echo "$response" | jq .errors)
  78. if [[ $errors != "null" ]]; then
  79. details=$(echo "$response" | jq .errors | jq -r ".[0].detail")
  80. if [[ $details = *"does not exist"* ]]; then
  81. ((error_count++))
  82. echo "❌ new crate $crate_name not found on crates.io. you can either
  83. 1. mark it as not for publication in its Cargo.toml
  84. [package]
  85. ...
  86. publish = false
  87. or
  88. 2. make a dummy publication.
  89. example:
  90. scripts/reserve-cratesio-package-name.sh \
  91. --token <GRIMES_CRATESIO_TOKEN> \
  92. lib solana-new-lib-crate
  93. see also: scripts/reserve-cratesio-package-name.sh --help
  94. "
  95. else
  96. ((error_count++))
  97. echo "❌ $response"
  98. fi
  99. else
  100. readarray -t owners <<<"$(echo "$response" | jq .users | jq -r ".[] | .login")"
  101. verified_owner_count=0
  102. unverified_owner_count=0
  103. for owner in "${owners[@]}"; do
  104. if [[ -z $owner ]]; then
  105. continue
  106. fi
  107. owner_id="$(echo "$owner" | awk '{print $1}')"
  108. if [[ ${verified_crate_owners[$owner_id]} ]]; then
  109. ((verified_owner_count++))
  110. echo "✅ $owner"
  111. else
  112. ((unverified_owner_count++))
  113. echo "❌ $owner"
  114. fi
  115. done
  116. if [[ ($unverified_owner_count -gt 0) ]]; then
  117. ((error_count++))
  118. echo "error: found unverified owner(s)"
  119. elif [[ ($verified_owner_count -le 0) ]]; then
  120. ((error_count++))
  121. echo "error: there are no verified owners"
  122. fi
  123. fi
  124. echo ""
  125. done
  126. if [ "$error_count" -eq 0 ]; then
  127. echo "success"
  128. exit 0
  129. else
  130. exit 1
  131. fi