shadcn-ui/ui

7 workflows · maturity 33% · 3 patterns · GitHub ↗

Security 7.14/100

Practices

○ Matrix✓ Permissions○ Security scan○ AI review✓ Cache○ Concurrency○ Reusable workflows

Detected patterns

Security dimensions

permissions
7.1
security scan
0
supply chain
0
secret handling
0
harden runner
0

Workflows (7)

code-check .github/workflows/code-check.yml
Triggers
pull_request
Runs on
ubuntu-latest, ubuntu-latest, ubuntu-latest
Jobs
lint, format, tsc
Actions
pnpm/action-setup, pnpm/action-setup, pnpm/action-setup
Commands
  • echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
  • pnpm install
  • pnpm lint
  • echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
  • pnpm install
  • pnpm --filter=shadcn build
  • pnpm format:check
  • echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
View raw YAML
name: Code check

on:
  pull_request:
    branches: ["*"]

jobs:
  lint:
    runs-on: ubuntu-latest
    name: pnpm lint
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 20

      - uses: pnpm/action-setup@v4
        name: Install pnpm
        id: pnpm-install
        with:
          version: 9.0.6
          run_install: false

      - name: Get pnpm store directory
        id: pnpm-cache
        run: |
          echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v3
        name: Setup pnpm cache
        with:
          path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      - name: Install dependencies
        run: pnpm install

      - run: pnpm lint

  format:
    runs-on: ubuntu-latest
    name: pnpm format:check
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 20

      - uses: pnpm/action-setup@v4
        name: Install pnpm
        id: pnpm-install
        with:
          version: 9.0.6
          run_install: false

      - name: Get pnpm store directory
        id: pnpm-cache
        run: |
          echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT

      - uses: actions/cache@v3
        name: Setup pnpm cache
        with:
          path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-

      - name: Install dependencies
        run: pnpm install

      - name: Build packages
        run: pnpm --filter=shadcn build

      - run: pnpm format:check

  tsc:
    runs-on: ubuntu-latest
    name: pnpm typecheck
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 20

      - uses: pnpm/action-setup@v4
        name: Install pnpm
        id: pnpm-install
        with:
          version: 9.0.6
          run_install: false

      - name: Get pnpm store directory
        id: pnpm-cache
        run: |
          echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v3
        name: Setup pnpm cache
        with:
          path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      - name: Install dependencies
        run: pnpm install

      - name: Build packages
        run: pnpm --filter=shadcn build

      - run: pnpm typecheck
issue-stale .github/workflows/issue-stale.yml
Triggers
workflow_dispatch, schedule
Runs on
ubuntu-latest
Jobs
stale
Actions
actions/stale, actions/stale
View raw YAML
# Adapted from vercel/next.js
name: "Stale issue handler"
on:
  workflow_dispatch:
  schedule:
    # This runs every day 20 minutes before midnight: https://crontab.guru/#40_23_*_*_*
    - cron: "40 23 * * *"

jobs:
  stale:
    runs-on: ubuntu-latest
    if: github.repository_owner == 'shadcn-ui'
    steps:
      - uses: actions/stale@v9
        id: issue-stale
        name: "Mark stale issues, close stale issues"
        with:
          repo-token: ${{ secrets.STALE_TOKEN }}
          ascending: true
          days-before-issue-close: 7
          days-before-issue-stale: 365
          days-before-pr-stale: -1
          days-before-pr-close: -1
          remove-issue-stale-when-updated: true
          stale-issue-label: "stale?"
          exempt-issue-labels: "roadmap,next"
          stale-issue-message: "This issue has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless there’s further input. If you believe this issue is still relevant, please leave a comment or provide updated details. Thank you. (This is an automated message)"
          close-issue-message: "This issue has been automatically closed due to one year of inactivity. If you’re still experiencing a similar problem or have additional details to share, please open a new issue following our current issue template. Your updated report helps us investigate and address concerns more efficiently. Thank you for your understanding! (This is an automated message)"
          operations-per-run: 300
      - uses: actions/stale@v9
        id: pr-state
        name: "Mark stale PRs, close stale PRs"
        with:
          repo-token: ${{ secrets.STALE_TOKEN }}
          ascending: true
          days-before-issue-close: -1
          days-before-issue-stale: -1
          days-before-pr-close: 7
          days-before-pr-stale: 365
          remove-pr-stale-when-updated: true
          exempt-pr-labels: "roadmap,next,bug"
          stale-pr-label: "stale?"
          stale-pr-message: "This PR has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless there’s further input. If you believe this PR is still relevant, please leave a comment or provide updated details. Thank you. (This is an automated message)"
          close-pr-message: "This PR has been automatically closed due to one year of inactivity. Thank you for your understanding! (This is an automated message)"
          operations-per-run: 300
prerelease perms .github/workflows/prerelease.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
prerelease
Actions
pnpm/action-setup, martinbeentjes/npm-get-version-action
Commands
  • npm install -g npm@latest
  • pnpm install
  • node .github/version-script-beta.js
  • pnpm pub:beta
