diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 984e415a..76ee0bfe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,10 @@ -# CI checks to run when PR is opened -name: ๐Ÿšฆ PR Check +# CI checks to run when a PR is opened, or manually via workflow_dispatch +name: ๐Ÿšฆ CI on: pull_request: branches: ['master', 'develop'] + workflow_dispatch: permissions: contents: read @@ -53,7 +54,7 @@ jobs: name: ๐Ÿ›ก๏ธ Lint runs-on: ubuntu-latest needs: changes - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' steps: - name: Checkout Code uses: actions/checkout@v6 @@ -74,7 +75,7 @@ jobs: name: ๐Ÿฆด Typecheck runs-on: ubuntu-latest needs: changes - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' steps: - name: Checkout Code uses: actions/checkout@v6 @@ -108,13 +109,21 @@ jobs: run: yarn install --frozen-lockfile - name: Run Tests - run: yarn test + run: yarn test 2>&1 | tee test-report.txt + + - name: Upload Test Report + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-report + path: test-report.txt + if-no-files-found: ignore locales: name: ๐ŸŒ Locale Check runs-on: ubuntu-latest needs: changes - if: needs.changes.outputs.locales == 'true' + if: needs.changes.outputs.locales == 'true' || github.event_name == 'workflow_dispatch' steps: - name: Checkout Code uses: actions/checkout@v6 @@ -125,13 +134,21 @@ jobs: node-version: '20' - name: Check Locales - run: yarn validate-locales + run: yarn validate-locales 2>&1 | tee locale-report.txt + + - name: Upload Locale Report + if: always() + uses: actions/upload-artifact@v4 + with: + name: locale-report + path: locale-report.txt + if-no-files-found: ignore spellcheck: name: โœ๏ธ Spellcheck runs-on: ubuntu-latest needs: changes - if: needs.changes.outputs.translations == 'true' + if: needs.changes.outputs.translations == 'true' || github.event_name == 'workflow_dispatch' steps: - name: Checkout Code uses: actions/checkout@v6 @@ -188,7 +205,7 @@ jobs: name: ๐Ÿ”’ Dependency Audit runs-on: ubuntu-latest needs: changes - if: needs.changes.outputs.lockfile == 'true' + if: needs.changes.outputs.lockfile == 'true' && github.event_name == 'pull_request' permissions: contents: read steps: @@ -222,7 +239,7 @@ jobs: name: ๐Ÿ› ๏ธ Workflow Audit runs-on: ubuntu-latest needs: changes - if: needs.changes.outputs.workflows == 'true' + if: needs.changes.outputs.workflows == 'true' || github.event_name == 'workflow_dispatch' steps: - name: Checkout Code uses: actions/checkout@v6 @@ -238,3 +255,75 @@ jobs: inputs: .github/workflows/ advanced-security: false annotations: true + + # Renders markdown summary of all checks at the end + summary: + name: ๐Ÿ“‹ Summary + runs-on: ubuntu-latest + if: always() + continue-on-error: true + needs: + - lint + - typecheck + - test + - locales + - spellcheck + - build + - docker-smoke + - dependency-review + - secret-scan + - workflow-audit + steps: + - name: Download Reports + uses: actions/download-artifact@v4 + continue-on-error: true + with: + path: reports + merge-multiple: true + + - name: Render Summary + env: + NEEDS: ${{ toJSON(needs) }} + run: | + label() { + case "$1" in + lint) echo "๐Ÿ›ก๏ธ Lint" ;; + typecheck) echo "๐Ÿฆด Typecheck" ;; + test) echo "๐Ÿงช Test" ;; + locales) echo "๐ŸŒ Locale Check" ;; + spellcheck) echo "โœ๏ธ Spellcheck" ;; + build) echo "๐Ÿ—๏ธ Build" ;; + docker-smoke) echo "๐Ÿณ Docker Smoke" ;; + dependency-review) echo "๐Ÿ”’ Dependency Audit" ;; + secret-scan) echo "๐Ÿ”‘ Secret Scan" ;; + workflow-audit) echo "๐Ÿ› ๏ธ Workflow Audit" ;; + *) echo "$1" ;; + esac + } + status() { + case "$1" in + success) echo "โœ… Passed" ;; + skipped) echo "โญ๏ธ Skipped" ;; + cancelled) echo "๐Ÿšซ Cancelled" ;; + failure) [ "$2" = docker-smoke ] && echo "โš ๏ธ Warnings" || echo "โŒ Failed" ;; + *) echo "โ” $1" ;; + esac + } + details() { + [ -f "$2" ] || return 0 + printf '\n
%s\n\n```\n' "$1" >> "$GITHUB_STEP_SUMMARY" + cat "$2" >> "$GITHUB_STEP_SUMMARY" + printf '\n```\n
\n' >> "$GITHUB_STEP_SUMMARY" + } + { + echo "## CI Summary" + echo "" + echo "| Check | Status |" + echo "|-------|--------|" + } >> "$GITHUB_STEP_SUMMARY" + for job in $(echo "$NEEDS" | jq -r 'keys[]'); do + result=$(echo "$NEEDS" | jq -r --arg j "$job" '.[$j].result') + echo "| $(label "$job") | $(status "$result" "$job") |" >> "$GITHUB_STEP_SUMMARY" + done + details "๐Ÿงช Test Report" reports/test-report.txt + details "๐ŸŒ Locale Report" reports/locale-report.txt diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 58902f4f..d4a46cd9 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -276,6 +276,9 @@ jobs: const sixMonthsAgo = new Date(); sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6); const isOld = new Date(issue.created_at) < sixMonthsAgo; + const sevenDaysAgo = new Date(); + sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7); + const isNew = new Date(issue.created_at) > sevenDaysAgo; const byLine = creditAuthor ? ` by @${prAuthor}` : ''; const parts = [ greeting, @@ -283,6 +286,10 @@ jobs: `and will be released shortly in ${version} ๐Ÿ˜‡`, ]; if (isOld) parts.push(`\n\nWe're sorry this one took so long ๐Ÿ˜”`); + if (isNew) { + parts.push(`\n\nIf you're enjoying Dashy, consider ` + + `[sponsoring us](https://github.com/sponsors/lissy93) on GitHub to help with development ๐Ÿ’–`); + } parts.push(``); const body = parts.join(' '); await github.rest.issues.createComment({ @@ -337,7 +344,7 @@ jobs: VERSION="${TAG_VERSION:-$(node -p "require('./package.json').version" 2>/dev/null || echo "unknown")}" { - echo "## ๐Ÿ”– Auto Version & Tag" + echo "## Auto Version & Tag" echo "" echo "| Step | Result |" echo "|------|--------|"