From 46f66f3da17966c90374fc325f9560d90f05d45b Mon Sep 17 00:00:00 2001 From: Ayush Date: Thu, 7 Nov 2024 17:12:11 +0530 Subject: [PATCH 1/2] fix: Solana Native and Steel Action should only work on changes. (#325) * run actions only when project is added or changed * test actions * solana version matrix workaround * try action fix * rename job names for setup --- .github/workflows/solana-native.yml | 293 +++++++++++++----- .github/workflows/steel.yml | 293 +++++++++++++----- .husky/pre-commit | 3 - CONTRIBUTING.md | 4 +- basics/hello-solana/native/package.json | 2 +- .../native/tests/{test.ts => index.test.ts} | 0 basics/hello-solana/steel/package.json | 2 +- .../steel/tests/{test.ts => index.test.ts} | 0 8 files changed, 436 insertions(+), 161 deletions(-) rename basics/hello-solana/native/tests/{test.ts => index.test.ts} (100%) rename basics/hello-solana/steel/tests/{test.ts => index.test.ts} (100%) diff --git a/.github/workflows/solana-native.yml b/.github/workflows/solana-native.yml index 5e79ae979..c3462dd52 100644 --- a/.github/workflows/solana-native.yml +++ b/.github/workflows/solana-native.yml @@ -11,107 +11,246 @@ on: branches: - main +env: + MAX_JOBS: 64 + MIN_PROJECTS_PER_JOB: 4 + MIN_PROJECTS_FOR_MATRIX: 4 + jobs: - build: + changes: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - solana-version: [stable] + permissions: + pull-requests: read + outputs: + changed_projects: ${{ steps.analyze.outputs.changed_projects }} + total_projects: ${{ steps.analyze.outputs.total_projects }} + matrix: ${{ steps.matrix.outputs.matrix }} steps: - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + - uses: dorny/paths-filter@v3 + id: changes + if: github.event_name == 'pull_request' with: - node-version: ${{ matrix.node-version }} - check-latest: true - - uses: heyAyushh/setup-solana@v5.5 - with: - solana-cli-version: ${{ matrix.solana-version }} - - run: solana -V - shell: bash - - name: Install pnpm + list-files: shell + filters: | + native: + - added|modified: '**/native/**' + workflow: + - added|modified: '.github/workflows/solana-native.yml' + - name: Analyze Changes + id: analyze run: | - npm install --global pnpm - - name: Build Native programs + # Generate ignore pattern, excluding comments + ignore_pattern=$(grep -v '^#' .github/.ghaignore | grep -v '^$' | tr '\n' '|' | sed 's/|$//') + echo "Ignore pattern: $ignore_pattern" + + function get_projects() { + find . -type d -name "native" | grep -vE "$ignore_pattern" | sort + } + + # Determine which projects to build and test + if [[ "${{ github.event_name }}" == "push" || "${{ github.event_name }}" == "schedule" || "${{ steps.changes.outputs.workflow }}" == "true" ]]; then + projects=$(get_projects) + elif [[ "${{ steps.changes.outputs.native }}" == "true" ]]; then + changed_files=(${{ steps.changes.outputs.native_files }}) + projects=$(for file in "${changed_files[@]}"; do dirname "${file}" | grep native | sed 's#/native/.*#/native#g'; done | grep -vE "$ignore_pattern" | sort -u) + else + projects="" + fi + + # Output project information + if [[ -n "$projects" ]]; then + echo "Projects to build and test" + echo "$projects" + total_projects=$(echo "$projects" | wc -l) + echo "Total projects: $total_projects" + echo "total_projects=$total_projects" >> $GITHUB_OUTPUT + echo "changed_projects=$(echo "$projects" | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + else + echo "No projects to build and test." + echo "total_projects=0" >> $GITHUB_OUTPUT + echo "changed_projects=[]" >> $GITHUB_OUTPUT + fi + - name: Generate matrix + id: matrix run: | - declare -a ProjectDirs=($(find . -type d -name "native"| grep -v -f <(grep . .github/.ghaignore | grep -v '^$'))) - echo "Projects to Build:" - printf "%s\n" "${ProjectDirs[@]}" - for projectDir in "${ProjectDirs[@]}"; do - echo " - ******** - Building $projectDir - ********" - cd $projectDir - if pnpm build; then - echo "Build succeeded for $projectDir." - else - failed=true - failed_builds+=($projectDir) - echo "Build failed for $projectDir. Continuing with the next program." - fi - cd - > /dev/null - done - if [ "$failed" = true ]; then - echo "Programs that failed building:" - printf "%s\n" "${failed_builds[@]}" - exit 1 + total_projects=${{ steps.analyze.outputs.total_projects }} + max_jobs=${{ env.MAX_JOBS }} + min_projects_per_job=${{ env.MIN_PROJECTS_PER_JOB }} + min_projects_for_matrix=${{ env.MIN_PROJECTS_FOR_MATRIX }} + + if [ "$total_projects" -lt "$min_projects_for_matrix" ]; then + echo "matrix=[0]" >> $GITHUB_OUTPUT else - echo "All programs built successfully." + projects_per_job=$(( (total_projects + max_jobs - 1) / max_jobs )) + projects_per_job=$(( projects_per_job > min_projects_per_job ? projects_per_job : min_projects_per_job )) + num_jobs=$(( (total_projects + projects_per_job - 1) / projects_per_job )) + + indices=$(seq 0 $(( num_jobs - 1 ))) + echo "matrix=[$(echo $indices | tr ' ' ',')]" >> $GITHUB_OUTPUT fi - shell: bash - test: + build-and-test: + needs: changes + if: needs.changes.outputs.total_projects != '0' runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - node-version: [20.x] - solana-version: [1.18.17, stable] + index: ${{ fromJson(needs.changes.outputs.matrix) }} + name: build-and-test-group-${{ matrix.index }} + outputs: + failed_projects: ${{ steps.set-failed.outputs.failed_projects }} steps: - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 20.x check-latest: true - - uses: heyAyushh/setup-solana@v5.4 - with: - solana-cli-version: ${{ matrix.solana-version }} - - run: solana block - shell: bash - - name: Install pnpm + - name: Setup build environment + id: setup run: | + # Create the build and test function + cat << 'EOF' > build_and_test.sh + function build_and_test() { + local project=$1 + local solana_version=$2 + echo "Building and Testing $project with Solana $solana_version" + cd "$project" || return 1 + + # Install dependencies + if ! pnpm install --frozen-lockfile; then + echo "::error::pnpm install failed for $project" + echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + # Build + if ! pnpm build; then + echo "::error::build failed for $project" + echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + # Test + if ! pnpm build-and-test; then + echo "::error::tests failed for $project" + echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + echo "Build and tests succeeded for $project with $solana_version version." + cd - > /dev/null + return 0 + } + + function process_projects() { + local solana_version=$1 + + readarray -t all_projects < <(echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]?') + start_index=$(( ${{ matrix.index }} * ${{ env.MIN_PROJECTS_PER_JOB }} )) + end_index=$(( start_index + ${{ env.MIN_PROJECTS_PER_JOB }} )) + end_index=$(( end_index > ${{ needs.changes.outputs.total_projects }} ? ${{ needs.changes.outputs.total_projects }} : end_index )) + + echo "Projects to build and test in this job" + for i in $(seq $start_index $(( end_index - 1 ))); do + echo "${all_projects[$i]}" + done + + failed=false + for i in $(seq $start_index $(( end_index - 1 ))); do + echo "::group::Building and testing ${all_projects[$i]}" + if ! build_and_test "${all_projects[$i]}" "$solana_version"; then + failed=true + fi + echo "::endgroup::" + done + + return $([ "$failed" = true ] && echo 1 || echo 0) + } + EOF + + # Make the script executable + chmod +x build_and_test.sh + + # Install pnpm npm install --global pnpm - - name: Test solana native programs + - name: Setup Solana stable + uses: heyAyushh/setup-solana@v5.5 + with: + solana-cli-version: stable + - name: Build and Test with Stable + run: | + source build_and_test.sh + solana -V + rustc -V + process_projects "stable" + - name: Setup Solana 1.18.17 + uses: heyAyushh/setup-solana@v5.5 + with: + solana-cli-version: 1.18.17 + - name: Build and Test with 1.18.17 run: | + source build_and_test.sh solana -V rustc -V - declare -a ProjectDirs=($(find . -type d -name "native"| grep -v -f <(grep . .github/.ghaignore | grep -v '^$'))) - echo "Projects to Test:" - printf "%s\n" "${ProjectDirs[@]}" - for projectDir in "${ProjectDirs[@]}"; do - echo " - ******** - Testing $projectDir - ********" - cd $projectDir - pnpm install --frozen-lockfile - if pnpm build-and-test; then - echo "Tests succeeded for $projectDir." + process_projects "1.18.17" + + - name: Set failed projects output + id: set-failed + if: failure() + run: | + if [ -f "$GITHUB_WORKSPACE/failed_projects.txt" ]; then + failed_projects=$(cat $GITHUB_WORKSPACE/failed_projects.txt | jq -R -s -c 'split("\n")[:-1]') + echo "failed_projects=$failed_projects" >> $GITHUB_OUTPUT + else + echo "failed_projects=[]" >> $GITHUB_OUTPUT + fi + + summary: + needs: [changes, build-and-test] + if: always() + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Create job summary + run: | + echo "## Native Workflow Summary" >> $GITHUB_STEP_SUMMARY + echo "- Total projects: ${{ needs.changes.outputs.total_projects }}" >> $GITHUB_STEP_SUMMARY + + # List all processed projects + echo "
" >> $GITHUB_STEP_SUMMARY + echo "Projects processed (click to expand)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]' | while read project; do + echo "- $project" >> $GITHUB_STEP_SUMMARY + done + echo "" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + + # Report build and test results + if [[ "${{ needs.build-and-test.result }}" == "failure" ]]; then + echo "## :x: Build or tests failed" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + echo "Failed projects (click to expand)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + failed_projects='${{ needs.build-and-test.outputs.failed_projects }}' + if [[ -n "$failed_projects" ]]; then + echo "$failed_projects" | jq -r '.[]' | while IFS=: read -r project failure_reason; do + echo "- **$project**" >> $GITHUB_STEP_SUMMARY + echo " - Failure reason: $failure_reason" >> $GITHUB_STEP_SUMMARY + done else - failed=true - failed_tests+=($projectDir) - echo "Tests failed for $projectDir. Continuing with the next program." + echo "No failed projects reported. This might indicate an unexpected error in the workflow." >> $GITHUB_STEP_SUMMARY fi - cd - > /dev/null - done - if [ "$failed" = true ]; then - echo "*****************************" - echo "Programs that failed testing:" - printf "%s\n" "${failed_tests[@]}" - exit 1 + echo "" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + elif [[ "${{ needs.build-and-test.result }}" == "success" ]]; then + echo "## :white_check_mark: All builds and tests passed" >> $GITHUB_STEP_SUMMARY else - echo "All tests passed." + echo "## :warning: Build and test job was skipped or canceled" >> $GITHUB_STEP_SUMMARY fi - shell: bash diff --git a/.github/workflows/steel.yml b/.github/workflows/steel.yml index 842222755..3b64292ec 100644 --- a/.github/workflows/steel.yml +++ b/.github/workflows/steel.yml @@ -11,107 +11,246 @@ on: branches: - main +env: + MAX_JOBS: 64 + MIN_PROJECTS_PER_JOB: 4 + MIN_PROJECTS_FOR_MATRIX: 4 + jobs: - build: + changes: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.x] - solana-version: [stable] + permissions: + pull-requests: read + outputs: + changed_projects: ${{ steps.analyze.outputs.changed_projects }} + total_projects: ${{ steps.analyze.outputs.total_projects }} + matrix: ${{ steps.matrix.outputs.matrix }} steps: - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + - uses: dorny/paths-filter@v3 + id: changes + if: github.event_name == 'pull_request' with: - node-version: ${{ matrix.node-version }} - check-latest: true - - uses: heyAyushh/setup-solana@v5.4 - with: - solana-cli-version: ${{ matrix.solana-version }} - - run: solana block - shell: bash - - name: Install pnpm + list-files: shell + filters: | + steel: + - added|modified: '**/steel/**' + workflow: + - added|modified: '.github/workflows/steel.yml' + - name: Analyze Changes + id: analyze run: | - npm install --global pnpm - - name: Build Steel native programs + # Generate ignore pattern, excluding comments + ignore_pattern=$(grep -v '^#' .github/.ghaignore | grep -v '^$' | tr '\n' '|' | sed 's/|$//') + echo "Ignore pattern: $ignore_pattern" + + function get_projects() { + find . -type d -name "steel" | grep -vE "$ignore_pattern" | sort + } + + # Determine which projects to build and test + if [[ "${{ github.event_name }}" == "push" || "${{ github.event_name }}" == "schedule" || "${{ steps.changes.outputs.workflow }}" == "true" ]]; then + projects=$(get_projects) + elif [[ "${{ steps.changes.outputs.steel }}" == "true" ]]; then + changed_files=(${{ steps.changes.outputs.steel_files }}) + projects=$(for file in "${changed_files[@]}"; do dirname "${file}" | grep steel | sed 's#/steel/.*#/steel#g'; done | grep -vE "$ignore_pattern" | sort -u) + else + projects="" + fi + + # Output project information + if [[ -n "$projects" ]]; then + echo "Projects to build and test" + echo "$projects" + total_projects=$(echo "$projects" | wc -l) + echo "Total projects: $total_projects" + echo "total_projects=$total_projects" >> $GITHUB_OUTPUT + echo "changed_projects=$(echo "$projects" | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT + else + echo "No projects to build and test." + echo "total_projects=0" >> $GITHUB_OUTPUT + echo "changed_projects=[]" >> $GITHUB_OUTPUT + fi + - name: Generate matrix + id: matrix run: | - declare -a ProjectDirs=($(find . -type d -name "steel"| grep -v -f <(grep . .github/.ghaignore | grep -v '^$'))) - echo "Projects to Build:" - printf "%s\n" "${ProjectDirs[@]}" - for projectDir in "${ProjectDirs[@]}"; do - echo " - ******** - Building $projectDir - ********" - cd $projectDir - if pnpm build; then - echo "Build succeeded for $projectDir." - else - failed=true - failed_builds+=($projectDir) - echo "Build failed for $projectDir. Continuing with the next program." - fi - cd - > /dev/null - done - if [ "$failed" = true ]; then - echo "Programs that failed building:" - printf "%s\n" "${failed_builds[@]}" - exit 1 + total_projects=${{ steps.analyze.outputs.total_projects }} + max_jobs=${{ env.MAX_JOBS }} + min_projects_per_job=${{ env.MIN_PROJECTS_PER_JOB }} + min_projects_for_matrix=${{ env.MIN_PROJECTS_FOR_MATRIX }} + + if [ "$total_projects" -lt "$min_projects_for_matrix" ]; then + echo "matrix=[0]" >> $GITHUB_OUTPUT else - echo "All programs built successfully." + projects_per_job=$(( (total_projects + max_jobs - 1) / max_jobs )) + projects_per_job=$(( projects_per_job > min_projects_per_job ? projects_per_job : min_projects_per_job )) + num_jobs=$(( (total_projects + projects_per_job - 1) / projects_per_job )) + + indices=$(seq 0 $(( num_jobs - 1 ))) + echo "matrix=[$(echo $indices | tr ' ' ',')]" >> $GITHUB_OUTPUT fi - shell: bash - test: + build-and-test: + needs: changes + if: needs.changes.outputs.total_projects != '0' runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - node-version: [20.x] - solana-version: [1.18.17, stable] + index: ${{ fromJson(needs.changes.outputs.matrix) }} + name: build-and-test-group-${{ matrix.index }} + outputs: + failed_projects: ${{ steps.set-failed.outputs.failed_projects }} steps: - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 20.x check-latest: true - - uses: heyAyushh/setup-solana@v5.4 - with: - solana-cli-version: ${{ matrix.solana-version }} - - run: solana block - shell: bash - - name: Install pnpm + - name: Setup build environment + id: setup run: | + # Create the build and test function + cat << 'EOF' > build_and_test.sh + function build_and_test() { + local project=$1 + local solana_version=$2 + echo "Building and Testing $project with Solana $solana_version" + cd "$project" || return 1 + + # Install dependencies + if ! pnpm install --frozen-lockfile; then + echo "::error::pnpm install failed for $project" + echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + # Build + if ! pnpm build; then + echo "::error::build failed for $project" + echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + # Test + if ! pnpm build-and-test; then + echo "::error::tests failed for $project" + echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + echo "Build and tests succeeded for $project with $solana_version version." + cd - > /dev/null + return 0 + } + + function process_projects() { + local solana_version=$1 + + readarray -t all_projects < <(echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]?') + start_index=$(( ${{ matrix.index }} * ${{ env.MIN_PROJECTS_PER_JOB }} )) + end_index=$(( start_index + ${{ env.MIN_PROJECTS_PER_JOB }} )) + end_index=$(( end_index > ${{ needs.changes.outputs.total_projects }} ? ${{ needs.changes.outputs.total_projects }} : end_index )) + + echo "Projects to build and test in this job" + for i in $(seq $start_index $(( end_index - 1 ))); do + echo "${all_projects[$i]}" + done + + failed=false + for i in $(seq $start_index $(( end_index - 1 ))); do + echo "::group::Building and testing ${all_projects[$i]}" + if ! build_and_test "${all_projects[$i]}" "$solana_version"; then + failed=true + fi + echo "::endgroup::" + done + + return $([ "$failed" = true ] && echo 1 || echo 0) + } + EOF + + # Make the script executable + chmod +x build_and_test.sh + + # Install pnpm npm install --global pnpm - - name: Test Steel native programs + - name: Setup Solana stable + uses: heyAyushh/setup-solana@v5.4 + with: + solana-cli-version: stable + - name: Build and Test with Stable + run: | + source build_and_test.sh + solana -V + rustc -V + process_projects "stable" + - name: Setup Solana 1.18.17 + uses: heyAyushh/setup-solana@v5.4 + with: + solana-cli-version: 1.18.17 + - name: Build and Test with 1.18.17 run: | + source build_and_test.sh solana -V rustc -V - declare -a ProjectDirs=($(find . -type d -name "steel"| grep -v -f <(grep . .github/.ghaignore | grep -v '^$'))) - echo "Projects to Test:" - printf "%s\n" "${ProjectDirs[@]}" - for projectDir in "${ProjectDirs[@]}"; do - echo " - ******** - Testing $projectDir - ********" - cd $projectDir - pnpm install --frozen-lockfile - if pnpm build-and-test; then - echo "Tests succeeded for $projectDir." + process_projects "1.18.17" + + - name: Set failed projects output + id: set-failed + if: failure() + run: | + if [ -f "$GITHUB_WORKSPACE/failed_projects.txt" ]; then + failed_projects=$(cat $GITHUB_WORKSPACE/failed_projects.txt | jq -R -s -c 'split("\n")[:-1]') + echo "failed_projects=$failed_projects" >> $GITHUB_OUTPUT + else + echo "failed_projects=[]" >> $GITHUB_OUTPUT + fi + + summary: + needs: [changes, build-and-test] + if: always() + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Create job summary + run: | + echo "## Steel Workflow Summary" >> $GITHUB_STEP_SUMMARY + echo "- Total projects: ${{ needs.changes.outputs.total_projects }}" >> $GITHUB_STEP_SUMMARY + + # List all processed projects + echo "
" >> $GITHUB_STEP_SUMMARY + echo "Projects processed (click to expand)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]' | while read project; do + echo "- $project" >> $GITHUB_STEP_SUMMARY + done + echo "" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + + # Report build and test results + if [[ "${{ needs.build-and-test.result }}" == "failure" ]]; then + echo "## :x: Build or tests failed" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + echo "Failed projects (click to expand)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + failed_projects='${{ needs.build-and-test.outputs.failed_projects }}' + if [[ -n "$failed_projects" ]]; then + echo "$failed_projects" | jq -r '.[]' | while IFS=: read -r project failure_reason; do + echo "- **$project**" >> $GITHUB_STEP_SUMMARY + echo " - Failure reason: $failure_reason" >> $GITHUB_STEP_SUMMARY + done else - failed=true - failed_tests+=($projectDir) - echo "Tests failed for $projectDir. Continuing with the next program." + echo "No failed projects reported. This might indicate an unexpected error in the workflow." >> $GITHUB_STEP_SUMMARY fi - cd - > /dev/null - done - if [ "$failed" = true ]; then - echo "*****************************" - echo "Programs that failed testing:" - printf "%s\n" "${failed_tests[@]}" - exit 1 + echo "" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + elif [[ "${{ needs.build-and-test.result }}" == "success" ]]; then + echo "## :white_check_mark: All builds and tests passed" >> $GITHUB_STEP_SUMMARY else - echo "All tests passed." + echo "## :warning: Build and test job was skipped or canceled" >> $GITHUB_STEP_SUMMARY fi - shell: bash diff --git a/.husky/pre-commit b/.husky/pre-commit index a16d8b1d5..2312dc587 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname "$0")/_/husky.sh" - npx lint-staged diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ed0528a34..bf3dab9c0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ We welcome contributions in the form of code, documentation, bug reports, featur ## General coding and writing guidelines -Please follow the [Contributing and Style Guide from the Developer Content Repo](https://github.com/solana-foundation/developer-content/blob/main/CONTRIBUTING.md). +Please follow the [Contributing and Style Guide from the Developer Content Repo](https://github.com/solana-foundation/developer-content/blob/main/CONTRIBUTING.md). Specifically for code in this repo: @@ -43,7 +43,7 @@ Specifically for code in this repo: [Biome](https://biomejs.dev/). Execute the following command to format and lint your code at the root of this project before submitting a pull request: ```bash -pnpm check:fix +pnpm fix ``` 7. Some projects can be ignored from the building and testing process by adding the project name to the `.gitignore` file. diff --git a/basics/hello-solana/native/package.json b/basics/hello-solana/native/package.json index e772d7dca..76cd4def3 100644 --- a/basics/hello-solana/native/package.json +++ b/basics/hello-solana/native/package.json @@ -1,6 +1,6 @@ { "scripts": { - "test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts", + "test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/index.test.ts", "build-and-test": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./tests/fixtures && pnpm test", "build": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./program/target/so", "deploy": "solana program deploy ./program/target/so/hello_solana_program.so" diff --git a/basics/hello-solana/native/tests/test.ts b/basics/hello-solana/native/tests/index.test.ts similarity index 100% rename from basics/hello-solana/native/tests/test.ts rename to basics/hello-solana/native/tests/index.test.ts diff --git a/basics/hello-solana/steel/package.json b/basics/hello-solana/steel/package.json index f054a3685..7b16847c5 100644 --- a/basics/hello-solana/steel/package.json +++ b/basics/hello-solana/steel/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "hello world with steel framework for solana", "scripts": { - "test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/test.ts", + "test": "pnpm ts-mocha -p ./tsconfig.json -t 1000000 ./tests/index.test.ts", "build-and-test": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./tests/fixtures && pnpm test", "build": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./program/target/so", "deploy": "solana program deploy ./program/target/so/hello_solana_program.so" diff --git a/basics/hello-solana/steel/tests/test.ts b/basics/hello-solana/steel/tests/index.test.ts similarity index 100% rename from basics/hello-solana/steel/tests/test.ts rename to basics/hello-solana/steel/tests/index.test.ts From 0ea43874ecdcd3f3e2b0c02ce7edf505e28569d0 Mon Sep 17 00:00:00 2001 From: Ayush Date: Thu, 14 Nov 2024 19:37:36 +0530 Subject: [PATCH 2/2] feat: steel clippy fmt and contributing guidelines (#326) * steel clippy fmt and contributing guidelines * clippy and fmt run fix, steel workspace check * Improve contributing --- .github/workflows/steel.yml | 123 ++++++++++++++++++++++----- CONTRIBUTING.md | 54 ++++++++++-- Cargo.toml | 1 - basics/hello-solana/steel/Cargo.toml | 21 +++++ basics/hello-solana/steel/cargo.toml | 8 -- 5 files changed, 171 insertions(+), 36 deletions(-) create mode 100644 basics/hello-solana/steel/Cargo.toml delete mode 100644 basics/hello-solana/steel/cargo.toml diff --git a/.github/workflows/steel.yml b/.github/workflows/steel.yml index 3b64292ec..ac3a5e2e5 100644 --- a/.github/workflows/steel.yml +++ b/.github/workflows/steel.yml @@ -90,6 +90,40 @@ jobs: echo "matrix=[$(echo $indices | tr ' ' ',')]" >> $GITHUB_OUTPUT fi + rust-checks: + needs: changes + if: ${{ github.event_name == 'pull_request' && needs.changes.outputs.total_projects != '0' }} + name: Rust Checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + - name: Run sccache-cache + if: github.event_name != 'release' + uses: mozilla-actions/sccache-action@v0.0.6 + - name: Set Rust cache env vars + if: github.event_name != 'release' + run: | + echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV + echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV + - name: Run fmt and clippy + run: | + readarray -t all_projects < <(echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]?') + for project in "${all_projects[@]}"; do + echo "::group::Checking ${project}" + if [ ! -f "${project}/Cargo.toml" ]; then + echo "::error::No Cargo.toml found in ${project}" + exit 1 + fi + cd "${project}" + cargo fmt --check + cargo clippy --all-features -- -D warnings + cd - > /dev/null + echo "::endgroup::" + done + build-and-test: needs: changes if: needs.changes.outputs.total_projects != '0' @@ -103,6 +137,19 @@ jobs: failed_projects: ${{ steps.set-failed.outputs.failed_projects }} steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - name: Run sccache-cache + if: github.event_name != 'release' + uses: mozilla-actions/sccache-action@v0.0.6 + - name: Set Rust cache env vars + if: github.event_name != 'release' + run: | + echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV + echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV + - uses: actions/cache@v3 + with: + path: ~/.cargo/bin/steel + key: ${{ runner.os }}-steel-cli - name: Use Node.js uses: actions/setup-node@v4 with: @@ -111,6 +158,8 @@ jobs: - name: Setup build environment id: setup run: | + npm install --global pnpm + # Create the build and test function cat << 'EOF' > build_and_test.sh function build_and_test() { @@ -120,27 +169,53 @@ jobs: cd "$project" || return 1 # Install dependencies - if ! pnpm install --frozen-lockfile; then - echo "::error::pnpm install failed for $project" - echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt - cd - > /dev/null - return 1 - fi + if [ -f "package.json" ]; then + if ! pnpm install --frozen-lockfile; then + echo "::error::pnpm install failed for $project" + echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi - # Build - if ! pnpm build; then - echo "::error::build failed for $project" - echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt - cd - > /dev/null - return 1 - fi + # Build + if ! pnpm build; then + echo "::error::build failed for $project" + echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi - # Test - if ! pnpm build-and-test; then - echo "::error::tests failed for $project" - echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt - cd - > /dev/null - return 1 + # Test + if ! pnpm build-and-test; then + echo "::error::tests failed for $project" + echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + else + # Use Steel CLI + if ! cargo install --quiet steel-cli; then + echo "::error::steel-cli installation failed for $project" + echo "$project: steel-cli installation failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + # Build + if ! steel build; then + echo "::error::steel build failed for $project" + echo "$project: steel build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi + + # Test + if ! steel test; then + echo "::error::steel test failed for $project" + echo "$project: steel test failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt + cd - > /dev/null + return 1 + fi fi echo "Build and tests succeeded for $project with $solana_version version." @@ -177,28 +252,34 @@ jobs: # Make the script executable chmod +x build_and_test.sh - # Install pnpm - npm install --global pnpm - name: Setup Solana stable uses: heyAyushh/setup-solana@v5.4 with: solana-cli-version: stable - name: Build and Test with Stable + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" run: | source build_and_test.sh solana -V rustc -V process_projects "stable" + sccache --show-stats - name: Setup Solana 1.18.17 uses: heyAyushh/setup-solana@v5.4 with: solana-cli-version: 1.18.17 - name: Build and Test with 1.18.17 + env: + SCCACHE_GHA_ENABLED: "true" + RUSTC_WRAPPER: "sccache" run: | source build_and_test.sh solana -V rustc -V process_projects "1.18.17" + sccache --show-stats - name: Set failed projects output id: set-failed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf3dab9c0..554928614 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,11 +22,40 @@ Specifically for code in this repo: 1. Use pnpm as the default package manager for the project. You can [install pnpm by following the instructions](https://pnpm.io/installation). Commit `pnpm-lock.yaml` to the repository. -2. Anchor programs should be in directory `anchor`, programs written for Solana Native should be in directory `native`, TypeScript in `poseidon` and Python in `seahorse`. +2. Solana Programs written for Anchor framework should be in directory (`anchor`)[https://www.anchor-lang.com], Solana Native in (`native`)[https://solana.com/developers/guides/getstarted/intro-to-native-rust], Steel Framework in (`steel`)[https://github.com/regolith-labs/steel], TypeScript in (`poseidon`)[https://github.com/Turbin3/poseidon], respectively. + - Project path structure: `/program-examples/category/example-name/` + - Project path structure example for anchor: `/program-examples/category/example-name/anchor` 3. Tests for Solana native programs, steel framework programs, and Anchor should be written with [solana-bankrun](https://kevinheavey.github.io/solana-bankrun) -4. For Solana native programs and Steel framework programs ensure adding these mandatory pnpm run scripts to your `package.json` file for successful CI/CD builds: +4. Steel framework programs must be organized as a Cargo workspace with separate projects for API and program: + - Project path structure: `/program-examples/category/example-name/steel` + - Initialise project using `steel new ` + - Must be a Cargo workspace with two separate projects: + - `api`: Contains API-related code + - `program`: Contains the program implementation + - Steel projects should NOT be added in the root [`Cargo.toml` file](https://github.com/solana-developers/program-examples/blob/main/Cargo.toml) + + This structure ensures proper organization and separation of concerns. + +5. For Steel framework programs: + - Steel CLI is the recommended way to build and test programs: + ```bash + # Install Steel CLI (one-time setup) + cargo install steel-cli + + # Create a new Steel project + steel new + + # Build the program + steel build + + # Run tests + steel test + ``` + - Alternatively, you can use package.json scripts if you need custom build/test configurations as Solana native one described below. + +6. For Solana native programs ensure adding these mandatory pnpm run scripts to your `package.json` file for successful CI/CD builds: ```json "scripts": { @@ -37,20 +66,33 @@ Specifically for code in this repo: }, ``` -5. Test command for Anchor should execute `pnpm test` instead of `yarn run test` for anchor programs. Replace `yarn` with `pnpm` in `[script]` table inside [Anchor.toml file.](https://www.anchor-lang.com/docs/manifest#scripts-required-for-testing) +Alternatively, You can add `steel test` and `steel build` as commands according to your project. -6. TypeScript, JavaScript and JSON files are formatted and linted using +"scripts": { + "test": "steel test", + "build-and-test": "steel build && steel test", + "build": "steel build", + "deploy": "solana program deploy ./program/target/so/program.so" +}, + +7. Test command for Anchor should execute `pnpm test` instead of `yarn run test` for anchor programs. Replace `yarn` with `pnpm` in `[script]` table inside [Anchor.toml file.](https://www.anchor-lang.com/docs/manifest#scripts-required-for-testing) + +``` +[scripts] +test = "pnpm ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" +``` + +8. TypeScript, JavaScript and JSON files are formatted and linted using [Biome](https://biomejs.dev/). Execute the following command to format and lint your code at the root of this project before submitting a pull request: ```bash pnpm fix ``` -7. Some projects can be ignored from the building and testing process by adding the project name to the `.gitignore` file. +9. Some projects can be ignored from the building and testing process by adding the project name to the `.gitignore` file. When removing or updating an example, please ensure that the example is removed from the `.gitignore` file and there's a change in that example's directory. - ## Code of Conduct We are committed to providing a friendly, safe, and welcoming environment for all contributors, regardless of their background, experience level, or personal characteristics. As a contributor, you are expected to: diff --git a/Cargo.toml b/Cargo.toml index c13e8b8c0..0b9149215 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ members = [ "basics/cross-program-invocation/anchor/programs/*", "basics/hello-solana/native/program", "basics/hello-solana/anchor/programs/*", - "basics/hello-solana/steel/program", "basics/pda-rent-payer/native/program", "basics/pda-rent-payer/anchor/programs/*", "basics/processing-instructions/native/program", diff --git a/basics/hello-solana/steel/Cargo.toml b/basics/hello-solana/steel/Cargo.toml new file mode 100644 index 000000000..be454182e --- /dev/null +++ b/basics/hello-solana/steel/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +resolver = "2" +members = ["program"] + +[workspace.package] +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" +homepage = "" +documentation = "" +repository = "" +readme = "./README.md" +keywords = ["solana"] + +[workspace.dependencies] +bytemuck = "1.14" +num_enum = "0.7" +solana-program = "1.18" +steel = "2.0" +thiserror = "1.0" +solana-sdk = "1.18" diff --git a/basics/hello-solana/steel/cargo.toml b/basics/hello-solana/steel/cargo.toml deleted file mode 100644 index 9cf5ee9d0..000000000 --- a/basics/hello-solana/steel/cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[workspace] -members = [ - "program", -] -resolver = "2" - -[profile.release] -overflow-checks = true