Skip to content

Conversation

@igort78
Copy link
Contributor

@igort78 igort78 commented Oct 23, 2025

Summary

Adds support for committing design tokens directly to GitHub repositories without requiring GitHub Actions workflows.

This feature bypasses the 65KB payload limitation of the GitHub Actions dispatch API, allowing larger design token files to be committed directly to repositories.

Changes

  • Add github_commit authentication type for direct file commits via GitHub API
  • Implement GithubRepository module for GitHub API integration
  • Add UI components for branch, filepath, and commit message configuration
  • Update README documentation with github_commit auth option
  • Support automatic branch creation if it doesn't exist
  • Handle both file creation and updates via GitHub API

Use Case

This allows users to commit design tokens directly to a GitHub repository from Figma, similar to the existing GitLab commit functionality. Useful for teams who want direct commits without setting up GitHub Actions workflows.

Testing

  • Tested with various repository configurations
  • Verified branch creation and file updates
  • Confirmed error handling for invalid tokens/repositories

- Add github_commit authentication type for direct file commits
- Implement GithubRepository module for GitHub API integration
- Add UI components for branch, filepath, and commit message configuration
- Update README documentation with github_commit auth option
- Supports automatic branch creation if not exists
- Handles both file creation and updates via GitHub API
@igort78 igort78 mentioned this pull request Oct 23, 2025
Closed
@igort78 igort78 force-pushed the feat/github-direct-commit branch from 4673cd4 to 4e5df87 Compare October 23, 2025 17:03
- Remove simple owner/repo format from URL parsing logic
- Update README to document only supported URL formats
- Keep support for https://api.github.com/repos/owner/repo
- Keep support for https://github.com/owner/repo
- Remove :username/:repo format that fails HTML5 validation
@igort78 igort78 force-pushed the feat/github-direct-commit branch 2 times, most recently from 975e2ad to f4aa38e Compare October 23, 2025 17:37
@igort78 igort78 force-pushed the feat/github-direct-commit branch from f4aa38e to 60a858a Compare October 23, 2025 17:37
@0m4r
Copy link
Collaborator

0m4r commented Oct 31, 2025

@igort78, thanks for the PR, I will be reviewing it and will get back to any questions.
Please be patient, as it may take a bit of time.

@0m4r 0m4r requested a review from Copilot November 5, 2025 08:01
@0m4r 0m4r added the Feature New feature or request label Nov 5, 2025
@0m4r 0m4r linked an issue Nov 5, 2025 that may be closed by this pull request
@0m4r 0m4r requested review from 0m4r and lukasoppermann November 5, 2025 08:02
@coveralls
Copy link

coveralls commented Nov 5, 2025

Pull Request Test Coverage Report for Build 19331724053

Details

  • 18 of 123 (14.63%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-6.5%) to 71.419%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/ui/modules/githubRepository.ts 6 111 5.41%
Totals Coverage Status
Change from base Build 18306258487: -6.5%
Covered Lines: 675
Relevant Lines: 945

