# CI/CD Automation – npm Publish & Storybook Deploy

Everything ships automatically through GitHub Actions. Use this guide to set up the secrets, understand what runs, and know how to fall back to a manual deploy if needed.

---

## 1. Overview

- **publish-npm.yml** → Builds the library, bumps the patch version, and publishes `@itech-india/itech-fluentui` publicly to npm with provenance.
- **deploy-storybook.yml** → Installs with the same credentials, builds Storybook, and deploys it to GitHub Pages (`https://itech-india.github.io/itech-fluentui/`).
- Both workflows trigger on pushes to `main` (and can be run manually from the Actions tab).

---

## 2. One-Time Setup Checklist

### Accounts

- npm account with **Publish** permissions for the `itech-fluentui` package (public package, no scope required).
- GitHub account with write access to `iTech-India/itech-fluentui`.

### Repository Settings

#### Step 1: Create npm Granular Access Token

**⚠️ Important:** npm has migrated from "Automation" tokens to **"Granular Access Tokens"**. Classic tokens are deprecated and will be revoked on December 9, 2025.

1. **Go to npm token settings:**

   - For personal account: <https://www.npmjs.com/settings/YOUR_USERNAME/tokens>
   - For organization: <https://www.npmjs.com/settings/@YOUR_ORG/tokens>

2. **Generate a new Granular Access Token:**

   - Click **"Generate New Token"** (or **"New Token"**)
   - You'll see the new Granular Access Token interface (not the old "Automation" type)

3. **Configure the token:**

   **General Section:**

   - **Token name:** Enter a descriptive name (e.g., "GitHub Actions CI/CD")
   - **Description (optional):** Add a note about what this token is for
   - **Bypass two-factor authentication (2FA):** Leave unchecked (more secure)
   - **Allowed IP ranges (optional):** Leave empty for GitHub Actions

   **Packages and scopes Section:**

   - Find the package `itech-fluentui` in the list (or select "All packages" if available)
   - Set **Permissions** dropdown to: **"Read and write"** ✅
     - This gives both read (install) and write (publish) permissions
     - Options are: "No access", "Read only", "Read and write"
   - If you don't see the specific package, you may need to:
     - Select your organization scope (if applicable)
     - Or select "All packages" with "Read and write" permission

4. **Generate and copy the token:**

   - Click **"Generate Token"** (or **"Create Token"**)
   - The token will start with `npm_...`
   - **⚠️ CRITICAL:** Copy it immediately - you won't be able to see it again!
   - Example: `npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`

**Note:** The new Granular Access Tokens replace the old "Automation" tokens. The "Read and write" permission covers both publishing and installing packages.

#### Step 2: Add NPM_TOKEN to GitHub Secrets

1. **Navigate to repository settings:**

   - Go to your repository: `https://github.com/iTech-India/itech-fluentui`
   - Click **Settings** (top navigation)
   - Click **Secrets and variables** → **Actions** (left sidebar)

2. **Add the secret:**

   - Click **"New repository secret"**
   - **Name:** `NPM_TOKEN` (must be exactly this name)
   - **Secret:** Paste your npm Granular Access Token (the `npm_...` token from Step 1)
   - Click **"Add secret"**

3. **Verify the secret exists:**
   - You should see `NPM_TOKEN` listed in your secrets
   - The value will be hidden (shows as `••••••••`)

#### Step 3: Verify Package Ownership (if package already exists)

If the package `itech-fluentui` already exists on npm, ensure your npm account has publish permissions:

```bash
# Check current owners (run locally)
npm owner ls itech-fluentui

# If you're not listed, add yourself as owner
npm owner add YOUR_NPM_USERNAME itech-fluentui
```

**Note:** For a new package, the token user will automatically become the owner on first publish.

#### Step 4: Configure GitHub Actions Permissions

1. **Go to repository settings:**

   - **Settings → Actions → General**

2. **Configure permissions:**

   - **Workflow permissions:** Select **"Read and write permissions"**
   - ✅ Allow GitHub Actions to create and approve pull requests
   - **Allow all actions and reusable workflows:** ✅ Enabled

3. **Save changes**

#### Step 5: Configure GitHub Pages (for Storybook)

1. **Go to repository settings:**

   - **Settings → Pages**

2. **Configure source:**
   - **Source:** Select **"GitHub Actions"**
   - Save

---

### Quick Setup Summary

```bash
# 1. Create npm Automation token at:
#    https://www.npmjs.com/settings/YOUR_USERNAME/tokens

# 2. Add to GitHub:
#    Repository → Settings → Secrets → Actions → New secret
#    Name: NPM_TOKEN
#    Value: [your npm_... token]

# 3. Verify locally (optional):
npm whoami  # Should show your npm username
npm owner ls itech-fluentui  # Check package ownership
```

