diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 17baef0..348a35f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,6 +2,9 @@ { "name": "hacs/action", "image": "ludeeus/container:python", + "containerEnv": { + "GITHUB_ACTION_PATH": "./" + }, "context": "..", "extensions": [ "github.vscode-pull-request-github", diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 72ad5f5..90867b3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,22 @@ on: - main jobs: + lint: + runs-on: ubuntu-latest + name: Lint + steps: + - name: Checkout the repository + uses: actions/checkout@v2 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@master + with: + additional_files: run common checks helpers + env: + SHELLCHECK_OPTS: --exclude SC2034 + integration: + needs: lint runs-on: ubuntu-latest name: "integration: ${{ matrix.repository }}" strategy: @@ -24,6 +39,7 @@ jobs: repository: ${{ matrix.repository }} theme: + needs: lint runs-on: ubuntu-latest name: "theme: ${{ matrix.repository }}" strategy: @@ -42,6 +58,7 @@ jobs: repository: ${{ matrix.repository }} plugin: + needs: lint runs-on: ubuntu-latest name: "plugin: ${{ matrix.repository }}" strategy: @@ -57,9 +74,11 @@ jobs: uses: ./ with: category: plugin + ignore: images repository: ${{ matrix.repository }} netdaemon: + needs: lint runs-on: ubuntu-latest name: "netdaemon: ${{ matrix.repository }}" strategy: @@ -79,6 +98,7 @@ jobs: repository: ${{ matrix.repository }} appdaemon: + needs: lint runs-on: ubuntu-latest name: "appdaemon: ${{ matrix.repository }}" strategy: @@ -97,6 +117,7 @@ jobs: repository: ${{ matrix.repository }} python_script: + needs: lint runs-on: ubuntu-latest name: "python_scripts: ${{ matrix.repository }}" strategy: diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac982cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +result +error +data +dummy \ No newline at end of file diff --git a/action.yml b/action.yml index 279316c..3154f4d 100644 --- a/action.yml +++ b/action.yml @@ -19,13 +19,7 @@ runs: steps: - shell: bash run: | - echo ${{steps.init.outputs.path }} - rm -rf "${{ github.action_path }}/data" - rm -rf "${{ github.action_path }}/hacs" - rm -rf "${{ github.action_path }}/brands" - rm -rf "${{ github.action_path }}/default" - rm -f "${{ github.action_path }}/error" - rm -f "${{ github.action_path }}/result" + bash "${{ github.action_path }}/helpers/cleanup" - shell: bash id: init @@ -34,15 +28,15 @@ runs: git clone --quiet --depth 1 https://github.com/hacs/integration.git "${{ github.action_path }}/hacs" > /dev/null - if [ ! -z "${{ github.event.inputs.repository }}" ]; then + if [ -n "${{ github.event.inputs.repository }}" ]; then repository="${{ github.event.inputs.repository }}" - elif [ ! -z "${{ inputs.repository }}" ]; then + elif [ -n "${{ inputs.repository }}" ]; then repository="${{ inputs.repository }}" else repository="${{ github.repository }}" fi - if [ ! -z "${{ github.event.inputs.category }}" ]; then + if [ -n "${{ github.event.inputs.category }}" ]; then category="${{ github.event.inputs.category }}" else category="${{ inputs.category }}" @@ -66,350 +60,20 @@ runs: echo "::set-output name=category::$category" echo "::set-output name=path::$path" - - shell: bash - id: manifest - run: | - moreinfo="(more-info: https://hacs.xyz/docs/publish/include#check-manifest )" - if [ "${{ inputs.category }}" == "integration" ]; then - echo "::group::manifest" - echo "https://hacs.xyz/docs/publish/include#check-manifest" - manifest=$(find "${{ steps.init.outputs.path }}" -name manifest.json) - if [ ! -f "$manifest" ]; then - echo "❌ manifest.json file not found $moreinfo"; - exit 1 - else - echo "::set-output name=path::$manifest" - cat "$manifest" | jq . - for key in "issue_tracker domain documentation codeowners"; do - if [ -z "$(jq --arg entry "$key" '.[$entry]' -r "$manifest")" ]; then - echo "❌ manifest.json file missing key $key $moreinfo"; - exit 1 - fi - done - fi - echo "::endgroup::" - fi - - - shell: bash - run: | - data=$(jq .description -r "${{ github.action_path }}/data/info") > /dev/null - if [[ ! "${{ inputs.ignore }}" =~ description ]]; then - echo "::group::description" - echo "https://hacs.xyz/docs/publish/include#check-repository" - if [ ! -z "${data}" ] && [ "${data}" != "null" ]; then - echo "${data}" - echo "✅ The repository has a description" >> "${{ github.action_path }}/result" - else - echo "❌ The repository is missing a description (more-info: https://hacs.xyz/docs/publish/include#check-repository )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: description" >> "${{ github.action_path }}/result" - fi - - - shell: bash - run: | - data=$(jq .archived -r "${{ github.action_path }}/data/info") > /dev/null - if [[ ! "${{ inputs.ignore }}" =~ archived ]]; then - echo "::group::archived" - echo "https://hacs.xyz/docs/publish/include#check-archived" - if [ "${data}" == "false" ]; then - echo "✅ The repository is not archived" >> "${{ github.action_path }}/result" - else - echo "❌ The repository is archived (more-info: https://hacs.xyz/docs/publish/include#check-archived )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: description" >> "${{ github.action_path }}/result" - fi - - - shell: bash - run: | - if [ "${{ inputs.category }}" == "integration" ]; then - if [[ ! "${{ inputs.ignore }}" =~ brands ]]; then - echo "::group::brands" - echo "https://hacs.xyz/docs/publish/include#check-brands" - domain=$(jq .domain -r ${{ steps.manifest.outputs.path }}) - git clone --quiet --depth 1 https://github.com/home-assistant/brands.git "${{ github.action_path }}/brands" > /dev/null - exsist=$(find "${{ github.action_path }}/brands" -type d -name "$domain") - if [ ! -z "${exsist}" ]; then - echo "${exsist}" - echo "✅ $domain is added to https://github.com/home-assistant/brands NICE!" >> "${{ github.action_path }}/result" - else - echo "❌ $domain is not added to https://github.com/home-assistant/brands (more-info: https://hacs.xyz/docs/publish/include#check-brands )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: description" >> "${{ github.action_path }}/result" - fi - fi - - - shell: bash - run: | - data=$(jq .names[] -r "${{ github.action_path }}/data/topics") > /dev/null - if [[ ! "${{ inputs.ignore }}" =~ topics ]]; then - echo "::group::topics" - echo "https://hacs.xyz/docs/publish/include#check-repository" - if [ ! -z "${data}" ]; then - echo "${data}" - echo "✅ The repository has topics" >> "${{ github.action_path }}/result" - else - echo "❌ The repository is missing topics (more-info: https://hacs.xyz/docs/publish/include#check-repository )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: description" >> "${{ github.action_path }}/result" - fi - - - shell: bash - run: | - data=$(jq .has_issues -r "${{ github.action_path }}/data/info") > /dev/null - if [[ ! "${{ inputs.ignore }}" =~ issues ]]; then - echo "::group::issues" - echo "https://hacs.xyz/docs/publish/include#check-repository" - echo "https://github.com/${{ steps.init.outputs.repository }}/issues" - if [ "${data}" == "true" ]; then - echo "✅ The repository has issues enabled" >> "${{ github.action_path }}/result" - else - echo "❌ The repository has not issues enabled (more-info: https://hacs.xyz/docs/publish/include#check-repository )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: issues" >> "${{ github.action_path }}/result" - fi - - - shell: bash - run: | - moreinfo="(more-info: https://hacs.xyz/docs/publish/include#check-fork)" - data=$(jq .fork -r "${{ github.action_path }}/data/info") > /dev/null - if [[ "${{ github.repository }}" == "hacs/default" ]]; then - echo "::group::fork" - echo "https://hacs.xyz/docs/publish/include#check-fork" - if [ "${data}" == "false" ]; then - echo "✅ The repository is not a fork" >> "${{ github.action_path }}/result" - else - echo "⚪ The repository is a fork (more-info: https://hacs.xyz/docs/publish/include#check-fork )" >> "${{ github.action_path }}/result" - fi - echo "::endgroup::" - fi - - - shell: bash - id: hacsjson - run: | - moreinfo="(more-info: https://hacs.xyz/docs/publish/include#check-hacs-manifest)" - if [[ ! "${{ inputs.ignore }}" =~ hacsjson ]]; then - echo "::group::hacsjson" - echo "https://hacs.xyz/docs/publish/include#check-hacs-manifest" - if [ ! -f "${{ steps.init.outputs.path }}/hacs.json" ]; then - echo "❌ hacs.json file not found in the root of the repository $moreinfo" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - else - cat "${{ steps.init.outputs.path }}/hacs.json" | jq . - echo "::set-output name=path::"${{ steps.init.outputs.path }}/hacs.json"" - name=$(jq .name "${{ steps.init.outputs.path }}/hacs.json") - if [ ! -z "${name}" ]; then - echo "✅ hacs.json has the 'name' key set" >> "${{ github.action_path }}/result" - else - echo "❌ Missing 'name' from hacs.json (more-info: https://hacs.xyz/docs/publish/include#check-hacs-manifest )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: hacsjson" >> "${{ github.action_path }}/result" - fi - - - shell: bash - run: | - echo "✅ This day ends with an 'y' ($(date +%A))" >> "${{ github.action_path }}/result" - - - shell: bash - id: information - run: | - if [[ ! "${{ inputs.ignore }}" =~ information ]]; then - echo "::group::information" - echo "https://hacs.xyz/docs/publish/include#check-info" - if [ -f "${{ steps.init.outputs.path }}/hacs.json" ]; then - render_readme=$(jq .render_readme -r "${{ steps.init.outputs.path }}/hacs.json") - fi - if [ -f "${{ steps.init.outputs.path }}/README.md" ] && [ "$render_readme" == "true" ]; then - echo "✅ README.md exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/README.md" - - elif [ -f "${{ steps.init.outputs.path }}/readme.md" ] && [ "$render_readme" == "true" ]; then - echo "✅ readme.md exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/readme.md" - - elif [ -f "${{ steps.init.outputs.path }}/README.MD" ] && [ "$render_readme" == "true" ]; then - echo "✅ README.MD exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/README.MD" - - elif [ -f "${{ steps.init.outputs.path }}/readme.MD" ] && [ "$render_readme" == "true" ]; then - echo "✅ readme.MD exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/readme.MD" - - elif [ -f "${{ steps.init.outputs.path }}/readme" ] && [ "$render_readme" == "true" ]; then - echo "✅ readme exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/readme" - - elif [ -f "${{ steps.init.outputs.path }}/README" ] && [ "$render_readme" == "true" ]; then - echo "✅ README exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/README" - - elif [ -f "${{ steps.init.outputs.path }}/INFO.md" ]; then - echo "✅ INFO.md exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/INFO.md" - - elif [ -f "${{ steps.init.outputs.path }}/info.md" ]; then - echo "✅ info.md exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/info.md" - - elif [ -f "${{ steps.init.outputs.path }}/INFO.MD" ]; then - echo "✅ INFO.MD exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/INFO.MD" - - elif [ -f "${{ steps.init.outputs.path }}/info.MD" ]; then - echo "✅ info.MD exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/info.MD" - - elif [ -f "${{ steps.init.outputs.path }}/INFO" ]; then - echo "✅ INFO exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/INFO" - - elif [ -f "${{ steps.init.outputs.path }}/info" ]; then - echo "✅ info exsists" >> "${{ github.action_path }}/result" - filepath="${{ steps.init.outputs.path }}/info" - else - echo "❌ Information file not found (more-info: https://hacs.xyz/docs/publish/include#check-info )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::set-output name=path::$filepath" - if [ -f "$filepath" ];then - cat "$filepath" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: information" >> "${{ github.action_path }}/result" - fi + echo "$repository" > "${{ github.action_path }}/data/repository" + echo "${{ github.repository }}" > "${{ github.action_path }}/data/action_repository" + echo "$category" > "${{ github.action_path }}/data/category" + echo "$path" > "${{ github.action_path }}/data/path" + echo "${{ inputs.ignore }}" > "${{ github.action_path }}/data/ignore" + echo "${{ github.token }}" > "${{ github.action_path }}/data/token" - shell: bash run: | - if [ "${{ inputs.category }}" == "integration" ]; then - if [[ ! "${{ inputs.ignore }}" =~ requirements ]]; then - requirements=$(cat "${{ steps.manifest.outputs.path }}" | jq -r '. | select(.requirements != null) | .requirements[]') > /dev/null - if [ ! -z "$requirements" ]; then - echo "::group::requirements" - mkdir -p "${{ steps.init.outputs.path }}/requirements" - wget -q -O "${{ github.action_path }}/helpers/requirements/validate_requirements.py" \ - https://raw.githubusercontent.com/home-assistant/wheels-custom-integrations/master/scripts/validate_requirements.py - cd "${{ github.action_path }}/helpers/requirements" - cat "${{ steps.manifest.outputs.path }}" | jq -r .requirements > ./requirements.json - cat ./requirements.json | jq . - docker build . -t homeassistant/home-assistant:beta - set +e - docker run homeassistant/home-assistant:beta - requirements=$? - set -e - if [ "${requirements}" == 0 ]; then - echo "✅ Requirements validation" >> "${{ github.action_path }}/result" - else - echo "❌ Requirements validation" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - fi - else - echo "⚪ Skipped check: requirements" >> "${{ github.action_path }}/result" - fi - fi - - - shell: bash - run: | - if [ "plugin" == ${{ inputs.category }} ] || [ "theme" == ${{ inputs.category }} ]; then - if [[ ! "${{ inputs.ignore }}" =~ images ]]; then - echo "::group::images" - echo "https://hacs.xyz/docs/publish/include#check-images" - images=$(python3 ${{ github.action_path }}/helpers/findimages.py "${{ steps.information.outputs.path }}") - if [ ! -z "${images}" ]; then - echo "${images}" - echo "✅ Information file has images" >> "${{ github.action_path }}/result" - else - echo "❌ There should be images to show the user what they get." >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: images" >> "${{ github.action_path }}/result" - fi - fi + bash "${{ github.action_path }}/run" - shell: bash - run: | - if [ "${{ inputs.category }}" == "integration" ]; then - if [[ ! "${{ inputs.ignore }}" =~ wheels ]]; then - requirements=$(cat "${{ steps.manifest.outputs.path }}" | jq -r '. | select(.requirements != null) | .requirements[]') > /dev/null - if [ ! -z "$requirements" ]; then - echo "::group::wheels" - echo "https://hacs.xyz/docs/publish/include#check-wheels" - domain=$(jq .domain -r ${{ steps.manifest.outputs.path }}) - set +e - wheelsurl="https://raw.githubusercontent.com/home-assistant/wheels-custom-integrations/master/components/$domain.json" - curl -sSLf "$wheelsurl" > /dev/null - wheels=$? - set -e - if [ "${wheels}" == 0 ]; then - echo "${wheelsurl}" - echo "✅ Python wheels" >> "${{ github.action_path }}/result" - else - echo "❌ Python wheels (more-info: https://hacs.xyz/docs/publish/include#check-wheels" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - fi - else - echo "⚪ Skipped check: wheels" >> "${{ github.action_path }}/result" - fi - fi + run: bash "${{ github.action_path }}/helpers/wrapup" "${{ github.action_path }}" - shell: bash run: | - if [[ ! "${{ inputs.ignore }}" =~ hacs ]]; then - echo "::group::hacs" - echo "https://hacs.xyz/docs/publish/include#check-hacs" - cd "${{ github.action_path }}/hacs/action" - cp "${{ github.action_path }}/helpers/action.py" "./action.py" - docker build . -t hacs/action - set +e - docker run \ - -e INPUT_GITHUB_TOKEN="${{ github.token }}" \ - -e GITHUB_ACTOR="${{ github.actor }}" \ - -e GITHUB_ACTION \ - -e GITHUB_WORKSPACE="/github/workspace" \ - -e GITHUB_EVENT_PATH="/github/event.json" \ - -e GITHUB_REPOSITORY="${{ github.repository }}" \ - -e CHANGED_FILES="$CHANGED_FILES" \ - -e REPOSITORY="${{ steps.init.outputs.repository }}" \ - -e CATEGORY="${{ steps.init.outputs.category }}" \ - -v "${{ github.event_path }}":/github/event.json \ - -v "${{ github.workspace }}":/github/workspace \ - hacs/action - hacs=$? - set -e - if [ "${hacs}" == 0 ]; then - echo "✅ HACS load check" >> "${{ github.action_path }}/result" - else - echo "❌ HACS load check (more-info: https://hacs.xyz/docs/publish/include#check-hacs )" >> "${{ github.action_path }}/result" - touch "${{ github.action_path }}/error" - fi - echo "::endgroup::" - else - echo "⚪ Skipped check: hacs" >> "${{ github.action_path }}/result" - fi - - - shell: bash - run: bash "${{ github.action_path }}/helpers/wrapup" "${{ github.action_path }}" + bash "${{ github.action_path }}/helpers/cleanup" diff --git a/checks/archived b/checks/archived new file mode 100644 index 0000000..213ac9a --- /dev/null +++ b/checks/archived @@ -0,0 +1,12 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-archived" +GROUP="archived" + +function checkRun () { + data=$(repoInfo archived) + if [ "${data}" == "false" ]; then + checkSuccess "The repository is not archived" + else + checkError "The repository is archived" + fi +} diff --git a/checks/brands b/checks/brands new file mode 100644 index 0000000..2ac76fe --- /dev/null +++ b/checks/brands @@ -0,0 +1,23 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-brands" +GROUP="brands" + +function checkCondition () { + category=$(cat "$GITHUB_ACTION_PATH"/data/category) + if [ "$category" != "integration" ]; then + return 1 + fi +} + +function checkRun () { + echo "https://hacs.xyz/docs/publish/include#check-brands" + domain=$(jq .domain -r "$GITHUB_ACTION_PATH/data/manifest.json") + git clone --quiet --depth 1 https://github.com/home-assistant/brands.git "$GITHUB_ACTION_PATH/brands" > /dev/null + exsist=$(find "$GITHUB_ACTION_PATH/brands" -type d -name "$domain") + if [ -n "${exsist}" ]; then + echo "${exsist}" + checkSuccess "$domain is added to https://github.com/home-assistant/brands NICE!" + else + checkError "$domain is not added to https://github.com/home-assistant/brands" + fi +} diff --git a/checks/day b/checks/day new file mode 100644 index 0000000..4e9fa41 --- /dev/null +++ b/checks/day @@ -0,0 +1,7 @@ +#!/bin/bash +URL=$(date +%A) +GROUP="day" + +function checkRun () { + checkSuccess "This day ends with an 'y' ($(date +%A))" +} diff --git a/checks/description b/checks/description new file mode 100644 index 0000000..72dae6e --- /dev/null +++ b/checks/description @@ -0,0 +1,13 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-repository" +GROUP="description" + +function checkRun () { + data=$(repoInfo description) + if [ -n "${data}" ] && [ "${data}" != "null" ]; then + echo "${data}" + checkSuccess "The repository has a description" + else + checkError "The repository is missing a description" + fi +} diff --git a/checks/fork b/checks/fork new file mode 100644 index 0000000..ed5dc06 --- /dev/null +++ b/checks/fork @@ -0,0 +1,19 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-fork" +GROUP="fork" + +function checkCondition () { + action_repository=$(cat "$GITHUB_ACTION_PATH"/data/action_repository) + if [ "$action_repository" != "hacs/default" ]; then + return 1 + fi +} + +function checkRun () { + data=$(repoInfo fork) + if [ "${data}" == "false" ]; then + checkSuccess "The repository is not a fork" + else + checkNeutral "The repository is a fork" + fi +} diff --git a/checks/hacs b/checks/hacs new file mode 100644 index 0000000..5948c29 --- /dev/null +++ b/checks/hacs @@ -0,0 +1,30 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-hacs" +GROUP="hacs" + +function checkRun () { + cd "$GITHUB_ACTION_PATH/hacs/action" + cp "$GITHUB_ACTION_PATH/helpers/action.py" "./action.py" + docker build . -t hacs/action + set +e + docker run \ + -e INPUT_GITHUB_TOKEN="$(cat "$GITHUB_ACTION_PATH"/data/token)" \ + -e GITHUB_ACTOR="$GITHUB_ACTOR" \ + -e GITHUB_ACTION \ + -e GITHUB_WORKSPACE="$GITHUB_WORKSPACE" \ + -e GITHUB_EVENT_PATH="$GITHUB_EVENT_PATH" \ + -e GITHUB_REPOSITORY="$GITHUB_REPOSITORY" \ + -e CHANGED_FILES="$CHANGED_FILES" \ + -e REPOSITORY="$(cat "$GITHUB_ACTION_PATH"/data/repository)" \ + -e CATEGORY="$(cat "$GITHUB_ACTION_PATH"/data/category)" \ + -v "$GITHUB_EVENT_PATH":/github/event.json \ + -v "$GITHUB_WORKSPACE":/github/workspace \ + hacs/action + hacs=$? + set -e + if [ "${hacs}" == 0 ]; then + checkSuccess "HACS load check" + else + checkError "HACS load check" + fi +} diff --git a/checks/hacsjson b/checks/hacsjson new file mode 100644 index 0000000..0f4e8cc --- /dev/null +++ b/checks/hacsjson @@ -0,0 +1,19 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-hacs-manifest" +GROUP="hacsjson" + +function checkRun () { + repoPath=$(cat "$GITHUB_ACTION_PATH"/data/path) + if [ ! -f "$repoPath/hacs.json" ]; then + checkError "hacs.json file not found in the root of the repository" + else + jq . "$repoPath/hacs.json" > "$GITHUB_ACTION_PATH/data/hacs.json" + jq . "$GITHUB_ACTION_PATH/data/hacs.json" + name=$(jq .name "$GITHUB_ACTION_PATH/data/hacs.json") + if [ -n "${name}" ]; then + checkSuccess "hacs.json has the 'name' key set" + else + checkError "Missing 'name' from hacs.json" + fi + fi +} diff --git a/checks/images b/checks/images new file mode 100644 index 0000000..01211ff --- /dev/null +++ b/checks/images @@ -0,0 +1,21 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-images" +GROUP="images" + +function checkCondition () { + category=$(cat "$GITHUB_ACTION_PATH"/data/category) + if [ "$category" == "plugin" ] || [ "$category" == "theme" ]; then + return 0 + fi + return 1 +} + +function checkRun () { + images=$(python3 "$GITHUB_ACTION_PATH"/helpers/findimages.py) + if [ -n "${images}" ]; then + echo "${images}" + checkSuccess "Information file has images" + else + checkError "There should be images to show the user what they get" + fi +} diff --git a/checks/information b/checks/information new file mode 100644 index 0000000..ba3fa4c --- /dev/null +++ b/checks/information @@ -0,0 +1,45 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-info" +GROUP="information" + +declare -a paths=( + "README.md" + "readme.md" + "README.MD" + "readme.MD" + "readme" + "README" + "INFO.md" + "info.md" + "INFO.MD" + "info.MD" + "info" + "INFO" +) + +function checkRun () { + repoPath=$(cat "$GITHUB_ACTION_PATH"/data/path) + render_readme=$(jq .render_readme -r "$repoPath/hacs.json") + + for path in "${paths[@]}"; do + if [ ! -f "$GITHUB_ACTION_PATH/data/readme.md" ]; then + if [ -f "$repoPath/$path" ]; then + if [[ "$path" =~ "readme" ]] || [[ "$path" =~ "README" ]]; then + if [ "$render_readme" == "true" ]; then + checkSuccess "$path exists" + cp "$repoPath/$path" "$GITHUB_ACTION_PATH/data/readme.md" + fi + else + checkSuccess "$path exists" + cp "$repoPath/$path" "$GITHUB_ACTION_PATH/data/readme.md" + fi + fi + fi + done + + if [ ! -f "$GITHUB_ACTION_PATH/data/readme.md" ]; then + checkError "Missing information file" + else + cat "$GITHUB_ACTION_PATH/data/readme.md" + fi +} diff --git a/checks/issues b/checks/issues new file mode 100644 index 0000000..331a262 --- /dev/null +++ b/checks/issues @@ -0,0 +1,14 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-repository" +GROUP="issues" + +function checkRun () { + data=$(repoInfo has_issues) + repository=$(cat "$GITHUB_ACTION_PATH"/data/repository) + echo "https://github.com/$repository/issues" + if [ "${data}" == "true" ]; then + checkSuccess "The repository has issues enabled" + else + checkError "The repository have not issues enabled" + fi +} diff --git a/checks/manifest b/checks/manifest new file mode 100644 index 0000000..3849848 --- /dev/null +++ b/checks/manifest @@ -0,0 +1,37 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-manifest" +GROUP="manifest" + +declare -a requiredKeys=( + issue_tracker + domain + documentation + codeowners +) + +function checkCondition () { + category=$(cat "$GITHUB_ACTION_PATH"/data/category) + if [ "$category" != "integration" ]; then + return 1 + fi +} + +function checkRun () { + repoPath=$(cat "$GITHUB_ACTION_PATH"/data/path) + manifest=$(find "$repoPath" -name manifest.json) + if [ ! -f "$manifest" ]; then + checkError "manifest.json file not found" + exit 1 + else + checkSuccess "manifest.json file exist" + jq . "$manifest" > "$GITHUB_ACTION_PATH/data/manifest.json" + jq . "$GITHUB_ACTION_PATH/data/manifest.json" + for key in "${requiredKeys[@]}"; do + if [ "$(jq --arg entry "$key" '.[$entry]' -r "$manifest")" == "null" ]; then + checkError "manifest.json file missing key $key" + exit 1 + fi + done + checkSuccess "All required keys are present in manifest.json" + fi +} diff --git a/checks/requirements b/checks/requirements new file mode 100644 index 0000000..d76eb4d --- /dev/null +++ b/checks/requirements @@ -0,0 +1,35 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-requirements" +GROUP="requirements" + +function checkCondition () { + category=$(cat "$GITHUB_ACTION_PATH"/data/category) + if [ "$category" == "integration" ]; then + requirements=$(jq -r '. | select(.requirements != null) | .requirements[]' "$GITHUB_ACTION_PATH/data/manifest.json") > /dev/null + if [ -n "$requirements" ]; then + return 0 + fi + fi + return 1 +} + + +function checkRun () { + repoPath=$(cat "$GITHUB_ACTION_PATH"/data/path) + mkdir -p "$repoPath/requirements" + wget -q -O "$GITHUB_ACTION_PATH/helpers/requirements/validate_requirements.py" \ + https://raw.githubusercontent.com/home-assistant/wheels-custom-integrations/master/scripts/validate_requirements.py + cd "$GITHUB_ACTION_PATH/helpers/requirements" + jq -r .requirements "$GITHUB_ACTION_PATH/data/manifest.json" > ./requirements.json + jq . ./requirements.json + docker build . -t homeassistant/home-assistant:beta + set +e + docker run homeassistant/home-assistant:beta + requirements="$?" + set -e + if [ "${requirements}" == 0 ]; then + checkSuccess "Requirements validation" + else + checkError "Requirements validation" + fi +} diff --git a/checks/topics b/checks/topics new file mode 100644 index 0000000..27f839e --- /dev/null +++ b/checks/topics @@ -0,0 +1,13 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-repository" +GROUP="topics" + +function checkRun () { + data=$(jq .names[] -r "$GITHUB_ACTION_PATH/data/topics") > /dev/null + if [ -n "${data}" ]; then + echo "${data}" + checkSuccess "The repository has topics" + else + checkError "The repository is missing topics" + fi +} diff --git a/checks/wheels b/checks/wheels new file mode 100644 index 0000000..5fc284b --- /dev/null +++ b/checks/wheels @@ -0,0 +1,29 @@ +#!/bin/bash +URL="https://hacs.xyz/docs/publish/include#check-wheels" +GROUP="wheels" + +function checkCondition () { + category=$(cat "$GITHUB_ACTION_PATH"/data/category) + if [ "$category" == "integration" ]; then + requirements=$(jq -r '. | select(.requirements != null) | .requirements[]' "$GITHUB_ACTION_PATH/data/manifest.json") > /dev/null + if [ -n "$requirements" ]; then + return 0 + fi + fi + return 1 +} + + +function checkRun () { + domain=$(jq .domain -r "$GITHUB_ACTION_PATH/data/manifest.json") + set +e + wheelsurl="https://raw.githubusercontent.com/home-assistant/wheels-custom-integrations/master/components/$domain.json" + curl -sSLf "$wheelsurl" > /dev/null + wheels=$? + set -e + if [ "${wheels}" == 0 ]; then + checkSuccess "Python wheels" + else + checkError "Python wheels" + fi +} diff --git a/common b/common new file mode 100644 index 0000000..c02447f --- /dev/null +++ b/common @@ -0,0 +1,69 @@ +#!/bin/bash + +EMOJI_CHECK="✅" +EMOJI_RED_X="❌" +EMOJI_WHITE_CIRCLE="⚪" + +function repoInfo () { + info=$(jq ."$1" -r "$GITHUB_ACTION_PATH/data/info") > /dev/null + echo "$info" +} + +function checkInit () { + echo "::group::$GROUP" + echo "More info: $URL" +} + +function checkComplete () { + echo "::endgroup::" +} + +function checkSuccess () { + echo "$EMOJI_CHECK $1" >> "$GITHUB_ACTION_PATH/result" +} + +function checkNeutral () { + echo "$EMOJI_WHITE_CIRCLE $1 (more-info: $URL )" >> "$GITHUB_ACTION_PATH/result" +} + +function checkError () { + echo "::error::$1" + msg="$1 (more-info: $URL )" + echo "$EMOJI_RED_X $msg" >> "$GITHUB_ACTION_PATH/result" + touch "$GITHUB_ACTION_PATH/error" +} + +function checkWarning () { + echo "::warning::$1" +} + +function setOutput () { + echo "::set-output name=$1::$2" +} + +function checkRun () { + echo "No checkRun function for $GROUP" +} + +function checkCondition () { + return 0 +} + +function checkIgnored () { + ignore=$(cat "$GITHUB_ACTION_PATH/data/ignore") + if [[ "$ignore" =~ $GROUP ]]; then + return 1 + fi +} + +function checkExecute () { + if checkIgnored ;then + if checkCondition ;then + checkInit + checkRun + checkComplete + fi + else + echo "$EMOJI_WHITE_CIRCLE Ignored check: $GROUP" >> "$GITHUB_ACTION_PATH/result" + fi +} \ No newline at end of file diff --git a/helpers/cleanup b/helpers/cleanup new file mode 100644 index 0000000..7d8f2d3 --- /dev/null +++ b/helpers/cleanup @@ -0,0 +1,6 @@ +rm -rf "$GITHUB_ACTION_PATH/data" +rm -rf "$GITHUB_ACTION_PATH/hacs" +rm -rf "$GITHUB_ACTION_PATH/brands" +rm -rf "$GITHUB_ACTION_PATH/default" +rm -f "$GITHUB_ACTION_PATH/error" +rm -f "$GITHUB_ACTION_PATH/result" \ No newline at end of file diff --git a/helpers/findimages.py b/helpers/findimages.py index 82b7a47..ed8ac08 100644 --- a/helpers/findimages.py +++ b/helpers/findimages.py @@ -1,6 +1,17 @@ -import sys +import os -with open(sys.argv[-1], "r") as inputfile: +ignored = [ + "-shield", + "img.shields.io", + "buymeacoffee.com" +] + +with open(f"{os.getenv('GITHUB_ACTION_PATH')}/data/readme.md", "r") as inputfile: for line in inputfile.read().split("\n"): if "