View raw YAML
# Adapted from create-t3-app.

name: Release - Beta

on:
  pull_request:
    types: [labeled]
    branches:
      - main

permissions:
  id-token: write
  contents: read

jobs:
  prerelease:
    if: |
      github.repository_owner == 'shadcn-ui' &&
      contains(github.event.pull_request.labels.*.name, '🚀 autorelease')
    name: Build & Publish a beta release to NPM
    runs-on: ubuntu-latest
    environment: Preview

    steps:
      - name: Checkout Repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Use PNPM
        uses: pnpm/action-setup@v4
        with:
          version: 9.0.6

      - name: Use Node.js 20
        uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: "https://registry.npmjs.org"
          cache: "pnpm"

      - name: Update npm for OIDC support
        run: npm install -g npm@latest

      - name: Install NPM Dependencies
        run: pnpm install

      - name: Modify package.json version
        run: node .github/version-script-beta.js

      - name: Publish Beta to NPM
        run: pnpm pub:beta

      - name: get-npm-version
        id: package-version
        uses: martinbeentjes/npm-get-version-action@main
        with:
          path: packages/shadcn

      - name: Upload packaged artifact
        uses: actions/upload-artifact@v4
        with:
          name: npm-package-shadcn@${{ steps.package-version.outputs.current-version }}-pr-${{ github.event.number }} # encode the PR number into the artifact name
          path: packages/shadcn/dist/index.js
prerelease-comment .github/workflows/prerelease-comment.yml
Triggers
workflow_run
Runs on
ubuntu-latest
Jobs
comment
Actions
marocchino/sticky-pull-request-comment
View raw YAML
# Adapted from create-t3-app.
name: Write Beta Release comment

on:
  workflow_run:
    workflows: ["Release - Beta"]
    types:
      - completed

jobs:
  comment:
    if: |
      github.repository_owner == 'shadcn-ui' &&
      ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    name: Write comment to the PR
    steps:
      - name: "Comment on PR"
        uses: actions/github-script@v6
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
              owner: context.repo.owner,
              repo: context.repo.repo,
              run_id: context.payload.workflow_run.id,
            });

            for (const artifact of allArtifacts.data.artifacts) {
              // Extract the PR number and package version from the artifact name
              const match = /^npm-package-shadcn@(.*?)-pr-(\d+)/.exec(artifact.name);

              if (match) {
                require("fs").appendFileSync(
                  process.env.GITHUB_ENV,
                  `\nBETA_PACKAGE_VERSION=${match[1]}` +
                  `\nWORKFLOW_RUN_PR=${match[2]}` +
                  `\nWORKFLOW_RUN_ID=${context.payload.workflow_run.id}`
                );
                break;
              }
            }

      - name: "Comment on PR with Link"
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          number: ${{ env.WORKFLOW_RUN_PR }}
          message: |
            A new prerelease is available for testing:

            ```sh
            pnpm dlx shadcn@${{ env.BETA_PACKAGE_VERSION }}
            ```

      - name: "Remove the autorelease label once published"
        uses: actions/github-script@v6
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            github.rest.issues.removeLabel({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: '${{ env.WORKFLOW_RUN_PR }}',
              name: '🚀 autorelease',
            });
release perms .github/workflows/release.yml
Triggers
push
Runs on
ubuntu-latest
Jobs
release
Actions
pnpm/action-setup, changesets/action
Commands
  • npm install -g npm@latest
  • pnpm install
  • pnpm shadcn:build
View raw YAML
# Adapted from create-t3-app.

name: Release

on:
  push:
    branches:
      - main

permissions:
  id-token: write
  contents: write
  pull-requests: write

jobs:
  release:
    if: ${{ github.repository_owner == 'shadcn-ui' }}
    name: Create a PR for release workflow
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Use PNPM
        uses: pnpm/action-setup@v4
        with:
          version: 9.0.6

      - name: Use Node.js 20
        uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: "https://registry.npmjs.org"
          cache: "pnpm"

      - name: Update npm for OIDC support
        run: npm install -g npm@latest

      - name: Install NPM Dependencies
        run: pnpm install

      # - name: Check for errors
      #   run: pnpm check

      - name: Build the package
        run: pnpm shadcn:build

      - name: Create Version PR or Publish to NPM
        id: changesets
        uses: changesets/action@v1
        with:
          commit: "chore(release): version packages"
          title: "chore(release): version packages"
          version: node .github/changeset-version.js
          publish: npx changeset publish
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NODE_ENV: "production"
test .github/workflows/test.yml
Triggers
pull_request
Runs on
ubuntu-latest
Jobs
test
Actions
pnpm/action-setup
Commands
  • echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
  • pnpm install
  • pnpm test
View raw YAML
name: Test

on:
  pull_request:
    branches: ["*"]