### (Optional) Local npmrc

```bash
cat <<'NPMRC' >> ~/.npmrc
@itech-india:registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
always-auth=true
NPMRC
```

Keeps local manual publishes consistent with CI. (Consumers no longer need this file now that the package is public.)

---

## 3. What the Workflows Do

### Publish to npm (`publish-npm.yml`)

1. Checkout with full history.
2. Setup Node 20 + npm auth.
3. `npm ci`
4. `npm version patch --no-git-tag-version`, commit & push result.
5. `npm run build`
6. Ensure version isn’t already on npm.
7. `npm publish --tag latest --access public` (first publish needs the flag; subsequent publishes keep it public, provenance stays enabled).
8. Create git tag + GitHub Release.

### Deploy Storybook (`deploy-storybook.yml`)

1. Checkout latest code.
2. Setup Node 20 + npm auth cache.
3. `npm ci`
4. `npm run build-storybook`
5. Upload artifact + deploy to GitHub Pages (env URL surfaced in workflow run).

### Manual Trigger

1. Go to **Actions**.
2. Select the workflow (Publish to npm / Deploy Storybook).
3. Click **Run workflow**, pick the branch (usually `main`), run.

---

## 4. Manual Fallback (only if automation unavailable)

```bash
npm ci
npm run build
npm version patch          # or minor/major as needed
npm publish --tag latest --access public
git push && git push --tags
npm run build-storybook    # optional, to verify locally
```

Use this when troubleshooting automation or performing the first-ever publish. Remember to include `--access public` if a publish is done from a clean environment.

### How to kick off a publish right now

1. Push your final changes to `main` (or ensure `main` already has what you need to publish).
2. Go to **GitHub → Actions → Publish to npm**.
3. Click **Run workflow**, keep the branch as `main`, and run it. This automatically bumps the patch version, builds, and publishes publicly.
4. Wait for the workflow to finish, then confirm Storybook deploy also ran (or manually trigger the **Deploy Storybook to GitHub Pages** workflow the same way if needed).

---

## 5. Verification Checklist

- `npm view @itech-india/itech-fluentui version` shows the new version.
- Install test succeeds in a clean project via `npm install @itech-india/itech-fluentui@latest`.
- Git tag + GitHub Release exist for the version.
- `https://itech-india.github.io/itech-fluentui/` shows the latest Storybook build.
- Both workflows finished green in the Actions tab.

---

## 6. Troubleshooting

### Quick Fix: NPM_TOKEN Not Set or 403 Forbidden

**If you see:** `❌ ERROR: NPM_TOKEN secret is not set!` or `403 Forbidden`

**⚠️ Already set up the token last week?** Don't recreate it yet! Check these first:

1. **Verify secret exists:**

   - Go to: **Repository → Settings → Secrets and variables → Actions**
   - Confirm `NPM_TOKEN` is listed (exact name, case-sensitive)

2. **Check if token expired/revoked:**

   - Go to: <https://www.npmjs.com/settings/YOUR_USERNAME/tokens>
   - Verify your token is still **Active** (not expired/revoked)
   - Check it's **Automation** type with **Publish** permission

3. **Check package ownership:**

   ```bash
   npm owner ls itech-fluentui
   # If you're not listed, add yourself:
   npm owner add YOUR_USERNAME itech-fluentui
   ```

4. **Re-run workflow** - The enhanced diagnostics will show exactly what's wrong

**If token is missing or invalid, then create a new one:**

1. Create npm Automation token: <https://www.npmjs.com/settings/YOUR_USERNAME/tokens>
   - Type: **Automation**
   - Permissions: **Publish** + **Install**
2. Add to GitHub: **Repository → Settings → Secrets → Actions → New secret**
   - Name: `NPM_TOKEN`
   - Value: Your `npm_...` token
3. Re-run workflow: **Actions → Publish to npm → Run workflow**

**See detailed steps below for more help.**

---

### Common Issues

| Issue                                                                     | Fix                                                                                    |
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `E401 Unauthorized / permission missing`                                  | Ensure token is Automation type, belongs to npm org, and `NPM_TOKEN` secret is updated |
| `E403 Forbidden - You may not perform that action with these credentials` | **See detailed fix below**                                                             |
| `Version already exists`                                                  | Run `npm version patch` (or bump manually), re-run workflow                            |
| `npm ERR! code E403 scope missing`                                        | User/token not added to org – ask admin to add Publish rights                          |
| Workflow fails at `npm ci`                                                | Token missing/expired; rotate `NPM_TOKEN`                                              |
| Storybook deploy fails                                                    | Verify GitHub Pages uses Actions + review `deploy-storybook` logs                      |