💛 - Coveralls

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for direct GitHub file commits alongside the existing GitHub Actions workflow dispatch method. Users can now choose to commit design tokens directly to a GitHub repository branch instead of triggering a workflow.

  • Introduces a new GithubRepository class similar to the existing GitlabRepository implementation
  • Adds a new github_commit authentication type option in the UI
  • Updates documentation to clarify the two GitHub integration methods

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/ui/modules/githubRepository.ts New class implementing GitHub API operations for branch management and file commits
src/ui/modules/urlExport.ts Adds URL parsing logic and integration point for GitHub direct commits
src/ui/components/UrlExportSettings.tsx Adds UI controls for the GitHub Direct Commit authentication type and branch selection
src/config/config.ts Adds githubCommit authentication type constant
README.md Updates documentation with GitHub Direct Commit usage instructions and formatting fixes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
) {
const encodedContent = utf8ToBase64(clientPayload.tokens)
const filepath = clientPayload.filename
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filepath is not URI-encoded before being used in GitHub API URLs (lines 44, 210, 265). This will cause API errors if the filename contains special characters like spaces. The GitlabRepository implementation uses encodeURIComponent(clientPayload.filename) to handle this correctly. Apply the same encoding here.

Suggested change
const filepath = clientPayload.filename
const filepath = encodeURIComponent(clientPayload.filename)

Copilot uses AI. Check for mistakes.

try {
// Use reference field (branch name) from settings, consistent with GitLab implementation
const targetBranch = branch
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable targetBranch is redundant. The branch parameter is already destructured from reference with clear semantics. Remove this intermediate variable and use branch directly throughout the method.

Copilot uses AI. Check for mistakes.
Comment on lines +129 to +141
let owner: string, repo: string

const urlParts = exportSettings.url.split('/')
const reposIndex = urlParts.indexOf('repos')
if (reposIndex !== -1 && urlParts.length > reposIndex + 2) {
owner = urlParts[reposIndex + 1]
repo = urlParts[reposIndex + 2]
} else {
// Try to parse from github.com/owner/repo format
owner = urlParts[urlParts.length - 2]
repo = urlParts[urlParts.length - 1]
}

Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL parsing logic has no validation and will silently produce incorrect results for malformed URLs. For example, if the URL ends with a trailing slash, urlParts[urlParts.length - 1] will be an empty string. Additionally, variables owner and repo might not be assigned if the array is too short. Add validation to ensure the URL is properly formatted and the required parts exist before instantiating GithubRepository.

Suggested change
let owner: string, repo: string
const urlParts = exportSettings.url.split('/')
const reposIndex = urlParts.indexOf('repos')
if (reposIndex !== -1 && urlParts.length > reposIndex + 2) {
owner = urlParts[reposIndex + 1]
repo = urlParts[reposIndex + 2]
} else {
// Try to parse from github.com/owner/repo format
owner = urlParts[urlParts.length - 2]
repo = urlParts[urlParts.length - 1]
}
let owner: string | undefined, repo: string | undefined
const urlParts = exportSettings.url.split('/').filter(Boolean) // Remove empty parts (e.g., from trailing slash)
const reposIndex = urlParts.indexOf('repos')
if (reposIndex !== -1 && urlParts.length > reposIndex + 2) {
owner = urlParts[reposIndex + 1]
repo = urlParts[reposIndex + 2]
} else if (urlParts.length >= 2) {
// Try to parse from github.com/owner/repo format
owner = urlParts[urlParts.length - 2]
repo = urlParts[urlParts.length - 1]
}
// Validate owner and repo
if (!owner || !repo) {
// @ts-ignore
parent.postMessage({
pluginMessage: {
command: commands.closePlugin,
payload: {
notification: '🚨 Invalid GitHub URL format. Could not determine owner and repository. Push aborted!'
}
} as PluginMessage
}, '*')
return
}

Copilot uses AI. Check for mistakes.
Comment on lines 183 to 186
if (statusCode === 201 || statusCode === 422) {
resolve()
return
}
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Treating status code 422 (Unprocessable Entity) as a success is incorrect. Status code 422 indicates the request was well-formed but semantically invalid - this is an error condition that should be handled, not silently treated as success. If the intent is to handle the case where the branch already exists, check for a more specific error message in the response rather than accepting all 422 errors.

Suggested change
if (statusCode === 201 || statusCode === 422) {
resolve()
return
}
if (statusCode === 201) {
resolve()
return
}
if (statusCode === 422) {
// Only treat as success if branch already exists
try {
const response = JSON.parse(request.responseText)
if (
response &&
typeof response.message === 'string' &&
response.message.includes('Reference already exists')
) {
resolve()
return
}
} catch (_e) {
// fall through to reject
}
}

Copilot uses AI. Check for mistakes.
}) {
const { request, branch, content, commitMessage, filepath, fileSHA } = args

const body: any = {
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using any type defeats the purpose of TypeScript's type safety. Define a proper interface for the request body with properties message, content, branch, and optional sha, or use an inline type annotation.

Copilot uses AI. Check for mistakes.

if (exportSettings.authType === config.key.authType.githubCommit) {
let owner: string, repo: string

Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Inconsistent blank line usage. This empty line after the variable declaration doesn't match the formatting style used elsewhere in the file.

Suggested change

Copilot uses AI. Check for mistakes.
@0m4r
Copy link
Collaborator

0m4r commented Nov 5, 2025

@igort78, the test coverage has decreased by about 8%.
Can you review it and add the necessary tests to cover your code changes?

- Add proper URI encoding for filenames with special characters
- Improve 422 status handling to only accept 'Reference already exists'
- Remove redundant targetBranch variable for code clarity
@igort78 igort78 force-pushed the feat/github-direct-commit branch from 60a858a to 30278af Compare November 10, 2025 12:35
- Test constructor initialization
- Test upload to existing branch with new/existing files
- Test branch creation when branch doesn't exist
- Test default commit message generation
- Test URL encoding for special characters and unicode
- Mock XMLHttpRequest for isolated unit testing
- Coverage increased from 1.76% to 46.01%

Addresses code review comment about test coverage decrease
- Add tests for URL encoding with slashes
- Add tests for 422 Reference already exists handling
- Add tests for other 422 validation errors
- Add tests for invalid JSON in 422 responses
- Add tests for 401 and 403 error handling
- Coverage improved from 46.01% to 50.44%

This addresses the code review comment about test coverage decrease
- Add 18 tests for githubRepository module covering upload, error handling, and URL encoding
- Add 6 tests for urlExport githubCommit auth type integration
- Improve githubRepository branch coverage from 22% to 40.74%
- Test URI encoding fix (encodeURIComponent)
- Test 422 error handling with 'Reference already exists' message
- Test URL parsing for both API and web URL formats
@igort78
Copy link
Contributor Author

igort78 commented Nov 10, 2025

Updates: Copilot AI Review + Test Coverage ✅

Copilot AI Code Review Fixes Implemented

I've implemented the key suggestions from GitHub Copilot:

  1. URI Encoding Fix - Applied encodeURIComponent() at the point of use (lines 217, 272) to properly encode filepaths with special characters
  2. Improved 422 Error Handling - Enhanced validation by parsing the response body and checking for "Reference already exists" message, not just relying on status code
  3. Code Cleanup - Removed redundant targetBranch variable, now using the branch parameter directly

Test Coverage Added

tests/unit/githubRepository.test.ts - 18 test cases:

  • Constructor and initialization
  • Upload operations (new files, existing files, branch creation)
  • URI encoding fixes (special characters, unicode, slashes in filepath)
  • 422 error handling with "Reference already exists" check
  • Other error codes (401 unauthorized, 403 forbidden)
  • Default commit messages
  • Files with special characters in names

tests/unit/urlExport.test.ts - 6 test cases:

  • githubCommit auth type integration
  • URL parsing (API format: repos/owner/repo and web format: github.com/owner/repo)
  • GithubRepository instantiation with correct parameters
  • Upload method invocation with error/loaded handlers

Coverage Results

githubRepository.ts:

  • Statements: 50.44%
  • Branches: 40.74% (+18.5% improvement from ~22%)
  • Functions: 52.38%
  • Lines: 50.45%

urlExport.ts: 65.15% statements, 76.19% branches

Overall project: 77.71% coverage (maintained)

All 194 tests passing

@igort78
Copy link
Contributor Author

igort78 commented Nov 10, 2025

@0m4r I've updated the PR 👍

@0m4r
Copy link
Collaborator

0m4r commented Nov 13, 2025

@0m4r I've updated the PR 👍

hi @igort78 - it looks good to me, you should do one last thing, include in the commit he build files.
image

Copy link
Collaborator

@0m4r 0m4r left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please include the built files.

@igort78
Copy link
Contributor Author

igort78 commented Nov 13, 2025

@0m4r Thanks! Done ✅

@igort78 igort78 requested a review from 0m4r November 13, 2025 12:36
@0m4r
Copy link
Collaborator

0m4r commented Nov 13, 2025

@lukasoppermann up to you now!

@igort78
Copy link
Contributor Author

igort78 commented Dec 9, 2025

@lukasoppermann Could you please check?

Copy link
Owner

@lukasoppermann lukasoppermann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@0m4r did you test it?

@0m4r
Copy link
Collaborator

0m4r commented Dec 12, 2025

Looks good to me.

@0m4r did you test it?

hey @lukasoppermann yes I did. it worked :)

@lukasoppermann lukasoppermann merged commit ee5d72b into lukasoppermann:main Dec 12, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Send design tokens to URL option does not work : Error 422

4 participants