Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/service/skills.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,12 @@ class SkillsService extends Service {
await SkillsItem.increment('downloads', {
by: 1,
where: { slug: value, is_delete: 0 },
// Do not bump updated_at — downloads must not reorder "recent" sort.
// 不更新 updated_at,避免下载操作影响“最近更新”排序与展示时间
// MySQL 表包含 ON UPDATE CURRENT_TIMESTAMP,显式赋原值防止触发自动更新
silent: true,
attributes: {
updated_at: this.app.Sequelize.col('updated_at'),
},
});
} catch (error) {
this.ctx.logger.warn(
Expand Down
2 changes: 1 addition & 1 deletion app/web/pages/agents/detail/AgentDetailContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ const AgentDetailContent: React.FC<AgentDetailContentProps> = ({ name, history }
<div className="agent-sync-meta-item">
<span className="meta-label">
最近同步代码时间
<Tooltip title="最近一次成功拉取新代码变动并完成同步入库的时间">
<Tooltip title="最近一次成功拉取新代码变动并完成同步入库的时间,定时间隔:1小时">
<QuestionCircleOutlined className="meta-tip-icon" />
</Tooltip>
</span>
Expand Down
8 changes: 4 additions & 4 deletions docs/docsify/zh-cn/guide/agent-market.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,11 @@ Doraemon 采用 GitOps 模式管理 Agent 插件,实现代码集中在 GitLab

> [!NOTE]
> **自动更新周期说明**:
> 系统默认配置了**后台定时自动同步任务(默认每 5 分钟轮询一次)**。远端 GitLab 仓库合入新代码后,后台会在周期触发时自动拉取更新并使新版本生效。若希望代码变动即时生效,可使用页面按钮或 CI/CD API 手动触发即时同步。
> 系统默认配置了**后台定时自动同步任务(默认每 1 小时轮询一次)**。远端 GitLab 仓库合入新代码后,后台会在周期触发时自动拉取更新并使新版本生效。若希望代码变动即时生效,可使用页面按钮或 CI/CD API 手动触发即时同步。

代码同步支持以下触发方式:

- **后台定时自动同步**:服务端默认每 5 分钟自动执行一次全量检查与增量同步(可通过服务端配置 `autoSyncInterval` 调整周期或关闭)。
- **后台定时自动同步**:服务端默认每 1 小时自动执行一次全量检查与增量同步(可通过服务端配置 `autoSyncInterval` 调整周期或关闭)。
- **单个 Agent 手动同步**:在列表页卡片右上角点击【从 Git 同步最新代码】,或在详情页侧边栏点击【从 Git 同步最新代码】按钮。
- **全量批量手动同步**:在列表页顶部点击【全量同步】按钮,后台将按序批量同步所有配置了 Git 仓库的 Agent。
- **配置修改并即时同步**:在详情页【Git 仓库设置】弹窗中修改分支或仓库地址后,可选择保存并立即同步。
Expand Down Expand Up @@ -390,11 +390,11 @@ exports.agentMarket = {
// 允许注入 Token 的 GitLab 域名白名单
gitlabHostWhitelist: ['gitlab.prod.dtstack.cn'],
// 仓库自动轮询定时同步间隔,可通过环境变量 AGENT_MARKET_AUTO_SYNC_INTERVAL 自定义,传空或 '0' 表示关闭
autoSyncInterval: process.env.AGENT_MARKET_AUTO_SYNC_INTERVAL || '5m',
autoSyncInterval: process.env.AGENT_MARKET_AUTO_SYNC_INTERVAL || '1h',
};
```

- **自动轮询同步**:`autoSyncInterval` 默认值为 `'5m'`(每 5 分钟执行一次全量轮询拉取)。当设置为 `''` 或 `'0'` 时可关闭定时轮询。
- **自动轮询同步**:`autoSyncInterval` 默认值为 `'1h'`(每 1 小时执行一次全量轮询拉取)。当设置为 `''` 或 `'0'` 时可关闭定时轮询。
- **凭证安全**:当配置了 `gitlabToken` 时,服务端仅在克隆/拉取属于 `gitlabHostWhitelist` 白名单内的仓库时才会注入 Basic Auth 认证。在执行 Git 操作发生错误时,系统会自动将命令输出和报错中的 Token 及 Authorization 字段进行脱敏,避免凭证泄漏到前端或日志中。

## 与 Skills Hub 的关系
Expand Down
6 changes: 6 additions & 0 deletions test/agent-detail-layout.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,9 @@ test('Agent 详情页提供当前原始 ZIP 下载入口(图标与 hover 提
assert.match(style, /\.agent-side-download-btn/);
assert.doesNotMatch(component, /agent-archive-download/);
});

test('Agent 详情页最近同步代码时间 hover 提示包含定时间隔 1 小时', () => {
const { component } = readDetailFiles();

assert.match(component, /最近一次成功拉取新代码变动并完成同步入库的时间,定时间隔:1小时/);
});
29 changes: 29 additions & 0 deletions test/skills-registry-contract.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1628,3 +1628,32 @@ test('SkillsRegistryController returns flat JSON (no wrapper)', async () => {
await controller.registryMetadata();
assert.deepEqual(controller.ctx.body, { apiBase: '/api/v1' });
});

test('incrementDownloads increments downloads while preserving updated_at (silent: true and attributes.updated_at)', async () => {
const SkillsService = require('../app/service/skills');
const service = Object.create(SkillsService.prototype);
let incrementField = null;
let incrementOptions = null;
service.ensureStorageReady = async () => {};
service.app = {
model: {
SkillsItem: {
increment: async (field, options) => {
incrementField = field;
incrementOptions = options;
},
},
},
Sequelize: {
col: (colName) => ({ col: colName }),
},
};
service.ctx = createMockCtx();

await service.incrementDownloads('demo-skill');
assert.equal(incrementField, 'downloads');
assert.equal(incrementOptions.silent, true);
assert.deepEqual(incrementOptions.attributes, {
updated_at: { col: 'updated_at' },
});
});
Loading