diff --git a/.github/workflows/check-action-metadata-task.yml b/.github/workflows/check-action-metadata-task.yml index 73c03f6..14b9f11 100644 --- a/.github/workflows/check-action-metadata-task.yml +++ b/.github/workflows/check-action-metadata-task.yml @@ -31,6 +31,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -56,6 +57,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/.github/workflows/check-files-task.yml b/.github/workflows/check-files-task.yml index ddc5a7e..f0aa84f 100644 --- a/.github/workflows/check-files-task.yml +++ b/.github/workflows/check-files-task.yml @@ -15,6 +15,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -40,6 +41,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository @@ -58,6 +61,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/.github/workflows/check-general-formatting-task.yml b/.github/workflows/check-general-formatting-task.yml index 1c3a94f..c5e7c82 100644 --- a/.github/workflows/check-general-formatting-task.yml +++ b/.github/workflows/check-general-formatting-task.yml @@ -15,6 +15,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -40,6 +41,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Set environment variables diff --git a/.github/workflows/check-license.yml b/.github/workflows/check-license.yml index e83e211..8fb832a 100644 --- a/.github/workflows/check-license.yml +++ b/.github/workflows/check-license.yml @@ -1,11 +1,6 @@ # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-license.md name: Check License -env: - EXPECTED_LICENSE_FILENAME: LICENSE.txt - # SPDX identifier: https://spdx.org/licenses/ - EXPECTED_LICENSE_TYPE: GPL-3.0 - # See: https://docs.github.com/actions/using-workflows/events-that-trigger-workflows on: create: @@ -35,6 +30,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -57,9 +53,22 @@ jobs: echo "result=$RESULT" >> $GITHUB_OUTPUT check-license: + name: ${{ matrix.check-license.path }} needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read + + strategy: + fail-fast: false + + matrix: + check-license: + - path: ./ + expected-filename: LICENSE.txt + # SPDX identifier: https://spdx.org/licenses/ + expected-type: GPL-3.0 steps: - name: Checkout repository @@ -73,23 +82,27 @@ jobs: - name: Install licensee run: gem install licensee - - name: Check license file + - name: Check license file for ${{ matrix.check-license.path }} run: | EXIT_STATUS=0 + + # Go into folder path + cd ./${{ matrix.check-license.path }} + # See: https://github.com/licensee/licensee LICENSEE_OUTPUT="$(licensee detect --json --confidence=100)" DETECTED_LICENSE_FILE="$(echo "$LICENSEE_OUTPUT" | jq .matched_files[0].filename | tr --delete '\r')" echo "Detected license file: $DETECTED_LICENSE_FILE" - if [ "$DETECTED_LICENSE_FILE" != "\"${EXPECTED_LICENSE_FILENAME}\"" ]; then - echo "::error file=${DETECTED_LICENSE_FILE}::detected license file $DETECTED_LICENSE_FILE doesn't match expected: $EXPECTED_LICENSE_FILENAME" + if [ "$DETECTED_LICENSE_FILE" != "\"${{ matrix.check-license.expected-filename }}\"" ]; then + echo "::error file=${DETECTED_LICENSE_FILE}::detected license file $DETECTED_LICENSE_FILE doesn't match expected: ${{ matrix.check-license.expected-filename }}" EXIT_STATUS=1 fi DETECTED_LICENSE_TYPE="$(echo "$LICENSEE_OUTPUT" | jq .matched_files[0].matched_license | tr --delete '\r')" echo "Detected license type: $DETECTED_LICENSE_TYPE" - if [ "$DETECTED_LICENSE_TYPE" != "\"${EXPECTED_LICENSE_TYPE}\"" ]; then - echo "::error file=${DETECTED_LICENSE_FILE}::detected license type $DETECTED_LICENSE_TYPE doesn't match expected \"${EXPECTED_LICENSE_TYPE}\"" + if [ "$DETECTED_LICENSE_TYPE" != "\"${{ matrix.check-license.expected-type }}\"" ]; then + echo "::error file=${DETECTED_LICENSE_FILE}::detected license type $DETECTED_LICENSE_TYPE doesn't match expected \"${{ matrix.check-license.expected-type }}\"" EXIT_STATUS=1 fi diff --git a/.github/workflows/check-markdown-task.yml b/.github/workflows/check-markdown-task.yml index beb934c..b9a8f3d 100644 --- a/.github/workflows/check-markdown-task.yml +++ b/.github/workflows/check-markdown-task.yml @@ -41,6 +41,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -66,6 +67,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository @@ -92,6 +95,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/.github/workflows/check-npm-task.yml b/.github/workflows/check-npm-task.yml index 8bec6a8..b022fa3 100644 --- a/.github/workflows/check-npm-task.yml +++ b/.github/workflows/check-npm-task.yml @@ -26,12 +26,10 @@ on: workflow_dispatch: repository_dispatch: -permissions: - contents: read - jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -54,9 +52,18 @@ jobs: echo "result=$RESULT" >> $GITHUB_OUTPUT validate: + name: validate (${{ matrix.project.path }}) needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read + + strategy: + fail-fast: false + matrix: + project: + - path: . steps: - name: Checkout repository @@ -74,12 +81,21 @@ jobs: version: 3.x - name: Validate package.json - run: task --silent npm:validate + run: task --silent npm:validate PROJECT_PATH="${{ matrix.project.path }}" check-sync: + name: check-sync (${{ matrix.project.path }}) needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read + + strategy: + fail-fast: false + matrix: + project: + - path: . steps: - name: Checkout repository @@ -97,7 +113,7 @@ jobs: version: 3.x - name: Install npm dependencies - run: task npm:install-deps + run: task npm:install-deps PROJECT_PATH="${{ matrix.project.path }}" - name: Check package-lock.json - run: git diff --color --exit-code package-lock.json + run: git diff --color --exit-code "${{ matrix.project.path }}/package-lock.json" diff --git a/.github/workflows/check-prettier-formatting-task.yml b/.github/workflows/check-prettier-formatting-task.yml index db19e30..630d741 100644 --- a/.github/workflows/check-prettier-formatting-task.yml +++ b/.github/workflows/check-prettier-formatting-task.yml @@ -209,6 +209,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -234,6 +235,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/.github/workflows/check-python-task.yml b/.github/workflows/check-python-task.yml index f836e82..8eaaaef 100644 --- a/.github/workflows/check-python-task.yml +++ b/.github/workflows/check-python-task.yml @@ -35,6 +35,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -60,6 +61,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository @@ -92,6 +95,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/.github/workflows/check-taskfiles.yml b/.github/workflows/check-taskfiles.yml index 9c3a60e..494166b 100644 --- a/.github/workflows/check-taskfiles.yml +++ b/.github/workflows/check-taskfiles.yml @@ -29,6 +29,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -55,6 +56,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false diff --git a/.github/workflows/check-toc-task.yml b/.github/workflows/check-toc-task.yml index b3e2506..84797d6 100644 --- a/.github/workflows/check-toc-task.yml +++ b/.github/workflows/check-toc-task.yml @@ -29,6 +29,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -55,6 +56,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false diff --git a/.github/workflows/check-workflows-task.yml b/.github/workflows/check-workflows-task.yml index fefdaec..f79a0c9 100644 --- a/.github/workflows/check-workflows-task.yml +++ b/.github/workflows/check-workflows-task.yml @@ -28,6 +28,8 @@ on: jobs: validate: runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/.github/workflows/check-yaml-task.yml b/.github/workflows/check-yaml-task.yml index 80bbf21..6cad341 100644 --- a/.github/workflows/check-yaml-task.yml +++ b/.github/workflows/check-yaml-task.yml @@ -47,6 +47,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -73,6 +74,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false diff --git a/.github/workflows/spell-check-task.yml b/.github/workflows/spell-check-task.yml index 2a36af4..09c0c60 100644 --- a/.github/workflows/spell-check-task.yml +++ b/.github/workflows/spell-check-task.yml @@ -15,6 +15,7 @@ on: jobs: run-determination: runs-on: ubuntu-latest + permissions: {} outputs: result: ${{ steps.determination.outputs.result }} steps: @@ -40,6 +41,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/.github/workflows/sync-labels-npm.yml b/.github/workflows/sync-labels-npm.yml index 31199d5..832de1b 100644 --- a/.github/workflows/sync-labels-npm.yml +++ b/.github/workflows/sync-labels-npm.yml @@ -30,6 +30,8 @@ on: jobs: check: runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository @@ -65,6 +67,7 @@ jobs: download: needs: check runs-on: ubuntu-latest + permissions: {} strategy: matrix: @@ -92,6 +95,9 @@ jobs: sync: needs: download runs-on: ubuntu-latest + permissions: + contents: read + issues: write steps: - name: Set environment variables diff --git a/.github/workflows/test-python-poetry-task.yml b/.github/workflows/test-python-poetry-task.yml index 8a480c8..754a081 100644 --- a/.github/workflows/test-python-poetry-task.yml +++ b/.github/workflows/test-python-poetry-task.yml @@ -41,6 +41,7 @@ jobs: runs-on: ubuntu-latest outputs: result: ${{ steps.determination.outputs.result }} + permissions: {} steps: - name: Determine if the rest of the workflow should run id: determination @@ -64,6 +65,8 @@ jobs: needs: run-determination if: needs.run-determination.outputs.result == 'true' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository diff --git a/Taskfile.yml b/Taskfile.yml index bb86ac3..733078d 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -104,8 +104,8 @@ tasks: ' \ basename "$0" | \ grep \ - --perl-regexp \ - --regexp='"'"'([<>:"/\\|?*\x{0000}-\x{001F}])|(.+\.$)'"'"' \ + --extended-regexp \ + --regexp='"'"'([<>:"/\\|?*'"'"'"$(printf "\001-\037")"'"'"'])|(.+\.$)'"'"' \ --silent \ && \ echo "$0" @@ -228,61 +228,39 @@ tasks: # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-markdown-task/Taskfile.yml markdown:check-links: desc: Check for broken links + vars: + # The command is defined in a Taskfile variable to allow it to be broken into multiple lines for readability. + # This can't be done in the `cmd` object of the Taskfile because `npx --call` uses the native shell, which causes + # standard newline escaping syntax to not work when the task is run on Windows. + # + # Using -regex instead of -name to avoid Task's behavior of globbing even when quoted on Windows + # The odd method for escaping . in the regex is required for windows compatibility because mvdan.cc/sh gives + # \ characters special treatment on Windows in an attempt to support them as path separators. + # + # prettier-ignore + CHECK_LINKS_COMMAND: + " + find . \ + -type d -name \".git\" -prune -o \ + -type d -name \".licenses\" -prune -o \ + -type d -name \"__pycache__\" -prune -o \ + -type d -name \"node_modules\" -prune -o \ + -regex \".*[.]md\" \ + -exec \ + markdown-link-check \ + --quiet \ + --config \"./.markdown-link-check.json\" \ + \\{\\} \ + + + " deps: - task: docs:generate - task: npm:install-deps cmds: - | - if [[ "{{.OS}}" == "Windows_NT" ]]; then - # npx --call uses the native shell, which makes it too difficult to use npx for this application on Windows, - # so the Windows user is required to have markdown-link-check installed and in PATH. - if ! which markdown-link-check &>/dev/null; then - echo "markdown-link-check not found or not in PATH." - echo "Please install: https://github.com/tcort/markdown-link-check#readme" - exit 1 - fi - # Default behavior of the task on Windows is to exit the task when the first broken link causes a non-zero - # exit status, but it's better to check all links before exiting. - set +o errexit - STATUS=0 - # Using -regex instead of -name to avoid Task's behavior of globbing even when quoted on Windows - # The odd method for escaping . in the regex is required for windows compatibility because mvdan.cc/sh gives - # \ characters special treatment on Windows in an attempt to support them as path separators. - for file in $( - find . \ - -type d -name '.git' -prune -o \ - -type d -name '.licenses' -prune -o \ - -type d -name '__pycache__' -prune -o \ - -type d -name 'node_modules' -prune -o \ - -regex ".*[.]md" -print - ); do - markdown-link-check \ - --quiet \ - --config "./.markdown-link-check.json" \ - "$file" - STATUS=$(( $STATUS + $? )) - done - exit $STATUS - else - npx --package=markdown-link-check --call=' - STATUS=0 - for file in $( - find . \ - -type d -name '.git' -prune -o \ - -type d -name '.licenses' -prune -o \ - -type d -name '__pycache__' -prune -o \ - -type d -name 'node_modules' -prune -o \ - -regex ".*[.]md" -print - ); do - markdown-link-check \ - --quiet \ - --config "./.markdown-link-check.json" \ - "$file" - STATUS=$(( $STATUS + $? )) - done - exit $STATUS - ' - fi + npx \ + --package=markdown-link-check \ + --call='{{.CHECK_LINKS_COMMAND}}' # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-markdown-task/Taskfile.yml markdown:fix: @@ -313,13 +291,19 @@ tasks: -i \ "{{.FILE_PATH}}" + # Parameter variables: + # - PROJECT_PATH: path of the npm-managed project. Default value: "./" # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/npm-task/Taskfile.yml npm:install-deps: desc: Install dependencies managed by npm run: once + dir: | + "{{default "./" .PROJECT_PATH}}" cmds: - npm install + # Parameter variables: + # - PROJECT_PATH: path of the npm-managed project. Default value: "./" # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-npm-task/Taskfile.yml npm:validate: desc: Validate npm configuration files against their JSON schema @@ -332,6 +316,10 @@ tasks: AVA_SCHEMA_URL: https://json.schemastore.org/ava.json AVA_SCHEMA_PATH: sh: task utility:mktemp-file TEMPLATE="ava-schema-XXXXXXXXXX.json" + # Source: https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/base.json + BASE_SCHEMA_URL: https://json.schemastore.org/base.json + BASE_SCHEMA_PATH: + sh: task utility:mktemp-file TEMPLATE="base-schema-XXXXXXXXXX.json" # Source: https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/eslintrc.json ESLINTRC_SCHEMA_URL: https://json.schemastore.org/eslintrc.json ESLINTRC_SCHEMA_PATH: @@ -344,6 +332,10 @@ tasks: NPM_BADGES_SCHEMA_URL: https://json.schemastore.org/npm-badges.json NPM_BADGES_SCHEMA_PATH: sh: task utility:mktemp-file TEMPLATE="npm-badges-schema-XXXXXXXXXX.json" + # Source: https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/partial-eslint-plugins.json + PARTIAL_ESLINT_PLUGINS_SCHEMA_URL: https://json.schemastore.org/partial-eslint-plugins.json + PARTIAL_ESLINT_PLUGINS_PATH: + sh: task utility:mktemp-file TEMPLATE="partial-eslint-plugins-schema-XXXXXXXXXX.json" # Source: https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/prettierrc.json PRETTIERRC_SCHEMA_URL: https://json.schemastore.org/prettierrc.json PRETTIERRC_SCHEMA_PATH: @@ -356,7 +348,8 @@ tasks: STYLELINTRC_SCHEMA_URL: https://json.schemastore.org/stylelintrc.json STYLELINTRC_SCHEMA_PATH: sh: task utility:mktemp-file TEMPLATE="stylelintrc-schema-XXXXXXXXXX.json" - INSTANCE_PATH: "**/package.json" + INSTANCE_PATH: >- + {{default "." .PROJECT_PATH}}/package.json PROJECT_FOLDER: sh: pwd WORKING_FOLDER: @@ -364,9 +357,11 @@ tasks: cmds: - wget --quiet --output-document="{{.SCHEMA_PATH}}" {{.SCHEMA_URL}} - wget --quiet --output-document="{{.AVA_SCHEMA_PATH}}" {{.AVA_SCHEMA_URL}} + - wget --quiet --output-document="{{.BASE_SCHEMA_PATH}}" {{.BASE_SCHEMA_URL}} - wget --quiet --output-document="{{.ESLINTRC_SCHEMA_PATH}}" {{.ESLINTRC_SCHEMA_URL}} - wget --quiet --output-document="{{.JSCPD_SCHEMA_PATH}}" {{.JSCPD_SCHEMA_URL}} - wget --quiet --output-document="{{.NPM_BADGES_SCHEMA_PATH}}" {{.NPM_BADGES_SCHEMA_URL}} + - wget --quiet --output-document="{{.PARTIAL_ESLINT_PLUGINS_PATH}}" {{.PARTIAL_ESLINT_PLUGINS_SCHEMA_URL}} - wget --quiet --output-document="{{.PRETTIERRC_SCHEMA_PATH}}" {{.PRETTIERRC_SCHEMA_URL}} - wget --quiet --output-document="{{.SEMANTIC_RELEASE_SCHEMA_PATH}}" {{.SEMANTIC_RELEASE_SCHEMA_URL}} - wget --quiet --output-document="{{.STYLELINTRC_SCHEMA_PATH}}" {{.STYLELINTRC_SCHEMA_URL}} @@ -376,9 +371,11 @@ tasks: --all-errors \ -s "{{.SCHEMA_PATH}}" \ -r "{{.AVA_SCHEMA_PATH}}" \ + -r "{{.BASE_SCHEMA_PATH}}" \ -r "{{.ESLINTRC_SCHEMA_PATH}}" \ -r "{{.JSCPD_SCHEMA_PATH}}" \ -r "{{.NPM_BADGES_SCHEMA_PATH}}" \ + -r "{{.PARTIAL_ESLINT_PLUGINS_PATH}}" \ -r "{{.PRETTIERRC_SCHEMA_PATH}}" \ -r "{{.SEMANTIC_RELEASE_SCHEMA_PATH}}" \ -r "{{.STYLELINTRC_SCHEMA_PATH}}" \