### Fixing E403 Forbidden / Missing NPM_TOKEN Error

If you see these errors:

- `❌ ERROR: NPM_TOKEN secret is not set!`
- `npm error 403 Forbidden - You may not perform that action with these credentials`

**Follow these steps:**

#### Step 1: Verify NPM_TOKEN Secret Exists

1. Go to: **Repository → Settings → Secrets and variables → Actions**
2. Check if `NPM_TOKEN` is listed
3. If missing, see **Step 2** below

#### Step 2: Create/Update NPM_TOKEN Secret

**Option A: Use your local npm token (if local publish works)**

```bash
# Get your local token
cat ~/.npmrc | grep _authToken
# Or
npm config get //registry.npmjs.org/:_authToken
```

Then:

1. Copy the token value (starts with `npm_...`)
2. Go to: **Repository → Settings → Secrets → Actions**
3. Click **"New repository secret"** (or edit existing `NPM_TOKEN`)
4. **Name:** `NPM_TOKEN`
5. **Value:** Paste your token
6. Click **"Add secret"** (or **"Update secret"**)

**Option B: Create a new Granular Access Token**

1. Go to: <https://www.npmjs.com/settings/YOUR_USERNAME/tokens>
2. Click **"Generate New Token"** (or **"New Token"**)
3. **Configure the token:**
   - **Token name:** Enter a descriptive name (e.g., "GitHub Actions CI/CD")
   - **Packages and scopes:** Find `itech-fluentui` or select "All packages"
   - **Permissions:** Set to **"Read and write"** ✅
     - This gives both publish and install permissions
4. Click **"Generate Token"** (or **"Create Token"**)
5. Copy the token (starts with `npm_...`) - **⚠️ Copy immediately, you won't see it again!**
6. Add to GitHub Secrets (same steps as Option A)

**Note:** npm has migrated to Granular Access Tokens. The old "Automation" token type is no longer available. Use "Read and write" permission which covers both publishing and installing.

#### Step 3: Verify Token Type and Permissions

**Common reasons existing tokens fail (even if set up correctly):**

- ❌ Token **expired** (check expiration date in npm settings)
- ❌ Token **revoked** (accidentally deleted or regenerated)
- ❌ **Old "Automation" or "Classic" token** - npm deprecated these on December 9, 2025
  - You need to create a new **Granular Access Token** with "Read and write" permissions
- ❌ Token missing **"Read and write"** permission (needed for publishing)
- ❌ Token set to **"Read only"** instead of **"Read and write"**
- ❌ Wrong token copied (extra spaces, missing characters)
- ❌ Secret name typo (must be exactly `NPM_TOKEN`, case-sensitive)
- ❌ Token doesn't have access to the package (ownership issue)

**Verify token works locally:**

```bash
# Test authentication
npm whoami

# Should show your npm username
# If it fails, your token is invalid or expired

# Check your local token (if you have one)
cat ~/.npmrc | grep _authToken
```

**Check token status in npm:**

1. Go to: <https://www.npmjs.com/settings/YOUR_USERNAME/tokens>
2. Find your token in the list
3. Check if it's:
   - ✅ Still **Active** (not expired/revoked)
   - ✅ Type: **Granular Access Token** (not Classic/Automation - those are deprecated)
   - ✅ Has **"Read and write"** permission for `itech-fluentui` (or "All packages")
   - ⚠️ If it's an old "Automation" or "Classic" token, create a new Granular Access Token

#### Step 4: Verify Package Ownership

```bash
# Check if you're an owner (run locally)
npm owner ls itech-fluentui

# If you're not listed, add yourself
npm owner add YOUR_NPM_USERNAME itech-fluentui

# Verify you can publish (dry-run)
npm publish --dry-run --access public
```

#### Step 5: Re-run Workflow

1. Go to: **Actions → Publish to npm**
2. Click **"Run workflow"**
3. Select branch: `main`
4. Click **"Run workflow"**

**If it still fails:**

- Check the workflow logs for detailed error messages
- The workflow now includes enhanced diagnostics
- Verify the token hasn't expired
- Ensure the package name matches exactly: `itech-fluentui` (no scope)

---

Need more depth on components or installation? See `README.md` for consumer setup and `docs/DOCUMENTATION.md` for the full design-system documentation. Update this guide whenever the pipeline changes.
