diff --git a/.github/actions/awesomebot-gh-summary-action/action.yml b/.github/actions/awesomebot-gh-summary-action/action.yml deleted file mode 100644 index afdb72ec5..000000000 --- a/.github/actions/awesomebot-gh-summary-action/action.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: 'AwesomeBot Markdown Summary Report' -description: 'Composes the summary report using JSON results of any AwesomeBot execution' - -inputs: - ab-root: - description: 'Path where AwesomeBot result files are written.' - required: true - files: - description: 'A delimited string containing the filenames to process.' - required: true - separator: - description: 'Token used to delimit each filename. Default: " ".' - required: false - default: ' ' - append-heading: - description: 'When should append report heading.' - required: false - default: "false" - write: - description: 'When should append the report to GITHUB_STEP_SUMMARY file descriptor.' - required: false - default: "true" - -outputs: - text: - description: Generated Markdown text. - value: ${{ steps.generate.outputs.text }} - -runs: - using: "composite" - - steps: - - - name: Generate markdown - id: generate - # Using PowerShell - shell: pwsh - # sec: sanatize inputs using environment variables - env: - GITHUB_ACTION_PATH: ${{ github.action_path }} - GITHUB_WORKSPACE: ${{ github.workspace }} - # INPUT_ is not available in Composite run steps - # https://github.community/t/input-variable-name-is-not-available-in-composite-run-steps/127611 - INPUT_AB_ROOT: ${{ inputs.ab-root }} - INPUT_FILES: ${{ inputs.files }} - INPUT_SEPARATOR: ${{ inputs.separator }} - INPUT_APPEND_HEADING: ${{ inputs.append-heading }} - run: | - $text = "" - - # Handle optional heading - if ("true" -eq $env:INPUT_APPEND_HEADING) { - $text += "### Report of Checked URLs!" - $text += "`n`n" - $text += "
`n`n" - $text += "_Link issues :rocket: powered by [``awesome_bot``](https://github.com/dkhamsing/awesome_bot)_." - $text += "`n`n
" - } - - # Loop ForEach files - $env:INPUT_FILES -split $env:INPUT_SEPARATOR | ForEach { - $file = $_ - if ($file -match "\s+" ) { - continue # is empty string - } - $abr_file = $env:INPUT_AB_ROOT + "/ab-results-" + ($file -replace "[/\\]","-") + "-markdown-table.json" - - try { - $json = Get-Content $abr_file | ConvertFrom-Json - } catch { - $message = $_ - echo "::error ::$message" # Notify as GitHub Actions annotation - continue # Don't crash!! - } - - $text += "`n`n" - if ("true" -eq $json.error) { - # Highlighting issues counter - $SearchExp = '(?\d+)' - $ReplaceExp = '**${Num}**' - $text += "`:page_facing_up: File: ``" + $file + "`` (:warning: " + ($json.title -replace $SearchExp,$ReplaceExp) + ")" - # removing where ab attribution lives (moved to report heading) - $text += $json.message -replace "####.*?\n","`n" - } else { - $text += ":page_facing_up: File: ``" + $file + "`` (:ok: **No issues**)" - } - } - - # set multiline output (the way of prevent script injection is with random delimiters) - # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings - # https://github.com/orgs/community/discussions/26288#discussioncomment-3876281 - $delimiter = (openssl rand -hex 8) | Out-String - echo "text<<$delimiter" >> $env:GITHUB_OUTPUT - echo "$text" >> $env:GITHUB_OUTPUT - echo "$delimiter" >> $env:GITHUB_OUTPUT - - - - name: Write output - if: ${{ fromJson(inputs.write) }} - shell: bash - env: - INPUT_TEXT: ${{ steps.generate.outputs.text }} - INPUT_WRITE: ${{ inputs.write }} - run: | - echo "$INPUT_TEXT" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/check-urls.yml b/.github/workflows/check-urls.yml index 448977241..b87219028 100644 --- a/.github/workflows/check-urls.yml +++ b/.github/workflows/check-urls.yml @@ -5,128 +5,44 @@ on: pull_request: permissions: - # needed for checkout code contents: read -# This allows a subsequently queued workflow run to interrupt/wait for previous runs concurrency: group: '${{ github.workflow }} @ ${{ github.run_id }}' - cancel-in-progress: false # true = interrupt, false = wait + cancel-in-progress: false jobs: - -# NOTE: tj-actions/changed-files. -# For push events you need to include fetch-depth: 0 | 2 depending on your use case. -# 0: retrieve all history for all branches and tags -# 1: retrieve only current commit (by default) -# 2: retrieve until the preceding commit get-changed-files: name: Get changed files runs-on: ubuntu-latest outputs: - fetch-depth: ${{ steps.set-params.outputs.fetch-depth }} - files: ${{ steps.set-files.outputs.files }} - files-len: ${{ steps.set-files.outputs.files-len }} - matrix: ${{ steps.set-matrix.outputs.matrix }} + files: ${{ steps.changed-files.outputs.all_changed_files }} steps: - - name: Determine workflow params - id: set-params - run: | - echo "fetch_depth=0" >> $GITHUB_OUTPUT - if [ "${{ github.event_name }}" == "pull_request" ]; then - echo "fetch_depth=0" >> $GITHUB_OUTPUT - fi - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@v4 with: - fetch-depth: ${{ steps.set-params.outputs.fetch-depth }} + fetch-depth: 0 + - name: Get changed files id: changed-files uses: tj-actions/changed-files@v46 with: separator: " " - json: true - - id: set-files - run: | - echo "${{ steps.changed-files.outputs.all_changed_files }}" \ - | jq --raw-output '. | join(" ")' \ - | sed -e 's/^/files=/' \ - >> $GITHUB_OUTPUT - echo "${{ steps.changed-files.outputs.all_changed_files }}" \ - | jq --raw-output '. | length' \ - | sed -e 's/^/files-len=/' \ - >> $GITHUB_OUTPUT - - id: set-matrix - run: | - echo "{\"file\":${{ steps.changed-files.outputs.all_changed_files }}}" \ - | sed -e 's/^/matrix=/' \ - >> $GITHUB_OUTPUT - + files: | + **/*.md + **/*.yml check-urls: - name: Check @ ${{ matrix.file }} - if: ${{ fromJSON(needs.get-changed-files.outputs.files-len) > 0 }} - needs: [get-changed-files] + name: Check URLs with Lychee + needs: get-changed-files + if: needs.get-changed-files.outputs.files != '' runs-on: ubuntu-latest - strategy: - matrix: ${{ fromJSON(needs.get-changed-files.outputs.matrix) }} - max-parallel: 10 - fail-fast: false steps: - name: Checkout - if: ${{ endsWith(matrix.file, '.yml') || endsWith(matrix.file, '.md') }} - uses: actions/checkout@v7 + uses: actions/checkout@v4 + + - name: Link Checker + uses: lycheeverse/lychee-action@v2 with: - fetch-depth: ${{ needs.get-changed-files.outputs.fetch-depth }} - - name: Setup Ruby v2.6 - if: ${{ endsWith(matrix.file, '.yml') || endsWith(matrix.file, '.md') }} - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.6 - - name: Install awesome_bot - if: ${{ endsWith(matrix.file, '.yml') || endsWith(matrix.file, '.md') }} - run: | - gem install awesome_bot - - name: Set output - id: set-output - # FILENAME takes the complete file path and strips everything before the final '/' - # FILEPATH replaces all '/' with '-' in the file path since '/' is not allowed in upload artifact name - # Due to a bug in actions/download-artifact, we need to rename README.md to BASE_README.md - run: | - echo "FILENAME=$(echo ${{ matrix.file }} | grep -oE '[a-zA-Z0-9_-]+(\.yml|\.md)')" >> "$GITHUB_OUTPUT" - - file_path="${{ matrix.file }}" - file_path="${file_path//\//-}" - - if [[ "$file_path" == "README.md" ]]; then - file_path="BASE_README.md" - fi - - echo "FILEPATH=${file_path}" >> "$GITHUB_OUTPUT" - - name: "Check URLs of file: ${{ matrix.file }}" - if: ${{ endsWith(matrix.file, '.yml') || endsWith(matrix.file, '.md') }} - run: | - awesome_bot "${{ matrix.file }}" --allow-redirect --allow-dupe --allow-ssl || true; - - uses: actions/upload-artifact@v7 - with: - name: ${{ steps.set-output.outputs.FILEPATH }} - path: ${{ github.workspace }}/ab-results-*.json - - - reporter: - name: GitHub report - needs: [get-changed-files, check-urls] - runs-on: ubuntu-latest - steps: - - name: Checkout # for having the sources of the local action - uses: actions/checkout@v7 - # download and unzip the ab-results-*.json generated by job-matrix: check-urls - - name: Download artifacts - uses: actions/download-artifact@v8 - - name: Generate Summary Report - uses: ./.github/actions/awesomebot-gh-summary-action - with: - ab-root: ${{ github.workspace }} - files: ${{ needs.get-changed-files.outputs.files }} - separator: " " - append-heading: ${{ true }} + args: --verbose --no-progress --timeout 10 --max-retries 3 --retry-wait-time 2 ${{ needs.get-changed-files.outputs.files }} + fail: false diff --git a/.github/workflows/comment-pr.yml b/.github/workflows/comment-pr.yml index 679b7cb26..847344fe2 100644 --- a/.github/workflows/comment-pr.yml +++ b/.github/workflows/comment-pr.yml @@ -15,7 +15,7 @@ jobs: ${{ github.event.workflow_run.event == 'pull_request' }} steps: - name: 'Download artifact' - uses: actions/github-script@v9 + uses: actions/github-script@v7 with: script: | let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ diff --git a/.github/workflows/fpb-lint.yml b/.github/workflows/fpb-lint.yml index 443067987..9a284f508 100644 --- a/.github/workflows/fpb-lint.yml +++ b/.github/workflows/fpb-lint.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@v4 - run: npm install -g free-programming-books-lint - name: Run linter @@ -28,7 +28,7 @@ jobs: cat output.log | sed -E 's:/home/runner/work/free-programming-books/|⚠.+::' | uniq > ./pr/error.log - name: Upload artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@v4 if: always() with: name: pr diff --git a/.github/workflows/rtl-ltr-linter.yml b/.github/workflows/rtl-ltr-linter.yml index 288c2685d..7d01cb407 100644 --- a/.github/workflows/rtl-ltr-linter.yml +++ b/.github/workflows/rtl-ltr-linter.yml @@ -12,7 +12,7 @@ jobs: steps: # Checkout the repository code - name: Checkout code - uses: actions/checkout@v7 + uses: actions/checkout@v4 # Fetch the full history of 'main' for accurate git diff in PRs - name: Fetch all history for main @@ -20,7 +20,7 @@ jobs: # Set up the required Python version for the linter - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v5 with: python-version: '3.11' # Use a recent Python version for compatibility @@ -94,7 +94,7 @@ jobs: # Only if the linter step was executed (success or failure) - name: Upload linter output artifact if: steps.run_linter.conclusion == 'success' || steps.run_linter.conclusion == 'failure' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@v4 with: name: rtl-linter-output # Name of the artifact path: rtl-linter-output.log # Path to the output file diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 2261c3ad4..aa36480d4 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -19,7 +19,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v10 + - uses: actions/stale@v9 with: days-before-issue-stale: -1 # Don't mark issues as stale days-before-issue-close: -1 # Don't close issues diff --git a/books/free-programming-books-langs.md b/books/free-programming-books-langs.md index e5674caad..1e2793e02 100644 --- a/books/free-programming-books-langs.md +++ b/books/free-programming-books-langs.md @@ -1382,6 +1382,7 @@ Books on general-purpose programming that don't focus on a specific language are * [How To Code in React.js](https://www.digitalocean.com/community/books/how-to-code-in-react-js-ebook) - Joe Morgan * [Intro to the React Framework](http://code.tutsplus.com/tutorials/intro-to-the-react-framework--net-35660) * [Learning React.js: Getting Started and Concepts](https://scotch.io/tutorials/learning-react-getting-started-and-concepts) +* [Patterns.dev](https://www.patterns.dev) - Lydia Hallie, Addy Osmani * [Quick Start](https://react.dev/learn) * [React-Bits](https://github.com/vasanthk/react-bits) * [React Book, your beginner guide to React](https://github.com/softchris/react-book/) - Chris Noring