Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
d55d6781
提交
d55d6781
authored
4月 15, 2025
作者:
Will Chen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
support github push
上级
05a97d31
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
126 行增加
和
1 行删除
+126
-1
GitHubConnector.tsx
src/components/GitHubConnector.tsx
+58
-1
github_handlers.ts
src/ipc/handlers/github_handlers.ts
+55
-0
ipc_client.ts
src/ipc/ipc_client.ts
+12
-0
preload.ts
src/preload.ts
+1
-0
没有找到文件。
src/components/GitHubConnector.tsx
浏览文件 @
d55d6781
...
...
@@ -117,7 +117,10 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
const
[
isCreatingRepo
,
setIsCreatingRepo
]
=
useState
(
false
);
const
[
createRepoError
,
setCreateRepoError
]
=
useState
<
string
|
null
>
(
null
);
const
[
createRepoSuccess
,
setCreateRepoSuccess
]
=
useState
<
boolean
>
(
false
);
// --- Sync to GitHub State ---
const
[
isSyncing
,
setIsSyncing
]
=
useState
(
false
);
const
[
syncError
,
setSyncError
]
=
useState
<
string
|
null
>
(
null
);
const
[
syncSuccess
,
setSyncSuccess
]
=
useState
<
boolean
>
(
false
);
// Assume org is the authenticated user for now (could add org input later)
// TODO: After device flow, fetch and store the GitHub username/org in settings for use here
const
githubOrg
=
""
;
// Use empty string for now (GitHub API will default to the authenticated user)
...
...
@@ -169,6 +172,24 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
};
if
(
app
?.
githubOrg
&&
app
?.
githubRepo
)
{
const
handleSyncToGithub
=
async
()
=>
{
setIsSyncing
(
true
);
setSyncError
(
null
);
setSyncSuccess
(
false
);
try
{
const
result
=
await
IpcClient
.
getInstance
().
syncGithubRepo
(
appId
!
);
if
(
result
.
success
)
{
setSyncSuccess
(
true
);
}
else
{
setSyncError
(
result
.
error
||
"Failed to sync to GitHub."
);
}
}
catch
(
err
:
any
)
{
setSyncError
(
err
.
message
||
"Failed to sync to GitHub."
);
}
finally
{
setIsSyncing
(
false
);
}
};
return
(
<
div
className=
"mt-4 w-full border border-gray-200 rounded-md p-4"
>
<
p
>
Connected to GitHub Repo:
</
p
>
...
...
@@ -185,6 +206,42 @@ export function GitHubConnector({ appId, folderName }: GitHubConnectorProps) {
>
{
app
.
githubOrg
}
/
{
app
.
githubRepo
}
</
a
>
<
div
className=
"mt-2"
>
<
Button
onClick=
{
handleSyncToGithub
}
disabled=
{
isSyncing
}
>
{
isSyncing
?
(
<>
<
svg
className=
"animate-spin h-5 w-5 mr-2 inline"
xmlns=
"http://www.w3.org/2000/svg"
fill=
"none"
viewBox=
"0 0 24 24"
style=
{
{
display
:
"inline"
}
}
>
<
circle
className=
"opacity-25"
cx=
"12"
cy=
"12"
r=
"10"
stroke=
"currentColor"
strokeWidth=
"4"
></
circle
>
<
path
className=
"opacity-75"
fill=
"currentColor"
d=
"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></
path
>
</
svg
>
Syncing...
</>
)
:
(
"Sync to GitHub"
)
}
</
Button
>
</
div
>
{
syncError
&&
<
p
className=
"text-red-600 mt-2"
>
{
syncError
}
</
p
>
}
{
syncSuccess
&&
(
<
p
className=
"text-green-600 mt-2"
>
Successfully pushed to GitHub!
</
p
>
)
}
</
div
>
);
}
...
...
src/ipc/handlers/github_handlers.ts
浏览文件 @
d55d6781
...
...
@@ -7,6 +7,14 @@ import {
import
fetch
from
"node-fetch"
;
// Use node-fetch for making HTTP requests in main process
import
{
writeSettings
,
readSettings
}
from
"../../main/settings"
;
import
{
updateAppGithubRepo
}
from
"../../db/index"
;
import
git
from
"isomorphic-git"
;
import
http
from
"isomorphic-git/http/node"
;
import
path
from
"node:path"
;
import
fs
from
"node:fs"
;
import
{
getDyadAppPath
}
from
"../../paths/paths"
;
import
{
db
}
from
"../../db"
;
import
{
apps
}
from
"../../db/schema"
;
import
{
eq
}
from
"drizzle-orm"
;
// --- GitHub Device Flow Constants ---
// TODO: Fetch this securely, e.g., from environment variables or a config file
...
...
@@ -363,10 +371,57 @@ async function handleCreateRepo(
}
}
// --- GitHub Push Handler ---
async
function
handlePushToGithub
(
event
:
IpcMainInvokeEvent
,
{
appId
}:
{
appId
:
number
}
)
{
try
{
// Get access token from settings
const
settings
=
readSettings
();
const
accessToken
=
settings
.
githubSettings
?.
secrets
?.
accessToken
;
if
(
!
accessToken
)
{
return
{
success
:
false
,
error
:
"Not authenticated with GitHub."
};
}
// Get app info from DB
const
app
=
await
db
.
query
.
apps
.
findFirst
({
where
:
eq
(
apps
.
id
,
appId
)
});
if
(
!
app
||
!
app
.
githubOrg
||
!
app
.
githubRepo
)
{
return
{
success
:
false
,
error
:
"App is not linked to a GitHub repo."
};
}
const
appPath
=
getDyadAppPath
(
app
.
path
);
// Set up remote URL with token
const
remoteUrl
=
`https://
${
accessToken
}
:x-oauth-basic@github.com/
${
app
.
githubOrg
}
/
${
app
.
githubRepo
}
.git`
;
// Set or update remote URL using git config
await
git
.
setConfig
({
fs
,
dir
:
appPath
,
path
:
"remote.origin.url"
,
value
:
remoteUrl
,
});
// Push to GitHub
await
git
.
push
({
fs
,
http
,
dir
:
appPath
,
remote
:
"origin"
,
ref
:
"main"
,
onAuth
:
()
=>
({
username
:
accessToken
,
password
:
"x-oauth-basic"
}),
force
:
false
,
});
return
{
success
:
true
};
}
catch
(
err
:
any
)
{
return
{
success
:
false
,
error
:
err
.
message
||
"Failed to push to GitHub."
,
};
}
}
// --- Registration ---
export
function
registerGithubHandlers
()
{
ipcMain
.
handle
(
"github:start-flow"
,
handleStartGithubFlow
);
// ipcMain.on('github:cancel-flow', handleCancelGithubFlow); // Uncomment if you add cancellation
ipcMain
.
handle
(
"github:is-repo-available"
,
handleIsRepoAvailable
);
ipcMain
.
handle
(
"github:create-repo"
,
handleCreateRepo
);
ipcMain
.
handle
(
"github:push"
,
handlePushToGithub
);
}
src/ipc/ipc_client.ts
浏览文件 @
d55d6781
...
...
@@ -603,6 +603,18 @@ export class IpcClient {
return
{
success
:
false
,
error
:
error
.
message
||
"Unknown error"
};
}
}
// Sync (push) local repo to GitHub
public
async
syncGithubRepo
(
appId
:
number
):
Promise
<
{
success
:
boolean
;
error
?:
string
}
>
{
try
{
const
result
=
await
this
.
ipcRenderer
.
invoke
(
"github:push"
,
{
appId
});
return
result
;
}
catch
(
error
:
any
)
{
return
{
success
:
false
,
error
:
error
.
message
||
"Unknown error"
};
}
}
// --- End GitHub Repo Management ---
// Example methods for listening to events (if needed)
...
...
src/preload.ts
浏览文件 @
d55d6781
...
...
@@ -35,6 +35,7 @@ const validInvokeChannels = [
"github:start-flow"
,
"github:is-repo-available"
,
"github:create-repo"
,
"github:push"
,
]
as
const
;
// Add valid receive channels
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论