jobs:
  test:
    runs-on: ubuntu-latest
    name: pnpm test
    env:
      NEXT_PUBLIC_APP_URL: http://localhost:4000
      NEXT_PUBLIC_V0_URL: https://v0.dev
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 22

      - uses: pnpm/action-setup@v4
        name: Install pnpm
        id: pnpm-install
        with:
          version: 9.0.6
          run_install: false

      - name: Get pnpm store directory
        id: pnpm-cache
        run: |
          echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v3
        name: Setup pnpm cache
        with:
          path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      - name: Install dependencies
        run: pnpm install

      - run: pnpm test
validate-registries .github/workflows/validate-registries.yml
Triggers
pull_request, push
Runs on
ubuntu-latest, ubuntu-latest
Jobs
check-registry-sync, validate
Actions
pnpm/action-setup
Commands
  • CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only) DIRECTORY_CHANGED=false REGISTRIES_CHANGED=false if echo "$CHANGED_FILES" | grep -q "^apps/v4/registry/directory.json$"; then DIRECTORY_CHANGED=true fi if echo "$CHANGED_FILES" | grep -q "^apps/v4/public/r/registries.json$"; then REGISTRIES_CHANGED=true fi echo "directory_changed=$DIRECTORY_CHANGED" >> $GITHUB_OUTPUT echo "registries_changed=$REGISTRIES_CHANGED" >> $GITHUB_OUTPUT
  • gh pr edit ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --add-label "registries: invalid" gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "can you run \`pnpm registry:build\` and commit the json files please?" exit 1
  • node <<'EOF' const fs = require("node:fs") const files = [ "apps/v4/public/r/registries.json", "apps/v4/registry/directory.json", ] const reservedNamespaces = new Set( process.env.RESERVED_NAMESPACES.split(",").filter(Boolean) ) function readNames(filePath) { return JSON.parse(fs.readFileSync(filePath, "utf8")).map( (entry) => entry.name ) } const violations = files.flatMap((filePath) => { return readNames(filePath) .filter((name) => reservedNamespaces.has(name)) .map((name) => `${filePath}: ${name}`) }) if (violations.length > 0) { console.error("Reserved registry namespaces are not allowed:") for (const violation of violations) { console.error(`- ${violation}`) } process.exit(1) } EOF
  • echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
  • pnpm install
  • pnpm --filter=v4 validate:registries
View raw YAML
name: Validate Registries

on:
  pull_request:
    paths:
      - "apps/v4/public/r/registries.json"
      - "apps/v4/registry/directory.json"
  push:
    branches:
      - main
    paths:
      - "apps/v4/public/r/registries.json"
      - "apps/v4/registry/directory.json"

jobs:
  check-registry-sync:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    name: check-registry-sync
    permissions:
      contents: read
      pull-requests: write
    steps:
      - name: Check changed files
        id: changed
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only)

          DIRECTORY_CHANGED=false
          REGISTRIES_CHANGED=false

          if echo "$CHANGED_FILES" | grep -q "^apps/v4/registry/directory.json$"; then
            DIRECTORY_CHANGED=true
          fi

          if echo "$CHANGED_FILES" | grep -q "^apps/v4/public/r/registries.json$"; then
            REGISTRIES_CHANGED=true
          fi

          echo "directory_changed=$DIRECTORY_CHANGED" >> $GITHUB_OUTPUT
          echo "registries_changed=$REGISTRIES_CHANGED" >> $GITHUB_OUTPUT

      - name: Flag missing registries.json update
        if: steps.changed.outputs.directory_changed == 'true' && steps.changed.outputs.registries_changed == 'false'
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh pr edit ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --add-label "registries: invalid"
          gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "can you run \`pnpm registry:build\` and commit the json files please?"
          exit 1

  validate:
    runs-on: ubuntu-latest
    name: pnpm validate:registries
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 20

      - name: Block reserved registry namespaces
        env:
          RESERVED_NAMESPACES: "@shadcn,@ui,@blocks,@components,@block,@component,@util,@utils,@registry,@lib,@hook,@hooks,@theme,@themes,@chart,@charts"
        run: |
          node <<'EOF'
          const fs = require("node:fs")

          const files = [
            "apps/v4/public/r/registries.json",
            "apps/v4/registry/directory.json",
          ]
          const reservedNamespaces = new Set(
            process.env.RESERVED_NAMESPACES.split(",").filter(Boolean)
          )

          function readNames(filePath) {
            return JSON.parse(fs.readFileSync(filePath, "utf8")).map(
              (entry) => entry.name
            )
          }

          const violations = files.flatMap((filePath) => {
            return readNames(filePath)
              .filter((name) => reservedNamespaces.has(name))
              .map((name) => `${filePath}: ${name}`)
          })

          if (violations.length > 0) {
            console.error("Reserved registry namespaces are not allowed:")

            for (const violation of violations) {
              console.error(`- ${violation}`)
            }

            process.exit(1)
          }
          EOF

      - uses: pnpm/action-setup@v4
        name: Install pnpm
        id: pnpm-install
        with:
          version: 9.0.6
          run_install: false

      - name: Get pnpm store directory
        id: pnpm-cache
        run: |
          echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v3
        name: Setup pnpm cache
        with:
          path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      - name: Install dependencies
        run: pnpm install

      - name: Validate registries
        run: pnpm --filter=v4 validate:registries