Skip to content

Export to GitLab

The plugin creates a branch, commits your exported icons, and opens a merge request. To do this via the GitLab REST API, your token must have API write access and your user/token must have at least Developer role on the repository.

Important: write_repository alone is not enough for the REST API (it only covers Git-over-HTTP). Use the api scope to call endpoints like “create branch”, “create commit”, and “create MR”.

Option A — Personal Access Token (user-scoped)

  1. In GitLab, go to User menu → Edit profile → Access Tokens
    (on gitlab.com: Settings → Access Tokens).
  2. Create a token:
    • Scopes: check api (required).
    • (Optional) also check read_repository / write_repository if you plan to use Git-over-HTTP, but api is the key scope for the REST calls this plugin makes.
    • Set an expiry you’re comfortable with.
  3. Copy the token.

Option B — Project Access Token (least privilege for a single repo)

  1. In your project, go to Settings → Access Tokens.
  2. Create a token:
    • Role: Developer (or higher).
    • Scopes: api (required).
      (read_repository/write_repository optional if you’ll use Git-over-HTTP.)
  3. Copy the token.

You can also use a Group Access Token in Group → Settings → Access tokens with Role: Developer and Scope: api if the repo lives in a group.

Add token in the plugin

Open Settings in the plugin and fill:

  • GitLab domain (e.g., https://gitlab.com or your self-hosted URL)
  • Project ID (numeric ID). Find it on the project’s Overview → Details page (shown as “Project ID”).
  • Token (paste the PAT or Project token from above)

Click Save, then run your export.

Troubleshooting

  • 403 Forbidden or insufficient_scope
    • Token doesn’t include api scope → regenerate with api.
    • Token isn’t associated with a member that has Developer (or higher) access to the project.
  • Branch creation fails / push blocked
    • Protected branches: pushing to main is blocked by default—create a feature branch off main.
      Ensure your role (Developer+) is allowed to create branches (check Settings → Repository → Protected branches).
  • Project ID not found / 404
    • Double-check the GitLab domain and Project ID. The ID is a number (not the path).
      If the project is private, the token must have access to it.
  • Self-managed GitLab
    • Ensure your instance permits API access and your token isn’t expired (some instances enforce max expirations).

Minimal API calls used by the plugin (for reference)

  • Create a branch
    POST /projects/:id/repository/branches with params branch=<new-branch>&ref=<base-ref>
  • Commit files (single or batch)
    POST /projects/:id/repository/commits with actions[] payload
  • Open a merge request
    POST /projects/:id/merge_requests with source_branch, target_branch, title

All of the above require the api scope and a Developer (or higher) access level.

Example Design System repository

Jump‑start your setup

We provide a complete example Design System repository you can copy for a production‑ready icon workflow:

See also: Design System Demo Repository

scripts/optimize-icons.mjs

js
import { readdir, readFile, writeFile } from 'fs/promises';
import path from 'path';
import { optimize } from 'svgo';

const ICONS_DIR = path.resolve('src', 'icons');

async function* getSvgs(dir) {
  const dirents = await readdir(dir, { withFileTypes: true });
  for (const dirent of dirents) {
    const res = path.join(dir, dirent.name);
    if (dirent.isDirectory()) {
      yield* getSvgs(res);
    } else if (res.endsWith('.svg')) {
      yield res;
    }
  }
}

for await (const file of getSvgs(ICONS_DIR)) {
  const source = await readFile(file, 'utf8');
  const { data } = optimize(source, {
    path: file,
    multipass: true,
    plugins: [
      {
        name: 'preset-default',
        params: {
          overrides: {
            removeViewBox: false,
          },
        },
      },
    ],
  });

  const colorized = data
    .replace(/stroke="#([0-9a-fA-F]{3,6})"/g, 'stroke="currentColor"')
    .replace(/fill="#([0-9a-fA-F]{3,6})"/g, 'fill="currentColor"');

  await writeFile(file, colorized, 'utf8');
}