release-it-gitea 1.3.3 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md ADDED
@@ -0,0 +1,402 @@
1
+ # Release It! Gitea Plugin
2
+
3
+ English | [中文](README.md)
4
+
5
+ A [release-it](https://github.com/release-it/release-it) plugin for Gitea that supports automatic Gitea release creation and asset uploads.
6
+
7
+ ## Features
8
+
9
+ - ✅ Automatically create and update Gitea releases
10
+ - ✅ Support template variable substitution (version, changelog, etc.)
11
+ - ✅ Support draft and prerelease versions
12
+ - ✅ **Support file and folder asset uploads**
13
+ - ✅ **Support automatic folder packaging to ZIP**
14
+ - ✅ **Support wildcard file matching**
15
+
16
+ ## Quick Start
17
+
18
+ ### 1. Install Plugin
19
+
20
+ ```bash
21
+ npm install --save-dev release-it-gitea
22
+ # or
23
+ pnpm add -D release-it-gitea
24
+ # or
25
+ yarn add -D release-it-gitea
26
+ ```
27
+
28
+ ### 2. Set Environment Variables
29
+
30
+ ```bash
31
+ export GITEA_TOKEN="your-gitea-api-token"
32
+ ```
33
+
34
+ ### 3. Basic Configuration
35
+
36
+ Add to `.release-it.json`:
37
+
38
+ ```json
39
+ {
40
+ "plugins": {
41
+ "release-it-gitea": {
42
+ "host": "https://gitea.example.com",
43
+ "owner": "your-username",
44
+ "repository": "your-repo"
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ ### 4. Run Release
51
+
52
+ ```bash
53
+ npx release-it
54
+ ```
55
+
56
+ ## Detailed Configuration
57
+
58
+ ### Basic Configuration Options
59
+
60
+ | Option | Type | Default | Description |
61
+ | -------------- | ------- | --------------------------- | ------------------------------ |
62
+ | `host` | string | Current repository host | Gitea server URL |
63
+ | `owner` | string | Auto-detect from git remote | Repository owner |
64
+ | `repository` | string | Auto-detect from git remote | Repository name |
65
+ | `release` | boolean | `true` | Whether to create release |
66
+ | `releaseTitle` | string | `"v${version}"` | Release title template |
67
+ | `releaseNotes` | string | `"${changelog}"` | Release notes template |
68
+ | `prerelease` | boolean | `false` | Whether it's a prerelease |
69
+ | `draft` | boolean | `false` | Whether it's a draft |
70
+ | `tokenRef` | string | `"GITEA_TOKEN"` | API token environment variable |
71
+ | `timeout` | number | `30000` | Request timeout (milliseconds) |
72
+ | `assets` | array | `[]` | Additional asset files |
73
+
74
+ ### Complete Configuration Example
75
+
76
+ ```json
77
+ {
78
+ "plugins": {
79
+ "release-it-gitea": {
80
+ "host": "https://gitea.example.com",
81
+ "owner": "your-username",
82
+ "repository": "your-repo",
83
+ "release": true,
84
+ "releaseTitle": "Release ${version}",
85
+ "releaseNotes": "## What's New\n\n${changelog}",
86
+ "prerelease": false,
87
+ "draft": false,
88
+ "tokenRef": "GITEA_TOKEN",
89
+ "timeout": 30000,
90
+ "assets": [
91
+ "dist/app.js",
92
+ "README.md",
93
+ {
94
+ "path": "dist/**/*",
95
+ "name": "distribution-${version}.zip",
96
+ "type": "zip",
97
+ "label": "Distribution Files"
98
+ }
99
+ ]
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## Asset Upload Features
106
+
107
+ ### Basic Usage
108
+
109
+ Supports multiple asset configuration formats:
110
+
111
+ ```json
112
+ {
113
+ "assets": [
114
+ "dist/app.js", // Single file
115
+ "dist/**/*.min.js", // Wildcard matching
116
+ "*.md" // Multiple matching files
117
+ ]
118
+ }
119
+ ```
120
+
121
+ ### Advanced Configuration
122
+
123
+ Use object format for more detailed configuration:
124
+
125
+ ```json
126
+ {
127
+ "assets": [
128
+ {
129
+ "path": "dist/**/*",
130
+ "name": "distribution-files.zip",
131
+ "type": "zip",
132
+ "label": "Distribution Files"
133
+ },
134
+ {
135
+ "path": "docs/*.md",
136
+ "type": "file",
137
+ "label": "Documentation"
138
+ },
139
+ {
140
+ "path": "src",
141
+ "name": "source-code-${version}.zip",
142
+ "type": "zip",
143
+ "label": "Source Code"
144
+ }
145
+ ]
146
+ }
147
+ ```
148
+
149
+ ### Asset Configuration Parameters
150
+
151
+ | Property | Type | Required | Description |
152
+ | -------- | --------------- | -------- | -------------------------------------------------------- |
153
+ | `path` | string | ✅ | File or folder path, supports wildcards |
154
+ | `name` | string | ❌ | Upload filename, uses original filename if not specified |
155
+ | `type` | 'file' \| 'zip' | ❌ | File type, defaults to 'file' |
156
+ | `label` | string | ❌ | File label for identifying file purpose |
157
+
158
+ ### File Type Description
159
+
160
+ - **`file`**: Directly upload matched files
161
+ - **`zip`**: Package matched files into ZIP before upload
162
+
163
+ ## Usage Examples
164
+
165
+ ### Example 1: Upload Build Artifacts
166
+
167
+ ```json
168
+ {
169
+ "assets": ["dist/bundle.js", "dist/bundle.css", "dist/assets/**/*"]
170
+ }
171
+ ```
172
+
173
+ ### Example 2: Package Source Code Release
174
+
175
+ ```json
176
+ {
177
+ "assets": [
178
+ {
179
+ "path": "src/**/*",
180
+ "name": "source-v${version}.zip",
181
+ "type": "zip",
182
+ "label": "Source Code"
183
+ }
184
+ ]
185
+ }
186
+ ```
187
+
188
+ ### Example 3: Multiple File Type Combination
189
+
190
+ ```json
191
+ {
192
+ "assets": [
193
+ "README.md",
194
+ "CHANGELOG.md",
195
+ {
196
+ "path": "dist",
197
+ "name": "build-output.zip",
198
+ "type": "zip"
199
+ },
200
+ {
201
+ "path": "docs/**/*.pdf",
202
+ "type": "file",
203
+ "label": "Documentation"
204
+ }
205
+ ]
206
+ }
207
+ ```
208
+
209
+ ### Example 4: Different Environment Configurations
210
+
211
+ ```json
212
+ {
213
+ "assets": [
214
+ {
215
+ "path": "dist/prod/**/*",
216
+ "name": "production-build-${version}.zip",
217
+ "type": "zip",
218
+ "label": "Production Build"
219
+ },
220
+ {
221
+ "path": "dist/dev/**/*",
222
+ "name": "development-build-${version}.zip",
223
+ "type": "zip",
224
+ "label": "Development Build"
225
+ }
226
+ ]
227
+ }
228
+ ```
229
+
230
+ ## Environment Variable Configuration
231
+
232
+ ### Default Token Configuration
233
+
234
+ ```bash
235
+ export GITEA_TOKEN=your_gitea_api_token
236
+ ```
237
+
238
+ ### Custom Token Configuration
239
+
240
+ ```json
241
+ {
242
+ "tokenRef": "MY_GITEA_TOKEN"
243
+ }
244
+ ```
245
+
246
+ ```bash
247
+ export MY_GITEA_TOKEN=your_gitea_api_token
248
+ ```
249
+
250
+ ## Template Variables
251
+
252
+ The following variables can be used in `releaseTitle`, `releaseNotes`, and asset `name`:
253
+
254
+ | Variable | Description | Example |
255
+ | -------------------- | ---------------- | -------------------- |
256
+ | `${version}` | Current version | `1.2.3` |
257
+ | `${latestVersion}` | Previous version | `1.2.2` |
258
+ | `${changelog}` | Changelog | `- Fixed some bug` |
259
+ | `${name}` | Project name | `my-awesome-project` |
260
+ | `${repo.owner}` | Repository owner | `username` |
261
+ | `${repo.repository}` | Repository name | `my-repo` |
262
+ | `${branchName}` | Branch name | `main` |
263
+
264
+ ### Template Usage Example
265
+
266
+ ```json
267
+ {
268
+ "releaseTitle": "🚀 ${name} v${version}",
269
+ "releaseNotes": "## 📋 What's New\n\n${changelog}\n\n## 📦 Download\n\nPlease download the appropriate file for your platform",
270
+ "assets": [
271
+ {
272
+ "path": "dist/**/*",
273
+ "name": "${name}-${version}-dist.zip",
274
+ "type": "zip",
275
+ "label": "${name} v${version} Distribution"
276
+ }
277
+ ]
278
+ }
279
+ ```
280
+
281
+ ## Troubleshooting
282
+
283
+ ### Common Issues and Solutions
284
+
285
+ #### 1. Asset Upload Failed
286
+
287
+ **Symptoms:**
288
+
289
+ - Error occurs during asset upload
290
+ - File not found
291
+
292
+ **Solutions:**
293
+
294
+ - Check if file paths are correct
295
+ - Ensure files exist and are readable
296
+ - Check if Gitea API Token has asset upload permissions
297
+
298
+ #### 2. ZIP File Creation Failed
299
+
300
+ **Symptoms:**
301
+
302
+ - Error occurs during ZIP file creation
303
+ - Insufficient disk space error
304
+
305
+ **Solutions:**
306
+
307
+ - Ensure sufficient disk space is available
308
+ - Check temporary directory permissions
309
+ - Verify that files to be packaged exist
310
+
311
+ #### 3. Wildcard Matching No Files
312
+
313
+ **Symptoms:**
314
+
315
+ - Wildcard pattern matches no files
316
+ - Asset list is empty
317
+
318
+ **Solutions:**
319
+
320
+ - Verify wildcard pattern is correct
321
+ - Check current working directory
322
+ - Test with absolute or relative paths
323
+
324
+ #### 4. API Request Failed
325
+
326
+ **Symptoms:**
327
+
328
+ - 401 Unauthorized error
329
+ - 404 Repository not found error
330
+ - Network timeout
331
+
332
+ **Solutions:**
333
+
334
+ - Check if Gitea server address is correct
335
+ - Verify API Token is valid and not expired
336
+ - Confirm repository owner and name are correct
337
+ - Check network connection and firewall settings
338
+
339
+ ### Debugging Tips
340
+
341
+ #### Enable Verbose Logging
342
+
343
+ ```bash
344
+ npx release-it --verbose
345
+ ```
346
+
347
+ #### Use Dry Run Mode
348
+
349
+ ```bash
350
+ npx release-it --dry-run
351
+ ```
352
+
353
+ #### Check Configuration
354
+
355
+ ```bash
356
+ npx release-it --config --verbose
357
+ ```
358
+
359
+ ## Development Guide
360
+
361
+ ### Development Environment Setup
362
+
363
+ ```bash
364
+ # Clone repository
365
+ git clone https://github.com/lib-pack/release-it-gitea.git
366
+ cd release-it-gitea
367
+
368
+ # Install dependencies
369
+ pnpm install
370
+
371
+ # Build project
372
+ pnpm build
373
+
374
+ # Run tests
375
+ pnpm test
376
+
377
+ # Code linting
378
+ pnpm lint
379
+
380
+ # Format code
381
+ pnpm format
382
+ ```
383
+
384
+ ### Contributing Guide
385
+
386
+ 1. Fork the project
387
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
388
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
389
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
390
+ 5. Create a Pull Request
391
+
392
+ ## License
393
+
394
+ This project is licensed under the MIT License. See the [LICENSE.md](LICENSE.md) file for details.
395
+
396
+ ## Acknowledgments
397
+
398
+ Thanks to all developers who have contributed to this project!
399
+
400
+ ---
401
+
402
+ If you find this project helpful, please give us a ⭐️!
package/README.md CHANGED
@@ -1,18 +1,21 @@
1
- # release-it-gitea
1
+ # Release It! Gitea Plugin
2
2
 
3
- 一个用于 [release-it](https://github.com/release-it/release-it) Gitea 插件,可以在生成版本和 changelog 后自动将它们推送到指定的 Gitea 服务器的仓库发布中。
3
+ [English](README.en.md) | 中文
4
+
5
+ 一个用于 [release-it](https://github.com/release-it/release-it) 的 Gitea 插件,支持自动创建 Gitea 发布并上传附件。
4
6
 
5
7
  ## 功能特性
6
8
 
7
- - ✅ 自动创建 Gitea 发布
8
- - ✅ 支持自定义发布标题和说明
9
- - ✅ 支持预发布和草稿发布
10
- - ✅ 支持模板变量替换
11
- - ✅ 自动检测并更新已存在的发布
12
- - ✅ 完整的错误处理和日志记录
13
- - ✅ TypeScript 支持
9
+ - ✅ 自动创建和更新 Gitea 发布
10
+ - ✅ 支持模板变量替换(版本号、变更日志等)
11
+ - ✅ 支持草稿和预发布版本
12
+ - ✅ **支持文件和文件夹附件上传**
13
+ - ✅ **支持自动打包文件夹为 ZIP**
14
+ - ✅ **支持通配符文件匹配**
15
+
16
+ ## 快速开始
14
17
 
15
- ## 安装
18
+ ### 1. 安装插件
16
19
 
17
20
  ```bash
18
21
  npm install --save-dev release-it-gitea
@@ -22,19 +25,53 @@ pnpm add -D release-it-gitea
22
25
  yarn add -D release-it-gitea
23
26
  ```
24
27
 
25
- ## 配置
28
+ ### 2. 设置环境变量
29
+
30
+ ```bash
31
+ export GITEA_TOKEN="your-gitea-api-token"
32
+ ```
33
+
34
+ ### 3. 基础配置
35
+
36
+ 在 `.release-it.json` 中添加:
26
37
 
27
- ### 1. 设置环境变量
38
+ ```json
39
+ {
40
+ "plugins": {
41
+ "release-it-gitea": {
42
+ "host": "https://gitea.example.com",
43
+ "owner": "your-username",
44
+ "repository": "your-repo"
45
+ }
46
+ }
47
+ }
48
+ ```
28
49
 
29
- 首先,你需要设置 Gitea API token:
50
+ ### 4. 运行发布
30
51
 
31
52
  ```bash
32
- export GITEA_TOKEN="your-gitea-api-token"
53
+ npx release-it
33
54
  ```
34
55
 
35
- ### 2. 配置 release-it
56
+ ## 详细配置
36
57
 
37
- 在你的 `.release-it.json` 文件中添加插件配置:
58
+ ### 基本配置选项
59
+
60
+ | 选项 | 类型 | 默认值 | 描述 |
61
+ | -------------- | ------- | ---------------------- | -------------------- |
62
+ | `host` | string | 当前仓库的 host | Gitea 服务器 URL |
63
+ | `owner` | string | 从 git remote 自动检测 | 仓库所有者 |
64
+ | `repository` | string | 从 git remote 自动检测 | 仓库名称 |
65
+ | `release` | boolean | `true` | 是否创建发布 |
66
+ | `releaseTitle` | string | `"v${version}"` | 发布标题模板 |
67
+ | `releaseNotes` | string | `"${changelog}"` | 发布说明模板 |
68
+ | `prerelease` | boolean | `false` | 是否为预发布 |
69
+ | `draft` | boolean | `false` | 是否为草稿 |
70
+ | `tokenRef` | string | `"GITEA_TOKEN"` | API token 环境变量名 |
71
+ | `timeout` | number | `30000` | 请求超时时间(毫秒) |
72
+ | `assets` | array | `[]` | 附加的资源文件 |
73
+
74
+ ### 完整配置示例
38
75
 
39
76
  ```json
40
77
  {
@@ -44,125 +81,284 @@ export GITEA_TOKEN="your-gitea-api-token"
44
81
  "owner": "your-username",
45
82
  "repository": "your-repo",
46
83
  "release": true,
47
- "releaseTitle": "v${version}",
48
- "releaseNotes": "${changelog}",
84
+ "releaseTitle": "Release ${version}",
85
+ "releaseNotes": "## 更新内容\n\n${changelog}",
49
86
  "prerelease": false,
50
- "draft": false
87
+ "draft": false,
88
+ "tokenRef": "GITEA_TOKEN",
89
+ "timeout": 30000,
90
+ "assets": [
91
+ "dist/app.js",
92
+ "README.md",
93
+ {
94
+ "path": "dist/**/*",
95
+ "name": "distribution-${version}.zip",
96
+ "type": "zip",
97
+ "label": "Distribution Files"
98
+ }
99
+ ]
51
100
  }
52
101
  }
53
102
  }
54
103
  ```
55
104
 
56
- 或者在 `package.json` 中:
105
+ ## 附件上传功能
106
+
107
+ ### 基本用法
108
+
109
+ 支持多种格式的附件配置:
57
110
 
58
111
  ```json
59
112
  {
60
- "release-it": {
61
- "plugins": {
62
- "release-it-gitea": {
63
- "host": "https://gitea.example.com",
64
- "owner": "your-username",
65
- "repository": "your-repo",
66
- "release": true
67
- }
113
+ "assets": [
114
+ "dist/app.js", // 单个文件
115
+ "dist/**/*.min.js", // 通配符匹配
116
+ "*.md" // 多个匹配文件
117
+ ]
118
+ }
119
+ ```
120
+
121
+ ### 高级配置
122
+
123
+ 使用对象格式进行更详细的配置:
124
+
125
+ ```json
126
+ {
127
+ "assets": [
128
+ {
129
+ "path": "dist/**/*",
130
+ "name": "distribution-files.zip",
131
+ "type": "zip",
132
+ "label": "Distribution Files"
133
+ },
134
+ {
135
+ "path": "docs/*.md",
136
+ "type": "file",
137
+ "label": "Documentation"
138
+ },
139
+ {
140
+ "path": "src",
141
+ "name": "source-code-${version}.zip",
142
+ "type": "zip",
143
+ "label": "Source Code"
68
144
  }
69
- }
145
+ ]
70
146
  }
71
147
  ```
72
148
 
73
- ## 配置选项
149
+ ### 附件配置参数
74
150
 
75
- | 选项 | 类型 | 默认值 | 描述 |
76
- | -------------- | --------- | ---------------------- | -------------------- |
77
- | `host` | `string` | 当前仓库的 host | Gitea 服务器 URL |
78
- | `owner` | `string` | git remote 自动检测 | 仓库所有者 |
79
- | `repository` | `string` | git remote 自动检测 | 仓库名称 |
80
- | `release` | `boolean` | `true` | 是否创建发布 |
81
- | `releaseTitle` | `string` | `"v${version}"` | 发布标题模板 |
82
- | `releaseNotes` | `string` | `"${changelog}"` | 发布说明模板 |
83
- | `prerelease` | `boolean` | `false` | 是否为预发布 |
84
- | `draft` | `boolean` | `false` | 是否为草稿 |
85
- | `tokenRef` | `string` | `"GITEA_TOKEN"` | API token 环境变量名 |
86
- | `timeout` | `number` | `30000` | 请求超时时间(毫秒) |
151
+ | 属性 | 类型 | 必需 | 描述 |
152
+ | ------- | --------------- | ---- | ------------------------------------ |
153
+ | `path` | string | | 文件或文件夹路径,支持通配符 |
154
+ | `name` | string | ❌ | 上传后的文件名,不指定则使用原文件名 |
155
+ | `type` | 'file' \| 'zip' | | 文件类型,默认为 'file' |
156
+ | `label` | string | | 文件标签,用于标识文件用途 |
87
157
 
88
- ## 模板变量
158
+ ### 文件类型说明
89
159
 
90
- `releaseTitle` 和 `releaseNotes` 中可以使用以下模板变量:
160
+ - **`file`**: 直接上传匹配到的文件
161
+ - **`zip`**: 将匹配到的文件打包成 ZIP 文件后上传
91
162
 
92
- - `${version}` - 当前版本号
93
- - `${latestVersion}` - 上一个版本号
94
- - `${changelog}` - 生成的 changelog
95
- - `${name}` - 项目名称
96
- - `${repo.owner}` - 仓库所有者
97
- - `${repo.repository}` - 仓库名称
98
- - `${branchName}` - 当前分支名
163
+ ## 使用场景示例
99
164
 
100
- ## 使用示例
165
+ ### 场景 1:上传构建产物
101
166
 
102
- ### 基础配置
167
+ ```json
168
+ {
169
+ "assets": ["dist/bundle.js", "dist/bundle.css", "dist/assets/**/*"]
170
+ }
171
+ ```
172
+
173
+ ### 场景 2:打包源代码发布
103
174
 
104
175
  ```json
105
176
  {
106
- "plugins": {
107
- "release-it-gitea": {
108
- "host": "https://gitea.example.com"
177
+ "assets": [
178
+ {
179
+ "path": "src/**/*",
180
+ "name": "source-v${version}.zip",
181
+ "type": "zip",
182
+ "label": "Source Code"
109
183
  }
110
- }
184
+ ]
111
185
  }
112
186
  ```
113
187
 
114
- ### 完整配置
188
+ ### 场景 3:多种文件类型组合
115
189
 
116
190
  ```json
117
191
  {
118
- "plugins": {
119
- "release-it-gitea": {
120
- "host": "https://gitea.example.com",
121
- "owner": "myorg",
122
- "repository": "myproject",
123
- "release": true,
124
- "releaseTitle": "Release ${version}",
125
- "releaseNotes": "## 更新内容\n\n${changelog}\n\n---\n\n完整更新日志请查看 [CHANGELOG.md](./CHANGELOG.md)",
126
- "prerelease": false,
127
- "draft": false,
128
- "tokenRef": "GITEA_TOKEN",
129
- "timeout": 30000
192
+ "assets": [
193
+ "README.md",
194
+ "CHANGELOG.md",
195
+ {
196
+ "path": "dist",
197
+ "name": "build-output.zip",
198
+ "type": "zip"
199
+ },
200
+ {
201
+ "path": "docs/**/*.pdf",
202
+ "type": "file",
203
+ "label": "Documentation"
130
204
  }
131
- }
205
+ ]
132
206
  }
133
207
  ```
134
208
 
135
- ### 预发布配置
209
+ ### 场景 4:不同环境的配置
136
210
 
137
211
  ```json
138
212
  {
139
- "plugins": {
140
- "release-it-gitea": {
141
- "host": "https://gitea.example.com",
142
- "releaseTitle": "v${version} (预发布)",
143
- "prerelease": true
213
+ "assets": [
214
+ {
215
+ "path": "dist/prod/**/*",
216
+ "name": "production-build-${version}.zip",
217
+ "type": "zip",
218
+ "label": "Production Build"
219
+ },
220
+ {
221
+ "path": "dist/dev/**/*",
222
+ "name": "development-build-${version}.zip",
223
+ "type": "zip",
224
+ "label": "Development Build"
144
225
  }
145
- }
226
+ ]
146
227
  }
147
228
  ```
148
229
 
149
- ## 工作流程
230
+ ## 环境变量配置
150
231
 
151
- 1. **初始化阶段** - 验证配置和 API 连接
152
- 2. **发布阶段** - 创建或更新 Gitea 发布
153
- 3. **发布后阶段** - 显示发布链接
232
+ ### 默认 Token 配置
154
233
 
155
- ## 错误处理
234
+ ```bash
235
+ export GITEA_TOKEN=your_gitea_api_token
236
+ ```
156
237
 
157
- 插件包含完整的错误处理:
238
+ ### 自定义 Token 配置
158
239
 
159
- - 配置验证
160
- - API token 验证
161
- - 网络连接检查
162
- - API 请求错误处理
163
- - 详细的错误日志
240
+ ```json
241
+ {
242
+ "tokenRef": "MY_GITEA_TOKEN"
243
+ }
244
+ ```
245
+
246
+ ```bash
247
+ export MY_GITEA_TOKEN=your_gitea_api_token
248
+ ```
249
+
250
+ ## 模板变量
251
+
252
+ 在 `releaseTitle`、`releaseNotes` 和附件 `name` 中可以使用以下变量:
253
+
254
+ | 变量 | 描述 | 示例 |
255
+ | -------------------- | ------------ | -------------------- |
256
+ | `${version}` | 当前版本号 | `1.2.3` |
257
+ | `${latestVersion}` | 上一个版本号 | `1.2.2` |
258
+ | `${changelog}` | 变更日志 | `- 修复了某个bug` |
259
+ | `${name}` | 项目名称 | `my-awesome-project` |
260
+ | `${repo.owner}` | 仓库所有者 | `username` |
261
+ | `${repo.repository}` | 仓库名称 | `my-repo` |
262
+ | `${branchName}` | 分支名称 | `main` |
263
+
264
+ ### 模板使用示例
265
+
266
+ ```json
267
+ {
268
+ "releaseTitle": "🚀 ${name} v${version}",
269
+ "releaseNotes": "## 📋 更新内容\n\n${changelog}\n\n## 📦 下载\n\n请下载对应平台的文件",
270
+ "assets": [
271
+ {
272
+ "path": "dist/**/*",
273
+ "name": "${name}-${version}-dist.zip",
274
+ "type": "zip",
275
+ "label": "${name} v${version} Distribution"
276
+ }
277
+ ]
278
+ }
279
+ ```
280
+
281
+ ## 故障排除
282
+
283
+ ### 常见问题及解决方案
284
+
285
+ #### 1. 附件上传失败
286
+
287
+ **问题症状:**
288
+
289
+ - 附件上传时出现错误
290
+ - 文件找不到
291
+
292
+ **解决方案:**
293
+
294
+ - 检查文件路径是否正确
295
+ - 确保文件存在且可读
296
+ - 检查 Gitea API Token 权限是否包含附件上传权限
297
+
298
+ #### 2. ZIP 文件创建失败
299
+
300
+ **问题症状:**
301
+
302
+ - ZIP 文件创建时出错
303
+ - 磁盘空间不足错误
304
+
305
+ **解决方案:**
306
+
307
+ - 确保有足够的磁盘空间
308
+ - 检查临时目录权限
309
+ - 验证要打包的文件是否存在
164
310
 
165
- ## 开发
311
+ #### 3. 通配符匹配无文件
312
+
313
+ **问题症状:**
314
+
315
+ - 通配符模式没有匹配到任何文件
316
+ - 附件列表为空
317
+
318
+ **解决方案:**
319
+
320
+ - 验证通配符模式是否正确
321
+ - 检查当前工作目录
322
+ - 使用绝对路径或相对路径进行测试
323
+
324
+ #### 4. API 请求失败
325
+
326
+ **问题症状:**
327
+
328
+ - 401 未授权错误
329
+ - 404 仓库不存在错误
330
+ - 网络超时
331
+
332
+ **解决方案:**
333
+
334
+ - 检查 Gitea 服务器地址是否正确
335
+ - 验证 API Token 是否有效且未过期
336
+ - 确认仓库所有者和名称正确
337
+ - 检查网络连接和防火墙设置
338
+
339
+ ### 调试技巧
340
+
341
+ #### 启用详细日志
342
+
343
+ ```bash
344
+ npx release-it --verbose
345
+ ```
346
+
347
+ #### 使用干运行模式
348
+
349
+ ```bash
350
+ npx release-it --dry-run
351
+ ```
352
+
353
+ #### 检查配置
354
+
355
+ ```bash
356
+ npx release-it --config --verbose
357
+ ```
358
+
359
+ ## 开发指南
360
+
361
+ ### 开发环境搭建
166
362
 
167
363
  ```bash
168
364
  # 克隆仓库
@@ -172,7 +368,7 @@ cd release-it-gitea
172
368
  # 安装依赖
173
369
  pnpm install
174
370
 
175
- # 构建
371
+ # 构建项目
176
372
  pnpm build
177
373
 
178
374
  # 运行测试
@@ -180,12 +376,27 @@ pnpm test
180
376
 
181
377
  # 代码检查
182
378
  pnpm lint
379
+
380
+ # 格式化代码
381
+ pnpm format
183
382
  ```
184
383
 
384
+ ### 贡献指南
385
+
386
+ 1. Fork 项目
387
+ 2. 创建功能分支 (`git checkout -b feature/amazing-feature`)
388
+ 3. 提交更改 (`git commit -m 'Add amazing feature'`)
389
+ 4. 推送到分支 (`git push origin feature/amazing-feature`)
390
+ 5. 创建 Pull Request
391
+
185
392
  ## 许可证
186
393
 
187
- MIT
394
+ 本项目采用 MIT 许可证。详情请参阅 [LICENSE.md](LICENSE.md) 文件。
395
+
396
+ ## 致谢
397
+
398
+ 感谢所有为这个项目做出贡献的开发者!
188
399
 
189
- ## 贡献
400
+ ---
190
401
 
191
- 欢迎提交 Issue 和 Pull Request!
402
+ 如果您觉得这个项目对您有帮助,请给我们一个 ⭐️!
package/lib/global.d.d.ts CHANGED
@@ -54,6 +54,21 @@ declare module "release-it" {
54
54
  }
55
55
  }
56
56
 
57
+ /** 附件配置接口 */
58
+ interface GiteaAssetConfig {
59
+ /** 文件或文件夹路径,支持通配符 */
60
+ path: string;
61
+
62
+ /** 上传后的文件名,如果不指定则使用原文件名 */
63
+ name?: string;
64
+
65
+ /** 文件类型:'file' 表示单个文件,'zip' 表示打包成 zip 文件 */
66
+ type?: "file" | "zip";
67
+
68
+ /** 文件标签,用于标识文件用途 */
69
+ label?: string;
70
+ }
71
+
57
72
  interface GiteaConfig {
58
73
  /** Gitea 服务器的完整 URL 地址 */
59
74
  host: string;
@@ -84,4 +99,7 @@ interface GiteaConfig {
84
99
 
85
100
  /** API 请求的超时时间,单位为毫秒 */
86
101
  timeout?: number;
102
+
103
+ /** 要上传的附件列表 */
104
+ assets?: (GiteaAssetConfig | string)[];
87
105
  }
package/lib/index.d.ts CHANGED
@@ -58,6 +58,46 @@ declare class GiteaPlugin extends Plugin {
58
58
  * @returns 替换变量后的字符串
59
59
  */
60
60
  private interpolate;
61
+ /**
62
+ * 解析附件配置,将字符串格式转换为标准配置对象
63
+ * @param asset 附件配置
64
+ * @returns 标准化的附件配置对象
65
+ */
66
+ private normalizeAssetConfig;
67
+ /**
68
+ * 根据路径模式匹配文件
69
+ * @param pattern 文件路径模式,支持通配符
70
+ * @returns 匹配到的文件路径数组
71
+ */
72
+ private resolveFiles;
73
+ /**
74
+ * 创建 ZIP 压缩包
75
+ * @param files 要压缩的文件列表
76
+ * @param outputPath 输出的 ZIP 文件路径
77
+ * @param basePath 基础路径,用于确定文件在压缩包中的相对路径
78
+ * @returns Promise<void>
79
+ */
80
+ private createZipArchive;
81
+ /**
82
+ * 上传单个附件到 Gitea 发布
83
+ * @param releaseId 发布 ID
84
+ * @param filePath 文件路径
85
+ * @param fileName 上传后的文件名
86
+ * @param label 文件标签
87
+ * @returns 上传结果
88
+ */
89
+ private uploadAsset;
90
+ /**
91
+ * 处理并上传所有配置的附件
92
+ * @param releaseId 发布 ID
93
+ */
94
+ private uploadAssets;
95
+ /**
96
+ * 处理单个附件配置
97
+ * @param releaseId 发布 ID
98
+ * @param config 附件配置
99
+ */
100
+ private processAsset;
61
101
  /**
62
102
  * 执行发布操作,创建或更新 Gitea 发布.
63
103
  * @throws 当发布创建失败时抛出错误
package/lib/index.js CHANGED
@@ -1,4 +1,9 @@
1
+ import archiver from "archiver";
2
+ import FormData from "form-data";
3
+ import { createReadStream, createWriteStream, statSync } from "fs";
4
+ import { glob } from "glob";
1
5
  import fetch from "node-fetch";
6
+ import { basename, dirname, join } from "path";
2
7
  import { Plugin } from "release-it";
3
8
  class GiteaPlugin extends Plugin {
4
9
  static isEnabled(config) {
@@ -16,6 +21,7 @@ class GiteaPlugin extends Plugin {
16
21
  }
17
22
  const repo = this.config.getContext("repo");
18
23
  const config = {
24
+ assets: gitea.assets ?? [],
19
25
  draft: gitea.draft ?? false,
20
26
  host: gitea.host ?? repo.host,
21
27
  owner: gitea.owner ?? repo.owner,
@@ -162,6 +168,177 @@ class GiteaPlugin extends Plugin {
162
168
  const context = this.config.getContext();
163
169
  return template.replace(/\$\{version\}/g, context.version).replace(/\$\{latestVersion\}/g, context.latestVersion).replace(/\$\{changelog\}/g, context.changelog).replace(/\$\{name\}/g, context.name).replace(/\$\{repo\.owner\}/g, context.repo.owner).replace(/\$\{repo\.repository\}/g, context.repo.repository).replace(/\$\{branchName\}/g, context.branchName);
164
170
  }
171
+ /**
172
+ * 解析附件配置,将字符串格式转换为标准配置对象
173
+ * @param asset 附件配置
174
+ * @returns 标准化的附件配置对象
175
+ */
176
+ normalizeAssetConfig(asset) {
177
+ if (typeof asset === "string") {
178
+ return {
179
+ path: asset,
180
+ type: "file"
181
+ };
182
+ }
183
+ return {
184
+ type: "file",
185
+ ...asset
186
+ };
187
+ }
188
+ /**
189
+ * 根据路径模式匹配文件
190
+ * @param pattern 文件路径模式,支持通配符
191
+ * @returns 匹配到的文件路径数组
192
+ */
193
+ async resolveFiles(pattern) {
194
+ try {
195
+ const files = await glob(pattern, {
196
+ absolute: true,
197
+ nodir: true
198
+ });
199
+ return files;
200
+ } catch (error) {
201
+ this.log.warn(`\u6587\u4EF6\u5339\u914D\u5931\u8D25: ${pattern}, \u9519\u8BEF: ${error}`);
202
+ return [];
203
+ }
204
+ }
205
+ /**
206
+ * 创建 ZIP 压缩包
207
+ * @param files 要压缩的文件列表
208
+ * @param outputPath 输出的 ZIP 文件路径
209
+ * @param basePath 基础路径,用于确定文件在压缩包中的相对路径
210
+ * @returns Promise<void>
211
+ */
212
+ async createZipArchive(files, outputPath, basePath) {
213
+ return new Promise((resolve, reject) => {
214
+ const output = createWriteStream(outputPath);
215
+ const archive = archiver("zip", {
216
+ zlib: { level: 9 }
217
+ });
218
+ output.on("close", () => {
219
+ this.log.verbose(
220
+ `ZIP \u6587\u4EF6\u521B\u5EFA\u5B8C\u6210: ${outputPath} (${archive.pointer()} bytes)`
221
+ );
222
+ resolve();
223
+ });
224
+ archive.on("error", (err) => {
225
+ reject(err);
226
+ });
227
+ archive.pipe(output);
228
+ for (const file of files) {
229
+ const stats = statSync(file);
230
+ if (stats.isFile()) {
231
+ const relativePath = basePath ? file.replace(basePath, "").replace(/^\//, "") : basename(file);
232
+ archive.file(file, { name: relativePath });
233
+ }
234
+ }
235
+ archive.finalize();
236
+ });
237
+ }
238
+ /**
239
+ * 上传单个附件到 Gitea 发布
240
+ * @param releaseId 发布 ID
241
+ * @param filePath 文件路径
242
+ * @param fileName 上传后的文件名
243
+ * @param label 文件标签
244
+ * @returns 上传结果
245
+ */
246
+ async uploadAsset(releaseId, filePath, fileName, label) {
247
+ const url = this.buildApiUrl(
248
+ `/repos/${this.giteaConfig.owner}/${this.giteaConfig.repository}/releases/${releaseId}/assets`
249
+ );
250
+ const token = this.getToken();
251
+ const form = new FormData();
252
+ form.append("attachment", createReadStream(filePath), {
253
+ contentType: "application/octet-stream",
254
+ filename: fileName
255
+ });
256
+ if (label) {
257
+ form.append("name", label);
258
+ }
259
+ const requestOptions = {
260
+ body: form,
261
+ headers: {
262
+ ...form.getHeaders(),
263
+ Authorization: `token ${token}`
264
+ },
265
+ method: "POST",
266
+ timeout: this.giteaConfig.timeout
267
+ };
268
+ this.log.verbose(`\u4E0A\u4F20\u9644\u4EF6: ${fileName} \u5230\u53D1\u5E03 ${releaseId}`);
269
+ try {
270
+ const response = await fetch(url, requestOptions);
271
+ if (!response.ok) {
272
+ const errorText = await response.text();
273
+ throw new Error(`\u9644\u4EF6\u4E0A\u4F20\u5931\u8D25 (${response.status}): ${errorText}`);
274
+ }
275
+ const result = await response.json();
276
+ this.log.info(`\u2705 \u9644\u4EF6\u4E0A\u4F20\u6210\u529F: ${fileName}`);
277
+ return result;
278
+ } catch (error) {
279
+ if (error instanceof Error) {
280
+ throw new Error(`\u9644\u4EF6\u4E0A\u4F20\u5931\u8D25: ${error.message}`);
281
+ }
282
+ throw error;
283
+ }
284
+ }
285
+ /**
286
+ * 处理并上传所有配置的附件
287
+ * @param releaseId 发布 ID
288
+ */
289
+ async uploadAssets(releaseId) {
290
+ const assets = this.giteaConfig.assets;
291
+ if (!assets || assets.length === 0) {
292
+ this.log.verbose("\u6CA1\u6709\u914D\u7F6E\u9644\u4EF6\uFF0C\u8DF3\u8FC7\u4E0A\u4F20");
293
+ return;
294
+ }
295
+ this.log.info(`\u5F00\u59CB\u4E0A\u4F20 ${assets.length} \u4E2A\u9644\u4EF6...`);
296
+ for (const asset of assets) {
297
+ try {
298
+ const config = this.normalizeAssetConfig(asset);
299
+ await this.processAsset(releaseId, config);
300
+ } catch (error) {
301
+ this.log.error(
302
+ `\u9644\u4EF6\u5904\u7406\u5931\u8D25: ${JSON.stringify(asset)}, \u9519\u8BEF: ${error}`
303
+ );
304
+ }
305
+ }
306
+ this.log.info("\u2705 \u6240\u6709\u9644\u4EF6\u5904\u7406\u5B8C\u6210");
307
+ }
308
+ /**
309
+ * 处理单个附件配置
310
+ * @param releaseId 发布 ID
311
+ * @param config 附件配置
312
+ */
313
+ async processAsset(releaseId, config) {
314
+ const files = await this.resolveFiles(config.path);
315
+ if (files.length === 0) {
316
+ this.log.warn(`\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u6587\u4EF6: ${config.path}`);
317
+ return;
318
+ }
319
+ if (config.type === "zip") {
320
+ const zipName = config.name || `${basename(config.path)}.zip`;
321
+ const tempZipPath = join(process.cwd(), ".temp", zipName);
322
+ const { mkdirSync } = await import("fs");
323
+ try {
324
+ mkdirSync(dirname(tempZipPath), { recursive: true });
325
+ } catch (error) {
326
+ }
327
+ await this.createZipArchive(files, tempZipPath, dirname(config.path));
328
+ await this.uploadAsset(releaseId, tempZipPath, zipName, config.label);
329
+ const { unlinkSync } = await import("fs");
330
+ try {
331
+ unlinkSync(tempZipPath);
332
+ } catch (error) {
333
+ this.log.warn(`\u6E05\u7406\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${tempZipPath}`);
334
+ }
335
+ } else {
336
+ for (const file of files) {
337
+ const fileName = config.name || basename(file);
338
+ await this.uploadAsset(releaseId, file, fileName, config.label);
339
+ }
340
+ }
341
+ }
165
342
  /**
166
343
  * 执行发布操作,创建或更新 Gitea 发布.
167
344
  * @throws 当发布创建失败时抛出错误
@@ -197,6 +374,9 @@ class GiteaPlugin extends Plugin {
197
374
  release = await this.createRelease(releaseData);
198
375
  }
199
376
  this.log.info(`\u2705 Gitea \u53D1\u5E03\u521B\u5EFA\u6210\u529F: ${release.html_url}`);
377
+ if (this.giteaConfig.assets && this.giteaConfig.assets.length > 0) {
378
+ await this.uploadAssets(release.id);
379
+ }
200
380
  this.config.setContext("releaseUrl", release.html_url);
201
381
  } catch (error) {
202
382
  if (error instanceof Error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-it-gitea",
3
- "version": "1.3.3",
3
+ "version": "1.4.1",
4
4
  "description": "release-it gitea plugin",
5
5
  "keywords": [
6
6
  "gitea",
@@ -44,12 +44,16 @@
44
44
  "*": "prettier --ignore-unknown --write"
45
45
  },
46
46
  "dependencies": {
47
+ "archiver": "^7.0.1",
48
+ "form-data": "^4.0.3",
49
+ "glob": "^11.0.3",
47
50
  "node-fetch": "^3.3.2"
48
51
  },
49
52
  "devDependencies": {
50
53
  "@eslint-community/eslint-plugin-eslint-comments": "4.5.0",
51
54
  "@eslint/js": "9.22.0",
52
55
  "@release-it/conventional-changelog": "10.0.0",
56
+ "@types/archiver": "^6.0.3",
53
57
  "@types/eslint-plugin-markdown": "2.0.2",
54
58
  "@types/node": "22.13.10",
55
59
  "@types/node-fetch": "^2.6.11",