diff --git a/.github/workflows/generate-theme-doc.yml b/.github/workflows/generate-theme-doc.yml new file mode 100644 index 00000000..9be86dc9 --- /dev/null +++ b/.github/workflows/generate-theme-doc.yml @@ -0,0 +1,53 @@ +name: Generate Theme Readme +on: + push: + branches: + - master + paths: + - "apps/backend/themes/index.js" + workflow_dispatch: + +permissions: {} + +jobs: + generate-theme-doc: + runs-on: ubuntu-latest + name: Generate theme doc + + permissions: + actions: read + checks: read + contents: write + deployments: read + issues: read + discussions: read + packages: read + pages: read + pull-requests: write + repository-projects: read + security-events: read + statuses: read + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Dependencies + uses: ./.github/actions/install-dependencies + + - name: Generate readme + run: | + pnpm --filter github-readme-stats run theme-readme-gen + + - name: Create Pull Request if themes README has changed + uses: peter-evans/create-pull-request@8 + with: + commit-message: "feat(backend): update themes README" + branch: "update_themes_readme/patch" + delete-branch: true + title: Update themes README + body: "The + [generate-theme-doc](https://github.com/stats-organization/github-stats-extended/actions/workflows/generate-theme-doc.yml) + action found new/updated languages in the [upstream languages JSON + file](https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml)." + labels: "ci" diff --git a/apps/backend/.github/workflows/update-langs.yml b/.github/workflows/update-langs.yml similarity index 63% rename from apps/backend/.github/workflows/update-langs.yml rename to .github/workflows/update-langs.yml index 262f7563..dca2cfb3 100644 --- a/apps/backend/.github/workflows/update-langs.yml +++ b/.github/workflows/update-langs.yml @@ -28,41 +28,33 @@ permissions: statuses: read jobs: - updateLanguages: - if: github.repository == 'anuraghazra/github-readme-stats' || - github.repository == 'stats-organization/github-readme-stats' + update-languages: + if: | + github.repository == 'anuraghazra/github-readme-stats' || + github.repository == 'stats-organization/github-readme-stats' || + github.repository == 'stats-organization/github-stats-extended' name: Update supported languages runs-on: ubuntu-latest - strategy: - matrix: - node-version: [22.x] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Checkout code + uses: actions/checkout@v6 - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - - name: Install dependencies - run: npm ci - env: - CI: true + - name: Install Dependencies + uses: ./.github/actions/install-dependencies - name: Run update-languages-json.js script - run: npm run generate-langs-json + run: pnpm --filter github-readme-stats run generate-langs-json - name: Create Pull Request if upstream language file is changed - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 + uses: peter-evans/create-pull-request@8 with: - commit-message: "refactor: update languages JSON" + commit-message: "feat(backend): update languages JSON" branch: "update_langs/patch" delete-branch: true title: Update languages JSON body: "The - [update-langs](https://github.com/anuraghazra/github-readme-stats/actions/workflows/update-langs.yaml) + [update-langs](https://github.com/stats-organization/github-stats-extended/actions/workflows/update-langs.yml) action found new/updated languages in the [upstream languages JSON file](https://raw.githubusercontent.com/github/linguist/master/lib/linguist/languages.yml)." - labels: "ci, lang-card" + labels: "ci" diff --git a/apps/backend/.github/workflows/deploy-prep.py b/apps/backend/.github/workflows/deploy-prep.py deleted file mode 100644 index 28cf7e8e..00000000 --- a/apps/backend/.github/workflows/deploy-prep.py +++ /dev/null @@ -1,10 +0,0 @@ -import os - -file = open('./vercel.json', 'r') -str = file.read() -file = open('./vercel.json', 'w') - -str = str.replace('"maxDuration": 10', '"maxDuration": 15') - -file.write(str) -file.close() diff --git a/apps/backend/.github/workflows/deploy-prep.yml b/apps/backend/.github/workflows/deploy-prep.yml deleted file mode 100644 index 20771fd3..00000000 --- a/apps/backend/.github/workflows/deploy-prep.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Deployment Prep -on: - workflow_dispatch: - push: - branches: - - master - -jobs: - config: - if: github.repository == 'anuraghazra/github-readme-stats' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Deployment Prep - run: python ./.github/workflows/deploy-prep.py - - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 - with: - branch: vercel - create_branch: true - push_options: "--force" diff --git a/apps/backend/.github/workflows/e2e-test.yml b/apps/backend/.github/workflows/e2e-test.yml deleted file mode 100644 index c75f2db9..00000000 --- a/apps/backend/.github/workflows/e2e-test.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Test Deployment -on: - # Temporarily disabled automatic triggers; manual-only for now. - workflow_dispatch: - # Original trigger (restore to re-enable): - # deployment_status: - -permissions: read-all - -jobs: - e2eTests: - # Temporarily disabled; set to the original condition to re-enable. - # if: - # github.repository == 'anuraghazra/github-readme-stats' && - # github.event_name == 'deployment_status' && - # github.event.deployment_status.state == 'success' - if: false - name: Perform e2e tests - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [22.x] - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - - name: Install dependencies - run: npm ci - env: - CI: true - - - name: Run end-to-end tests. - run: npm run test:e2e - # env: - # VERCEL_PREVIEW_URL: ${{ github.event.deployment_status.target_url }} diff --git a/apps/backend/.github/workflows/empty-issues-closer.yml b/apps/backend/.github/workflows/empty-issues-closer.yml deleted file mode 100644 index 3de09d82..00000000 --- a/apps/backend/.github/workflows/empty-issues-closer.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Close empty issues and templates -on: - issues: - types: - - reopened - - opened - - edited - -permissions: - actions: read - checks: read - contents: read - deployments: read - issues: write - discussions: read - packages: read - pages: read - pull-requests: read - repository-projects: read - security-events: read - statuses: read - -jobs: - closeEmptyIssuesAndTemplates: - if: github.repository == 'anuraghazra/github-readme-stats' - name: Close empty issues - runs-on: ubuntu-latest - steps: - # NOTE: Retrieve issue templates. - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Run empty issues closer action - uses: rickstaa/empty-issues-closer-action@e96914613221511279ca25f50fd4acc85e331d99 # v1.1.74 - env: - github_token: ${{ secrets.GITHUB_TOKEN }} - with: - close_comment: - Closing this issue because it appears to be empty. Please update the - issue for it to be reopened. - open_comment: Reopening this issue because the author provided more information. - check_templates: true - template_close_comment: - Closing this issue since the issue template was not filled in. - Please provide us with more information to have this issue reopened. - template_open_comment: Reopening this issue because the author provided more information. diff --git a/apps/backend/.github/workflows/generate-theme-doc.yml b/apps/backend/.github/workflows/generate-theme-doc.yml deleted file mode 100644 index baef8965..00000000 --- a/apps/backend/.github/workflows/generate-theme-doc.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Generate Theme Readme -on: - push: - branches: - - master - paths: - - "themes/index.js" - workflow_dispatch: - -permissions: - actions: read - checks: read - contents: write - deployments: read - issues: read - discussions: read - packages: read - pages: read - pull-requests: read - repository-projects: read - security-events: read - statuses: read - -jobs: - generateThemeDoc: - runs-on: ubuntu-latest - name: Generate theme doc - strategy: - matrix: - node-version: [22.x] - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - # Fix the unsafe repo error which was introduced by the CVE-2022-24765 git patches. - - name: Fix unsafe repo error - run: git config --global --add safe.directory ${{ github.workspace }} - - - name: npm install, generate readme - run: | - npm ci - npm run theme-readme-gen - env: - CI: true - - - name: Run Script - uses: skx/github-action-tester@e29768ff4ff67be9d1fdbccd8836ab83233bebb1 # v0.10.0 - with: - script: ./scripts/push-theme-readme.sh - env: - CI: true - PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }} - GH_REPO: ${{ secrets.GH_REPO }} diff --git a/apps/backend/.github/workflows/label-pr.yml b/apps/backend/.github/workflows/label-pr.yml deleted file mode 100644 index b774b145..00000000 --- a/apps/backend/.github/workflows/label-pr.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: "Pull Request Labeler" -on: - - pull_request_target - -permissions: - actions: read - checks: read - contents: read - deployments: read - issues: read - discussions: read - packages: read - pages: read - pull-requests: write - repository-projects: read - security-events: read - statuses: read - -jobs: - triage: - if: github.repository == 'anuraghazra/github-readme-stats' - runs-on: ubuntu-latest - steps: - - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - sync-labels: true diff --git a/apps/backend/.github/workflows/ossf-analysis.yml b/apps/backend/.github/workflows/ossf-analysis.yml deleted file mode 100644 index 9b53f4bc..00000000 --- a/apps/backend/.github/workflows/ossf-analysis.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: OSSF Scorecard analysis workflow -on: - push: - branches: - - master - pull_request: - branches: - - master - -permissions: read-all - -jobs: - analysis: - if: github.repository == 'anuraghazra/github-readme-stats' - name: Scorecard analysis - runs-on: ubuntu-latest - permissions: - # Needed if using Code scanning alerts - security-events: write - # Needed for GitHub OIDC token if publish_results is true - id-token: write - - steps: - - name: "Checkout code" - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: "Run analysis" - uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 - with: - results_file: results.sarif - results_format: sarif - publish_results: true - - # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF - # format to the repository Actions tab. - - name: "Upload artifact" - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: SARIF file - path: results.sarif - retention-days: 5 - - # required for Code scanning alerts - - name: "Upload SARIF results to code scanning" - uses: github/codeql-action/upload-sarif@fdcae64e1484d349b3366718cdfef3d404390e85 # v2.22.1 - with: - sarif_file: results.sarif diff --git a/apps/backend/.github/workflows/preview-theme.yml b/apps/backend/.github/workflows/preview-theme.yml deleted file mode 100644 index 1d0e8063..00000000 --- a/apps/backend/.github/workflows/preview-theme.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Theme preview -on: - # Temporary disabled due to paused themes addition. - # See: https://github.com/anuraghazra/github-readme-stats/issues/3404 - # pull_request_target: - # types: [opened, edited, reopened, synchronize] - # branches: - # - master - # paths: - # - "themes/index.js" - workflow_dispatch: - -permissions: - actions: read - checks: read - contents: read - deployments: read - issues: read - discussions: read - packages: read - pages: read - pull-requests: write - repository-projects: read - security-events: read - statuses: read - -jobs: - previewTheme: - name: Install & Preview - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [22.x] - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - - uses: bahmutov/npm-install@3e063b974f0d209807684aa23e534b3dde517fd9 # v1.11.2 - with: - useLockFile: false - - - run: npm run preview-theme - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/apps/backend/.github/workflows/prs-cache-clean.yml b/apps/backend/.github/workflows/prs-cache-clean.yml deleted file mode 100644 index 89393b4b..00000000 --- a/apps/backend/.github/workflows/prs-cache-clean.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Cleanup closed pull requests cache -on: - pull_request: - types: - - closed - -permissions: - actions: write - checks: read - contents: read - deployments: read - issues: read - discussions: read - packages: read - pages: read - pull-requests: read - repository-projects: read - security-events: read - statuses: read - -jobs: - cleanup: - runs-on: ubuntu-latest - steps: - - name: Cleanup - run: | - gh extension install actions/gh-actions-cache - - REPO=${{ github.repository }} - BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge" - - echo "Fetching list of cache key" - cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) - - ## Setting this to not fail the workflow while deleting cache keys. - set +e - echo "Deleting caches..." - for cacheKey in $cacheKeysForPR - do - gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm - done - echo "Done" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/apps/backend/.github/workflows/stale-theme-pr-closer.yml b/apps/backend/.github/workflows/stale-theme-pr-closer.yml deleted file mode 100644 index ace72a55..00000000 --- a/apps/backend/.github/workflows/stale-theme-pr-closer.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Close stale theme pull requests that have the 'invalid' label. -on: - # Temporary disabled due to paused themes addition. - # See: https://github.com/anuraghazra/github-readme-stats/issues/3404 - # schedule: - # # ┌───────────── minute (0 - 59) - # # │ ┌───────────── hour (0 - 23) - # # │ │ ┌───────────── day of the month (1 - 31) - # # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) - # # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) - # # │ │ │ │ │ - # # │ │ │ │ │ - # # │ │ │ │ │ - # # * * * * * - # - cron: "0 0 */7 * *" - workflow_dispatch: - -permissions: - actions: read - checks: read - contents: read - deployments: read - issues: read - discussions: read - packages: read - pages: read - pull-requests: write - repository-projects: read - security-events: read - statuses: read - -jobs: - closeOldThemePrs: - if: github.repository == 'anuraghazra/github-readme-stats' - name: Close stale 'invalid' theme PRs - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [22.x] - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - - uses: bahmutov/npm-install@3e063b974f0d209807684aa23e534b3dde517fd9 # v1.11.2 - with: - useLockFile: false - - - run: npm run close-stale-theme-prs - env: - STALE_DAYS: 20 - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/apps/backend/.github/workflows/test.yml b/apps/backend/.github/workflows/test.yml deleted file mode 100644 index 390aefb4..00000000 --- a/apps/backend/.github/workflows/test.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Test -on: - workflow_dispatch: - push: - branches: - - master - pull_request: - branches: - - master - -permissions: read-all - -jobs: - build: - name: Perform tests - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [22.x] - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - - name: Install & Test - run: | - npm ci - npm run test - - - name: Run ESLint - run: | - npm run lint - - - name: Run bench tests - run: | - npm run bench - - - name: Run Prettier - run: | - npm run format:check - - - name: Code Coverage - uses: codecov/codecov-action@4fe8c5f003fae66aa5ebb77cfd3e7bfbbda0b6b0 # v3.1.5 diff --git a/apps/backend/.github/workflows/theme-prs-closer.yml b/apps/backend/.github/workflows/theme-prs-closer.yml deleted file mode 100644 index b71a1c18..00000000 --- a/apps/backend/.github/workflows/theme-prs-closer.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Theme Pull Requests Closer - -on: - - pull_request_target - -permissions: - actions: read - checks: read - contents: read - deployments: read - issues: read - discussions: read - packages: read - pages: read - pull-requests: write - repository-projects: read - security-events: read - statuses: read - -jobs: - close-prs: - if: github.repository == 'anuraghazra/github-readme-stats' - runs-on: ubuntu-latest - steps: - - name: Check out the code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Set up Git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Close Pull Requests - run: | - comment_message="We are currently pausing addition of new themes. If this theme is exclusively for your personal use, then instead of adding it to our theme collection, you can use card [customization options](https://github.com/anuraghazra/github-readme-stats?tab=readme-ov-file#customization)." - - for pr_number in $(gh pr list -l "themes" -q is:open --json number -q ".[].number"); do - gh pr close $pr_number -c "$comment_message" - done - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/apps/backend/.github/workflows/top-issues-dashboard.yml b/apps/backend/.github/workflows/top-issues-dashboard.yml deleted file mode 100644 index e4ebadb9..00000000 --- a/apps/backend/.github/workflows/top-issues-dashboard.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Update top issues dashboard -on: - schedule: - # ┌───────────── minute (0 - 59) - # │ ┌───────────── hour (0 - 23) - # │ │ ┌───────────── day of the month (1 - 31) - # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) - # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) - # │ │ │ │ │ - # │ │ │ │ │ - # │ │ │ │ │ - # * * * * * - - cron: "0 0 */3 * *" - workflow_dispatch: - -permissions: - actions: read - checks: read - contents: read - deployments: read - issues: write - discussions: read - packages: read - pages: read - pull-requests: write - repository-projects: read - security-events: read - statuses: read - -jobs: - showAndLabelTopIssues: - if: github.repository == 'anuraghazra/github-readme-stats' - name: Update top issues Dashboard. - runs-on: ubuntu-latest - steps: - - name: Run top issues action - uses: rickstaa/top-issues-action@7e8dda5d5ae3087670f9094b9724a9a091fc3ba1 # v1.3.101 - env: - github_token: ${{ secrets.GITHUB_TOKEN }} - with: - top_list_size: 10 - filter: "1772" - label: true - dashboard: true - dashboard_show_total_reactions: true - top_issues: true - top_bugs: true - top_features: true - top_pull_requests: true diff --git a/apps/backend/package.json b/apps/backend/package.json index aac0359a..ecfa8e49 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -24,8 +24,6 @@ "test:update:snapshot": "node --experimental-vm-modules node_modules/jest/bin/jest.js -u", "test:e2e": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.e2e.config.js", "theme-readme-gen": "node scripts/generate-theme-doc", - "preview-theme": "node scripts/preview-theme", - "close-stale-theme-prs": "node scripts/close-stale-theme-prs", "generate-langs-json": "node scripts/generate-langs-json", "lint": "npx eslint --max-warnings 0 \"./src/**/*.js\" \"./scripts/**/*.js\" \"./tests/**/*.js\" \"./api-renamed/**/*.js\" \"./themes/**/*.js\"", "bench": "node --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.bench.config.js" @@ -33,21 +31,15 @@ "author": "Anurag Hazra", "license": "MIT", "devDependencies": { - "@actions/core": "^3.0.0", - "@actions/github": "^9.0.0", "@jest/globals": "30.2.0", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@uppercod/css-to-object": "^1.1.1", "axios-mock-adapter": "^2.1.0", - "color-contrast-checker": "^2.1.0", "express": "^5.2.1", - "hjson": "^3.2.2", "jest": "^30.2.0", "jest-environment-jsdom": "^30.2.0", - "js-yaml": "^4.1.1", - "lodash.snakecase": "^4.1.1", - "parse-diff": "^0.11.1" + "js-yaml": "^4.1.1" }, "dependencies": { "axios": "^1.13.4", diff --git a/apps/backend/scripts/close-stale-theme-prs.js b/apps/backend/scripts/close-stale-theme-prs.js deleted file mode 100644 index 26b374f4..00000000 --- a/apps/backend/scripts/close-stale-theme-prs.js +++ /dev/null @@ -1,182 +0,0 @@ -/** - * @file Script that can be used to close stale theme PRs that have a `invalid` label. - */ -import { debug, setFailed } from "@actions/core"; -import * as github from "@actions/github"; -// eslint-disable-next-line import-x/no-unresolved -import { RequestError } from "@octokit/request-error"; -import * as dotenv from "dotenv"; - -import { getGithubToken, getRepoInfo } from "./helpers.js"; - -dotenv.config(); - -const CLOSING_COMMENT = ` - \rThis theme PR has been automatically closed due to inactivity. Please reopen it if you want to continue working on it.\ - \rThank you for your contributions. -`; -const REVIEWER = "github-actions[bot]"; - -/** - * Retrieve the review user. - * @returns {string} review user. - */ -const getReviewer = () => { - return process.env.REVIEWER ? process.env.REVIEWER : REVIEWER; -}; - -/** - * Fetch open PRs from a given repository. - * - * @param {module:@actions/github.Octokit} octokit The octokit client. - * @param {string} user The user name of the repository owner. - * @param {string} repo The name of the repository. - * @param {string} reviewer The reviewer to filter by. - * @returns {Promise} The open PRs. - */ -export const fetchOpenPRs = async (octokit, user, repo, reviewer) => { - const openPRs = []; - let hasNextPage = true; - let endCursor; - while (hasNextPage) { - try { - const { repository } = await octokit.graphql( - ` - { - repository(owner: "${user}", name: "${repo}") { - open_prs: pullRequests(${ - endCursor ? `after: "${endCursor}", ` : "" - } - first: 100, states: OPEN, orderBy: {field: CREATED_AT, direction: DESC}) { - nodes { - number - commits(last:1){ - nodes{ - commit{ - pushedDate - } - } - } - labels(first: 100, orderBy:{field: CREATED_AT, direction: DESC}) { - nodes { - name - } - } - reviews(first: 100, states: CHANGES_REQUESTED, author: "${reviewer}") { - nodes { - submittedAt - } - } - } - pageInfo { - endCursor - hasNextPage - } - } - } - } - `, - ); - openPRs.push(...repository.open_prs.nodes); - hasNextPage = repository.open_prs.pageInfo.hasNextPage; - endCursor = repository.open_prs.pageInfo.endCursor; - } catch (error) { - if (error instanceof RequestError) { - setFailed(`Could not retrieve top PRs using GraphQl: ${error.message}`); - } - throw error; - } - } - return openPRs; -}; - -/** - * Retrieve pull requests that have a given label. - * - * @param {Object[]} pulls The pull requests to check. - * @param {string} label The label to check for. - * @returns {Object[]} The pull requests that have the given label. - */ -export const pullsWithLabel = (pulls, label) => { - return pulls.filter((pr) => { - return pr.labels.nodes.some((lab) => lab.name === label); - }); -}; - -/** - * Check if PR is stale. Meaning that it hasn't been updated in a given time. - * - * @param {Object} pullRequest request object. - * @param {number} staleDays number of days. - * @returns {boolean} indicating if PR is stale. - */ -const isStale = (pullRequest, staleDays) => { - const lastCommitDate = new Date( - pullRequest.commits.nodes[0].commit.pushedDate, - ); - if (pullRequest.reviews.nodes[0]) { - const lastReviewDate = new Date( - pullRequest.reviews.nodes.sort((a, b) => (a < b ? 1 : -1))[0].submittedAt, - ); - const lastUpdateDate = - lastCommitDate >= lastReviewDate ? lastCommitDate : lastReviewDate; - const now = new Date(); - return (now - lastUpdateDate) / (1000 * 60 * 60 * 24) >= staleDays; - } else { - return false; - } -}; - -/** - * Main function. - * - * @returns {Promise} A promise. - */ -const run = async () => { - try { - // Create octokit client. - const dryRun = process.env.DRY_RUN === "true" || false; - const staleDays = process.env.STALE_DAYS || 20; - debug("Creating octokit client..."); - const octokit = github.getOctokit(getGithubToken()); - const { owner, repo } = getRepoInfo(github.context); - const reviewer = getReviewer(); - - // Retrieve all theme pull requests. - debug("Retrieving all theme pull requests..."); - const prs = await fetchOpenPRs(octokit, owner, repo, reviewer); - const themePRs = pullsWithLabel(prs, "themes"); - const invalidThemePRs = pullsWithLabel(themePRs, "invalid"); - debug("Retrieving stale theme PRs..."); - const staleThemePRs = invalidThemePRs.filter((pr) => - isStale(pr, staleDays), - ); - const staleThemePRsNumbers = staleThemePRs.map((pr) => pr.number); - debug(`Found ${staleThemePRs.length} stale theme PRs`); - - // Loop through all stale invalid theme pull requests and close them. - for (const prNumber of staleThemePRsNumbers) { - debug(`Closing #${prNumber} because it is stale...`); - if (dryRun) { - debug("Dry run enabled, skipping..."); - } else { - await octokit.rest.issues.createComment({ - owner, - repo, - issue_number: prNumber, - body: CLOSING_COMMENT, - }); - await octokit.rest.pulls.update({ - owner, - repo, - pull_number: prNumber, - state: "closed", - }); - } - } - } catch (error) { - setFailed(error.message); - } -}; - -run(); diff --git a/apps/backend/scripts/helpers.js b/apps/backend/scripts/helpers.js deleted file mode 100644 index f73011f0..00000000 --- a/apps/backend/scripts/helpers.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file Contains helper functions used in the scripts. - */ - -import { getInput } from "@actions/core"; - -const OWNER = "anuraghazra"; -const REPO = "github-readme-stats"; - -/** - * Retrieve information about the repository that ran the action. - * - * @param {Object} ctx Action context. - * @returns {Object} Repository information. - */ -export const getRepoInfo = (ctx) => { - try { - return { - owner: ctx.repo.owner, - repo: ctx.repo.repo, - }; - } catch (error) { - // Resolve eslint no-unused-vars - error; - - return { - owner: OWNER, - repo: REPO, - }; - } -}; - -/** - * Retrieve github token and throw error if it is not found. - * - * @returns {string} GitHub token. - */ -export const getGithubToken = () => { - const token = getInput("github_token") || process.env.GITHUB_TOKEN; - if (!token) { - throw Error("Could not find github token"); - } - return token; -}; diff --git a/apps/backend/scripts/preview-theme.js b/apps/backend/scripts/preview-theme.js deleted file mode 100644 index f4d71567..00000000 --- a/apps/backend/scripts/preview-theme.js +++ /dev/null @@ -1,690 +0,0 @@ -/** - * @file This script is used to preview the theme on theme PRs. - */ -import { info } from "console"; -import { inspect } from "util"; - -import { debug, setFailed } from "@actions/core"; -import { default as github } from "@actions/github"; -import ColorContrastChecker from "color-contrast-checker"; -import * as dotenv from "dotenv"; -import Hjson from "hjson"; -import snakeCase from "lodash.snakecase"; -import parse from "parse-diff"; - -import { isValidGradient, isValidHexColor } from "../src/common/color.js"; -import { themes } from "../themes/index.js"; - -import { getGithubToken, getRepoInfo } from "./helpers.js"; - -dotenv.config(); - -const COMMENTER = "github-actions[bot]"; - -const COMMENT_TITLE = "Automated Theme Preview"; -const THEME_PR_FAIL_TEXT = ":x: Theme PR does not adhere to our guidelines."; -const THEME_PR_SUCCESS_TEXT = - ":heavy_check_mark: Theme PR does adhere to our guidelines."; -const FAIL_TEXT = ` - \rUnfortunately, your theme PR contains an error or does not adhere to our [theme guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution). Please fix the issues below, and we will review your\ - \r PR again. This pull request will **automatically close in 20 days** if no changes are made. After this time, you must re-open the PR for it to be reviewed. -`; -const THEME_CONTRIB_GUIDELINES = ` - \rHi, thanks for the theme contribution. Please read our theme [contribution guidelines](https://github.com/anuraghazra/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution). - - \r> [!WARNING]\ - \r> Keep in mind that we already have a vast collection of different themes. To keep their number manageable, we began to add only themes supported by the community. Your pull request with theme addition will be merged once we get enough positive feedback from the community in the form of thumbs up :+1: emojis (see [#1935](https://github.com/anuraghazra/github-readme-stats/issues/1935#top-themes-prs)). We expect to see at least 10-15 thumbs up before making a decision to merge your pull request into the master branch. Remember that you can also support themes of other contributors that you liked to speed up their merge. - - \r> [!WARNING]\ - \r> Please do not submit a pull request with a batch of themes, since it will be hard to judge how the community will react to each of them. We will only merge one theme per pull request. If you have several themes, please submit a separate pull request for each of them. Situations when you have several versions of the same theme (e.g. light and dark) are an exception to this rule. - - \r> [!NOTE]\ - \r> Also, note that if this theme is exclusively for your personal use, then instead of adding it to our theme collection, you can use card [customization options](https://github.com/anuraghazra/github-readme-stats#customization). -`; -const COLOR_PROPS = { - title_color: 6, - icon_color: 6, - text_color: 6, - bg_color: 23, - border_color: 6, -}; -const ACCEPTED_COLOR_PROPS = Object.keys(COLOR_PROPS); -const REQUIRED_COLOR_PROPS = ACCEPTED_COLOR_PROPS.slice(0, 4); -const INVALID_REVIEW_COMMENT = (commentUrl) => - `Some themes are invalid. See the [Automated Theme Preview](${commentUrl}) comment above for more information.`; -var OCTOKIT; -var OWNER; -var REPO; -var PULL_REQUEST_ID; - -/** - * Incorrect JSON format error. - * @extends Error - * @param {string} message Error message. - * @returns {Error} IncorrectJsonFormatError. - */ -class IncorrectJsonFormatError extends Error { - /** - * Constructor. - * - * @param {string} message Error message. - */ - constructor(message) { - super(message); - this.name = "IncorrectJsonFormatError"; - } -} - -/** - * Retrieve PR number from the event payload. - * - * @returns {number} PR number. - */ -const getPrNumber = () => { - if (process.env.MOCK_PR_NUMBER) { - return process.env.MOCK_PR_NUMBER; // For testing purposes. - } - - const pullRequest = github.context.payload.pull_request; - if (!pullRequest) { - throw Error("Could not get pull request number from context"); - } - return pullRequest.number; -}; - -/** - * Retrieve the commenting user. - * @returns {string} Commenting user. - */ -const getCommenter = () => { - return process.env.COMMENTER ? process.env.COMMENTER : COMMENTER; -}; - -/** - * Returns whether the comment is a preview comment. - * - * @param {Object} inputs Action inputs. - * @param {Object} comment Comment object. - * @returns {boolean} Whether the comment is a preview comment. - */ -const isPreviewComment = (inputs, comment) => { - return ( - (inputs.commentAuthor && comment.user - ? comment.user.login === inputs.commentAuthor - : true) && - (inputs.bodyIncludes && comment.body - ? comment.body.includes(inputs.bodyIncludes) - : true) - ); -}; - -/** - * Find the preview theme comment. - * - * @param {Object} octokit Octokit instance. - * @param {number} issueNumber Issue number. - * @param {string} owner Owner of the repository. - * @param {string} repo Repository name. - * @param {string} commenter Comment author. - * @returns {Object | undefined} The GitHub comment object. - */ -const findComment = async (octokit, issueNumber, owner, repo, commenter) => { - const parameters = { - owner, - repo, - issue_number: issueNumber, - }; - const inputs = { - commentAuthor: commenter, - bodyIncludes: COMMENT_TITLE, - }; - - // Search each page for the comment - for await (const { data: comments } of octokit.paginate.iterator( - octokit.rest.issues.listComments, - parameters, - )) { - const comment = comments.find((comment) => - isPreviewComment(inputs, comment), - ); - if (comment) { - debug(`Found theme preview comment: ${inspect(comment)}`); - return comment; - } else { - debug(`No theme preview comment found.`); - } - } - - return undefined; -}; - -/** - * Create or update the preview comment. - * - * @param {Object} octokit Octokit instance. - * @param {number} issueNumber Issue number. - * @param {Object} repo Repository name. - * @param {Object} owner Owner of the repository. - * @param {number} commentId Comment ID. - * @param {string} body Comment body. - * @returns {string} The comment URL. - */ -const upsertComment = async ( - octokit, - issueNumber, - repo, - owner, - commentId, - body, -) => { - let resp; - if (commentId === undefined) { - resp = await octokit.rest.issues.createComment({ - owner, - repo, - issue_number: issueNumber, - body, - }); - } else { - resp = await octokit.rest.issues.updateComment({ - owner, - repo, - comment_id: commentId, - body, - }); - } - return resp.data.html_url; -}; - -/** - * Adds a review to the pull request. - * - * @param {Object} octokit Octokit instance. - * @param {number} prNumber Pull request number. - * @param {string} owner Owner of the repository. - * @param {string} repo Repository name. - * @param {string} reviewState The review state. Options are (APPROVE, REQUEST_CHANGES, COMMENT, PENDING). - * @param {string} reason The reason for the review. - * @returns {Promise} Promise. - */ -const addReview = async ( - octokit, - prNumber, - owner, - repo, - reviewState, - reason, -) => { - await octokit.rest.pulls.createReview({ - owner, - repo, - pull_number: prNumber, - event: reviewState, - body: reason, - }); -}; - -/** - * Add label to pull request. - * - * @param {Object} octokit Octokit instance. - * @param {number} prNumber Pull request number. - * @param {string} owner Repository owner. - * @param {string} repo Repository name. - * @param {string[]} labels Labels to add. - * @returns {Promise} Promise. - */ -const addLabel = async (octokit, prNumber, owner, repo, labels) => { - await octokit.rest.issues.addLabels({ - owner, - repo, - issue_number: prNumber, - labels, - }); -}; - -/** - * Remove label from the pull request. - * - * @param {Object} octokit Octokit instance. - * @param {number} prNumber Pull request number. - * @param {string} owner Repository owner. - * @param {string} repo Repository name. - * @param {string} label Label to add or remove. - * @returns {Promise} Promise. - */ -const removeLabel = async (octokit, prNumber, owner, repo, label) => { - await octokit.rest.issues.removeLabel({ - owner, - repo, - issue_number: prNumber, - name: label, - }); -}; - -/** - * Adds or removes a label from the pull request. - * - * @param {Object} octokit Octokit instance. - * @param {number} prNumber Pull request number. - * @param {string} owner Repository owner. - * @param {string} repo Repository name. - * @param {string} label Label to add or remove. - * @param {boolean} add Whether to add or remove the label. - * @returns {Promise} Promise. - */ -const addRemoveLabel = async (octokit, prNumber, owner, repo, label, add) => { - const res = await octokit.rest.pulls.get({ - owner, - repo, - pull_number: prNumber, - }); - if (add) { - if (!res.data.labels.find((l) => l.name === label)) { - await addLabel(octokit, prNumber, owner, repo, [label]); - } - } else { - if (res.data.labels.find((l) => l.name === label)) { - await removeLabel(octokit, prNumber, owner, repo, label); - } - } -}; - -/** - * Retrieve webAim contrast color check link. - * - * @param {string} color1 First color. - * @param {string} color2 Second color. - * @returns {string} WebAim contrast color check link. - */ -const getWebAimLink = (color1, color2) => { - return `https://webaim.org/resources/contrastchecker/?fcolor=${color1}&bcolor=${color2}`; -}; - -/** - * Retrieves the theme GRS url. - * - * @param {Object} colors The theme colors. - * @returns {string} GRS theme url. - */ -const getGRSLink = (colors) => { - const url = `https://github-stats-extended.vercel.app/api?username=anuraghazra`; - const colorString = Object.keys(colors) - .map((colorKey) => `${colorKey}=${colors[colorKey]}`) - .join("&"); - - return `${url}&${colorString}&show_icons=true`; -}; - -/** - * Retrieve javascript object from json string. - * - * @description Wraps the Hjson parse function to fix several known json syntax errors. - * - * @param {string} json The json to parse. - * @returns {Object} Object parsed from the json. - */ -const parseJSON = (json) => { - try { - const parsedJson = Hjson.parse(json); - if (typeof parsedJson === "object") { - return parsedJson; - } else { - throw new IncorrectJsonFormatError( - "PR diff is not a valid theme JSON object.", - ); - } - } catch (error) { - // Resolve eslint no-unused-vars - error; - - // Remove trailing commas (if any). - let parsedJson = json.replace(/(,\s*})/g, "}"); - - // Remove JS comments (if any). - parsedJson = parsedJson.replace(/\/\/[A-z\s]*\s/g, ""); - - // Fix incorrect open bracket (if any). - const splitJson = parsedJson - .split(/([\s\r\s]*}[\s\r\s]*,[\s\r\s]*)(?=[\w"-]+:)/) - .filter((x) => typeof x !== "string" || !!x.trim()); // Split json into array of strings and objects. - if (splitJson[0].replace(/\s+/g, "") === "},") { - splitJson[0] = "},"; - if (/\s*}\s*,?\s*$/.test(splitJson[1])) { - splitJson.shift(); - } else { - splitJson.push(splitJson.shift()); - } - parsedJson = splitJson.join(""); - } - - // Try to parse the fixed json. - try { - return Hjson.parse(parsedJson); - } catch (error) { - throw new IncorrectJsonFormatError( - `Theme JSON file could not be parsed: ${error.message}`, - ); - } - } -}; - -/** - * Check whether the theme name is still available. - * @param {string} name Theme name. - * @returns {boolean} Whether the theme name is available. - */ -const themeNameAlreadyExists = (name) => { - return themes[name] !== undefined; -}; - -const DRY_RUN = process.env.DRY_RUN === "true" || false; - -/** - * Main function. - * - * @returns {Promise} Promise. - */ -export const run = async () => { - try { - debug("Retrieve action information from context..."); - debug(`Context: ${inspect(github.context)}`); - let commentBody = ` - \r# ${COMMENT_TITLE} - \r${THEME_CONTRIB_GUIDELINES} - `; - const ccc = new ColorContrastChecker(); - OCTOKIT = github.getOctokit(getGithubToken()); - PULL_REQUEST_ID = getPrNumber(); - const { owner, repo } = getRepoInfo(github.context); - OWNER = owner; - REPO = repo; - const commenter = getCommenter(); - PULL_REQUEST_ID = getPrNumber(); - debug(`Owner: ${OWNER}`); - debug(`Repo: ${REPO}`); - debug(`Commenter: ${commenter}`); - - // Retrieve the PR diff and preview-theme comment. - debug("Retrieve PR diff..."); - const res = await OCTOKIT.rest.pulls.get({ - owner: OWNER, - repo: REPO, - pull_number: PULL_REQUEST_ID, - mediaType: { - format: "diff", - }, - }); - debug("Retrieve preview-theme comment..."); - const comment = await findComment( - OCTOKIT, - PULL_REQUEST_ID, - OWNER, - REPO, - commenter, - ); - - // Retrieve theme changes from the PR diff. - debug("Retrieve themes..."); - const diff = parse(res.data); - - // Retrieve all theme changes from the PR diff and convert to JSON. - debug("Retrieve theme changes..."); - const content = diff - .find((file) => file.to === "themes/index.js") - .chunks.map((chunk) => - chunk.changes - .filter((c) => c.type === "add") - .map((c) => c.content.replace("+", "")) - .join(""), - ) - .join(""); - const themeObject = parseJSON(content); - if ( - Object.keys(themeObject).every( - (key) => typeof themeObject[key] !== "object", - ) - ) { - throw new Error("PR diff is not a valid theme JSON object."); - } - - // Loop through themes and create theme preview body. - debug("Create theme preview body..."); - const themeValid = Object.fromEntries( - Object.keys(themeObject).map((name) => [name, true]), - ); - let previewBody = ""; - for (const theme in themeObject) { - debug(`Create theme preview for ${theme}...`); - const themeName = theme; - const colors = themeObject[theme]; - const warnings = []; - const errors = []; - - // Check if the theme name is valid. - debug("Theme preview body: Check if the theme name is valid..."); - if (themeNameAlreadyExists(themeName)) { - warnings.push("Theme name already taken"); - themeValid[theme] = false; - } - if (themeName !== snakeCase(themeName)) { - warnings.push("Theme name isn't in snake_case"); - themeValid[theme] = false; - } - - // Check if the theme colors are valid. - debug("Theme preview body: Check if the theme colors are valid..."); - let invalidColors = false; - if (colors) { - const missingKeys = REQUIRED_COLOR_PROPS.filter( - (x) => !Object.keys(colors).includes(x), - ); - const extraKeys = Object.keys(colors).filter( - (x) => !ACCEPTED_COLOR_PROPS.includes(x), - ); - if (missingKeys.length > 0 || extraKeys.length > 0) { - for (const missingKey of missingKeys) { - errors.push(`Theme color properties \`${missingKey}\` are missing`); - } - - for (const extraKey of extraKeys) { - warnings.push( - `Theme color properties \`${extraKey}\` is not supported`, - ); - } - invalidColors = true; - } else { - for (const [colorKey, colorValue] of Object.entries(colors)) { - if (colorValue[0] === "#") { - errors.push( - `Theme color property \`${colorKey}\` should not start with '#'`, - ); - invalidColors = true; - } else if (colorValue.length > COLOR_PROPS[colorKey]) { - errors.push( - `Theme color property \`${colorKey}\` can not be longer than \`${COLOR_PROPS[colorKey]}\` characters`, - ); - invalidColors = true; - } else if ( - !(colorKey === "bg_color" && colorValue.split(",").length > 1 - ? isValidGradient(colorValue.split(",")) - : isValidHexColor(colorValue)) - ) { - errors.push( - `Theme color property \`${colorKey}\` is not a valid hex color: ${colorValue}`, - ); - invalidColors = true; - } - } - } - } else { - warnings.push("Theme colors are missing"); - invalidColors = true; - } - if (invalidColors) { - themeValid[theme] = false; - previewBody += ` - \r### ${ - themeName.charAt(0).toUpperCase() + themeName.slice(1) - } theme preview - - \r${warnings.map((warning) => `- :warning: ${warning}.\n`).join("")} - \r${errors.map((error) => `- :x: ${error}.\n`).join("")} - - \r>:x: Cannot create theme preview. - `; - continue; - } - - // Check color contrast. - debug("Theme preview body: Check color contrast..."); - const titleColor = colors.title_color; - const iconColor = colors.icon_color; - const textColor = colors.text_color; - const bgColor = colors.bg_color; - const borderColor = colors.border_color; - const url = getGRSLink(colors); - const colorPairs = { - title_color: [titleColor, bgColor], - icon_color: [iconColor, bgColor], - text_color: [textColor, bgColor], - }; - Object.keys(colorPairs).forEach((item) => { - let color1 = colorPairs[item][0]; - let color2 = colorPairs[item][1]; - const isGradientColor = color2.split(",").length > 1; - if (isGradientColor) { - return; - } - color1 = color1.length === 4 ? color1.slice(0, 3) : color1.slice(0, 6); - color2 = color2.length === 4 ? color2.slice(0, 3) : color2.slice(0, 6); - if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) { - const permalink = getWebAimLink(color1, color2); - warnings.push( - `\`${item}\` does not pass [AA contrast ratio](${permalink})`, - ); - themeValid[theme] = false; - } - }); - - // Create theme preview body. - debug("Theme preview body: Create theme preview body..."); - previewBody += ` - \r### ${ - themeName.charAt(0).toUpperCase() + themeName.slice(1) - } theme preview - - \r${warnings.map((warning) => `- :warning: ${warning}.\n`).join("")} - - \ntitle_color: #${titleColor} | icon_color: #${iconColor} | text_color: #${textColor} | bg_color: #${bgColor}${ - borderColor ? ` | border_color: #${borderColor}` : "" - } - - \r[Preview Link](${url}) - - \r[![](${url})](${url}) - `; - } - - // Create comment body. - debug("Create comment body..."); - commentBody += ` - \r${ - Object.values(themeValid).every((value) => value) - ? THEME_PR_SUCCESS_TEXT - : THEME_PR_FAIL_TEXT - } - \r## Test results - \r${Object.entries(themeValid) - .map( - ([key, value]) => `- ${value ? ":heavy_check_mark:" : ":x:"} ${key}`, - ) - .join("\r")} - - \r${ - Object.values(themeValid).every((value) => value) - ? "**Result:** :heavy_check_mark: All themes are valid." - : "**Result:** :x: Some themes are invalid.\n\n" + FAIL_TEXT - } - - \r## Details - \r${previewBody} - `; - - // Create or update theme-preview comment. - debug("Create or update theme-preview comment..."); - let comment_url; - if (DRY_RUN) { - info(`DRY_RUN: Comment body: ${commentBody}`); - comment_url = ""; - } else { - comment_url = await upsertComment( - OCTOKIT, - PULL_REQUEST_ID, - REPO, - OWNER, - comment?.id, - commentBody, - ); - } - - // Change review state and add/remove `invalid` label based on theme PR validity. - debug( - "Change review state and add/remove `invalid` label based on whether all themes passed...", - ); - const themesValid = Object.values(themeValid).every((value) => value); - const reviewState = themesValid ? "APPROVE" : "REQUEST_CHANGES"; - const reviewReason = themesValid - ? undefined - : INVALID_REVIEW_COMMENT(comment_url); - if (DRY_RUN) { - info(`DRY_RUN: Review state: ${reviewState}`); - info(`DRY_RUN: Review reason: ${reviewReason}`); - } else { - await addReview( - OCTOKIT, - PULL_REQUEST_ID, - OWNER, - REPO, - reviewState, - reviewReason, - ); - await addRemoveLabel( - OCTOKIT, - PULL_REQUEST_ID, - OWNER, - REPO, - "invalid", - !themesValid, - ); - } - } catch (error) { - debug("Set review state to `REQUEST_CHANGES` and add `invalid` label..."); - if (DRY_RUN) { - info(`DRY_RUN: Review state: REQUEST_CHANGES`); - info(`DRY_RUN: Review reason: ${error.message}`); - } else { - await addReview( - OCTOKIT, - PULL_REQUEST_ID, - OWNER, - REPO, - "REQUEST_CHANGES", - "**Something went wrong in the theme preview action:** `" + - error.message + - "`", - ); - await addRemoveLabel( - OCTOKIT, - PULL_REQUEST_ID, - OWNER, - REPO, - "invalid", - true, - ); - } - setFailed(error.message); - } -}; - -run(); diff --git a/apps/backend/scripts/push-theme-readme.sh b/apps/backend/scripts/push-theme-readme.sh deleted file mode 100644 index d983d54a..00000000 --- a/apps/backend/scripts/push-theme-readme.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -x -set -e - -export BRANCH_NAME=updated-theme-readme -git --version -git config --global user.email "no-reply@githubreadmestats.com" -git config --global user.name "GitHub Readme Stats Bot" -git config --global --add safe.directory ${GITHUB_WORKSPACE} -git branch -d $BRANCH_NAME || true -git checkout -b $BRANCH_NAME -git add --all -git commit --no-verify --message "docs(theme): auto update theme readme" -git remote add origin-$BRANCH_NAME https://${PERSONAL_TOKEN}@github.com/${GH_REPO}.git -git push --force --quiet --set-upstream origin-$BRANCH_NAME $BRANCH_NAME diff --git a/apps/backend/src/common/color.js b/apps/backend/src/common/color.js index 4b26dc80..fbbf0423 100644 --- a/apps/backend/src/common/color.js +++ b/apps/backend/src/common/color.js @@ -142,4 +142,4 @@ const getCardColors = ({ return { titleColor, iconColor, textColor, bgColor, borderColor, ringColor }; }; -export { isValidHexColor, isValidGradient, getCardColors }; +export { getCardColors }; diff --git a/knip.jsonc b/knip.jsonc index b1b0c6a1..85bbcccb 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -13,8 +13,7 @@ "_dot_vercel_copy/**/*" // Hopefully by using a npm package this file will be removed ], "ignoreDependencies": [ - "jest", // used by test scripts referencing binary due to lack of ESM support - "@octokit/request-error" // used by js scripts executed in a GitHub actions not listed in deps + "jest" // used by test scripts referencing binary due to lack of ESM support ] }, "apps/frontend": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6f0727f..5c78f32e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,12 +90,6 @@ importers: specifier: ^1.2.5 version: 1.2.5 devDependencies: - '@actions/core': - specifier: ^3.0.0 - version: 3.0.0 - '@actions/github': - specifier: ^9.0.0 - version: 9.0.0 '@jest/globals': specifier: 30.2.0 version: 30.2.0 @@ -111,15 +105,9 @@ importers: axios-mock-adapter: specifier: ^2.1.0 version: 2.1.0(axios@1.13.4) - color-contrast-checker: - specifier: ^2.1.0 - version: 2.1.0 express: specifier: ^5.2.1 version: 5.2.1 - hjson: - specifier: ^3.2.2 - version: 3.2.2 jest: specifier: ^30.2.0 version: 30.2.0(@types/node@24.10.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.15.8)(@types/node@24.10.9)(typescript@5.9.3)) @@ -129,12 +117,6 @@ importers: js-yaml: specifier: ^4.1.1 version: 4.1.1 - lodash.snakecase: - specifier: ^4.1.1 - version: 4.1.1 - parse-diff: - specifier: ^0.11.1 - version: 0.11.1 apps/frontend: dependencies: @@ -223,24 +205,6 @@ importers: packages: - '@actions/core@3.0.0': - resolution: {integrity: sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==} - - '@actions/exec@3.0.0': - resolution: {integrity: sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==} - - '@actions/github@9.0.0': - resolution: {integrity: sha512-yJ0RoswsAaKcvkmpCE4XxBRiy/whH2SdTBHWzs0gi4wkqTDhXMChjSdqBz/F4AeiDlP28rQqL33iHb+kjAMX6w==} - - '@actions/http-client@3.0.2': - resolution: {integrity: sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==} - - '@actions/http-client@4.0.0': - resolution: {integrity: sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g==} - - '@actions/io@3.0.2': - resolution: {integrity: sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==} - '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} @@ -832,48 +796,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@octokit/auth-token@6.0.0': - resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} - engines: {node: '>= 20'} - - '@octokit/core@7.0.6': - resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} - engines: {node: '>= 20'} - - '@octokit/endpoint@11.0.2': - resolution: {integrity: sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==} - engines: {node: '>= 20'} - - '@octokit/graphql@9.0.3': - resolution: {integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==} - engines: {node: '>= 20'} - - '@octokit/openapi-types@27.0.0': - resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} - - '@octokit/plugin-paginate-rest@14.0.0': - resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} - engines: {node: '>= 20'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/plugin-rest-endpoint-methods@17.0.0': - resolution: {integrity: sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==} - engines: {node: '>= 20'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/request-error@7.1.0': - resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} - engines: {node: '>= 20'} - - '@octokit/request@10.0.7': - resolution: {integrity: sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==} - engines: {node: '>= 20'} - - '@octokit/types@16.0.0': - resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} - '@oxc-resolver/binding-android-arm-eabi@11.17.0': resolution: {integrity: sha512-kVnY21v0GyZ/+LG6EIO48wK3mE79BUuakHUYLIqobO/Qqq4mJsjuYXMSn3JtLcKZpN1HDVit4UHpGJHef1lrlw==} cpu: [arm] @@ -1840,9 +1762,6 @@ packages: resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} hasBin: true - before-after-hook@4.0.0: - resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} - bn.js@4.12.2: resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} @@ -1989,9 +1908,6 @@ packages: collect-v8-coverage@1.0.3: resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} - color-contrast-checker@2.1.0: - resolution: {integrity: sha512-6Y0aIEej3pwZTVlicIqVzhO6T4izDWouaIXnYoDdTuFFAMQ9nnN0dgHNP9J94jRnH6asjPq1/wzUKxwoNbWtRQ==} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -2442,9 +2358,6 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} - fast-content-type-parse@3.0.0: - resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2689,10 +2602,6 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - hjson@3.2.2: - resolution: {integrity: sha512-MkUeB0cTIlppeSsndgESkfFD21T2nXPRaBStLtf3cAYA2bVEFdXlodZB0TukwZiobPD1Ksax5DK4RTZeaXCI3Q==} - hasBin: true - hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} @@ -3274,9 +3183,6 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.snakecase@4.1.1: - resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - log-update@6.1.0: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} @@ -3535,9 +3441,6 @@ packages: resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==} engines: {node: '>= 0.10'} - parse-diff@0.11.1: - resolution: {integrity: sha512-Oq4j8LAOPOcssanQkIjxosjATBIEJhCxMCxPhMu+Ci4wdNmAEdx0O+a7gzbR2PyKXgKPvRLIN5g224+dJAsKHA==} - parse-imports-exports@0.2.4: resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} @@ -4280,10 +4183,6 @@ packages: tty-browserify@0.0.1: resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} - tunnel@0.0.6: - resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} - engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -4335,17 +4234,10 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@6.23.0: - resolution: {integrity: sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==} - engines: {node: '>=18.17'} - unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} - universal-user-agent@7.0.3: - resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} - unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -4620,37 +4512,6 @@ packages: snapshots: - '@actions/core@3.0.0': - dependencies: - '@actions/exec': 3.0.0 - '@actions/http-client': 4.0.0 - - '@actions/exec@3.0.0': - dependencies: - '@actions/io': 3.0.2 - - '@actions/github@9.0.0': - dependencies: - '@actions/http-client': 3.0.2 - '@octokit/core': 7.0.6 - '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) - '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) - '@octokit/request': 10.0.7 - '@octokit/request-error': 7.1.0 - undici: 6.23.0 - - '@actions/http-client@3.0.2': - dependencies: - tunnel: 0.0.6 - undici: 6.23.0 - - '@actions/http-client@4.0.0': - dependencies: - tunnel: 0.0.6 - undici: 6.23.0 - - '@actions/io@3.0.2': {} - '@adobe/css-tools@4.4.4': {} '@asamuzakjp/css-color@3.2.0': @@ -5314,57 +5175,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@octokit/auth-token@6.0.0': {} - - '@octokit/core@7.0.6': - dependencies: - '@octokit/auth-token': 6.0.0 - '@octokit/graphql': 9.0.3 - '@octokit/request': 10.0.7 - '@octokit/request-error': 7.1.0 - '@octokit/types': 16.0.0 - before-after-hook: 4.0.0 - universal-user-agent: 7.0.3 - - '@octokit/endpoint@11.0.2': - dependencies: - '@octokit/types': 16.0.0 - universal-user-agent: 7.0.3 - - '@octokit/graphql@9.0.3': - dependencies: - '@octokit/request': 10.0.7 - '@octokit/types': 16.0.0 - universal-user-agent: 7.0.3 - - '@octokit/openapi-types@27.0.0': {} - - '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)': - dependencies: - '@octokit/core': 7.0.6 - '@octokit/types': 16.0.0 - - '@octokit/plugin-rest-endpoint-methods@17.0.0(@octokit/core@7.0.6)': - dependencies: - '@octokit/core': 7.0.6 - '@octokit/types': 16.0.0 - - '@octokit/request-error@7.1.0': - dependencies: - '@octokit/types': 16.0.0 - - '@octokit/request@10.0.7': - dependencies: - '@octokit/endpoint': 11.0.2 - '@octokit/request-error': 7.1.0 - '@octokit/types': 16.0.0 - fast-content-type-parse: 3.0.0 - universal-user-agent: 7.0.3 - - '@octokit/types@16.0.0': - dependencies: - '@octokit/openapi-types': 27.0.0 - '@oxc-resolver/binding-android-arm-eabi@11.17.0': optional: true @@ -6238,8 +6048,6 @@ snapshots: baseline-browser-mapping@2.9.19: {} - before-after-hook@4.0.0: {} - bn.js@4.12.2: {} bn.js@5.2.2: {} @@ -6413,8 +6221,6 @@ snapshots: collect-v8-coverage@1.0.3: {} - color-contrast-checker@2.1.0: {} - color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -7036,8 +6842,6 @@ snapshots: transitivePeerDependencies: - supports-color - fast-content-type-parse@3.0.0: {} - fast-deep-equal@3.1.3: {} fast-defer@1.1.9: {} @@ -7289,8 +7093,6 @@ snapshots: dependencies: hermes-estree: 0.25.1 - hjson@3.2.2: {} - hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 @@ -8067,8 +7869,6 @@ snapshots: lodash.merge@4.6.2: {} - lodash.snakecase@4.1.1: {} - log-update@6.1.0: dependencies: ansi-escapes: 7.2.0 @@ -8355,8 +8155,6 @@ snapshots: pbkdf2: 3.1.5 safe-buffer: 5.2.1 - parse-diff@0.11.1: {} - parse-imports-exports@0.2.4: dependencies: parse-statements: 1.0.11 @@ -9162,8 +8960,6 @@ snapshots: tty-browserify@0.0.1: {} - tunnel@0.0.6: {} - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -9233,12 +9029,8 @@ snapshots: undici-types@7.16.0: {} - undici@6.23.0: {} - unicorn-magic@0.3.0: {} - universal-user-agent@7.0.3: {} - unpipe@1.0.0: {} unrs-resolver@1.11.1: