Skip to content

Commit 886c67e

Browse files
committed
refine code to improve readability
1 parent 4c0efc0 commit 886c67e

File tree

8 files changed

+160
-170
lines changed

8 files changed

+160
-170
lines changed

packages/app-builder-lib/src/publish/PublishManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ export async function createPublisher(
317317
return new GitHubPublisher(context, publishConfig as GithubOptions, version, options)
318318

319319
case "gitlab":
320-
return new GitlabPublisher(context, publishConfig as GitlabOptions, version, options)
320+
return new GitlabPublisher(context, publishConfig as GitlabOptions, version)
321321

322322
case "keygen":
323323
return new KeygenPublisher(context, publishConfig as KeygenOptions, version)

packages/builder-util-runtime/src/publishOptions.ts

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,53 @@ export function githubUrl(options: GithubOptions, defaultHost = "github.com") {
143143
return `${options.protocol || "https"}://${options.host || defaultHost}`
144144
}
145145

146+
/**
147+
* [GitLab](https://docs.gitlab.com/ee/user/project/releases/) options.
148+
*
149+
* GitLab [personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) is required for private repositories. You can generate one by going to your GitLab profile settings.
150+
* Define `GITLAB_TOKEN` or `GL_TOKEN` environment variable.
151+
*/
152+
export interface GitlabOptions extends PublishConfiguration {
153+
/**
154+
* The provider. Must be `gitlab`.
155+
*/
156+
readonly provider: "gitlab"
157+
158+
/**
159+
* The GitLab project ID or path (e.g., "12345678" or "namespace/project").
160+
*/
161+
readonly projectId?: string | number | null
162+
163+
/**
164+
* The GitLab host (including the port if need).
165+
* @default gitlab.com
166+
*/
167+
readonly host?: string | null
168+
169+
/**
170+
* The access token to support auto-update from private GitLab repositories. Never specify it in the configuration files.
171+
*/
172+
readonly token?: string | null
173+
174+
/**
175+
* Whether to use `v`-prefixed tag name.
176+
* @default true
177+
*/
178+
readonly vPrefixedTagName?: boolean
179+
180+
/**
181+
* The channel.
182+
* @default latest
183+
*/
184+
readonly channel?: string | null
185+
186+
/**
187+
* Upload target method. Can be "project_upload" for GitLab project uploads or "generic_package" for GitLab generic packages.
188+
* @default "project_upload"
189+
*/
190+
readonly uploadTarget?: "project_upload" | "generic_package" | null
191+
}
192+
146193
/**
147194
* Generic (any HTTP(S) server) options.
148195
* In all publish options [File Macros](./file-patterns.md#file-macros) are supported.
@@ -276,53 +323,6 @@ export interface SnapStoreOptions extends PublishConfiguration {
276323
readonly channels?: string | Array<string> | null
277324
}
278325

279-
/**
280-
* [GitLab](https://docs.gitlab.com/ee/user/project/releases/) options.
281-
*
282-
* GitLab [personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) is required for private repositories. You can generate one by going to your GitLab profile settings.
283-
* Define `GITLAB_TOKEN` or `GL_TOKEN` environment variable.
284-
*/
285-
export interface GitlabOptions extends PublishConfiguration {
286-
/**
287-
* The provider. Must be `gitlab`.
288-
*/
289-
readonly provider: "gitlab"
290-
291-
/**
292-
* The GitLab project ID or path (e.g., "12345678" or "namespace/project").
293-
*/
294-
readonly projectId?: string | number | null
295-
296-
/**
297-
* The GitLab host (including the port if need).
298-
* @default gitlab.com
299-
*/
300-
readonly host?: string | null
301-
302-
/**
303-
* The access token to support auto-update from private GitLab repositories. Never specify it in the configuration files.
304-
*/
305-
readonly token?: string | null
306-
307-
/**
308-
* Whether to use `v`-prefixed tag name.
309-
* @default true
310-
*/
311-
readonly vPrefixedTagName?: boolean
312-
313-
/**
314-
* The channel.
315-
* @default latest
316-
*/
317-
readonly channel?: string | null
318-
319-
/**
320-
* Upload target method. Can be "project_upload" for GitLab project uploads or "generic_package" for GitLab generic packages.
321-
* @default "project_upload"
322-
*/
323-
readonly uploadTarget?: "project_upload" | "generic_package" | null
324-
}
325-
326326
export interface BaseS3Options extends PublishConfiguration {
327327
/**
328328
* The update channel.

packages/electron-publish/src/gitlabPublisher.ts

Lines changed: 59 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import * as mime from "mime"
99
import * as FormData from "form-data"
1010
import { URL } from "url"
1111
import { HttpPublisher } from "./httpPublisher"
12-
import { PublishContext, PublishOptions } from "./index"
13-
import { getCiTag } from "./publisher"
12+
import { PublishContext } from "./index"
13+
14+
type RequestProcessor = (request: ClientRequest, reject: (error: Error) => void) => void
1415

1516
export class GitlabPublisher extends HttpPublisher {
1617
private readonly tag: string
@@ -28,8 +29,7 @@ export class GitlabPublisher extends HttpPublisher {
2829
constructor(
2930
context: PublishContext,
3031
private readonly info: GitlabOptions,
31-
private readonly version: string,
32-
private readonly options: PublishOptions = {}
32+
private readonly version: string
3333
) {
3434
super(context, true)
3535

@@ -67,32 +67,13 @@ export class GitlabPublisher extends HttpPublisher {
6767
}
6868

6969
try {
70-
// Get all releases first, then filter by tag (similar to GitHub publisher pattern)
71-
const url = new URL(`${this.baseApiPath}/projects/${encodeURIComponent(this.projectId)}/releases`)
72-
const releases = await this.gitlabRequest<GitlabReleaseInfo[]>(url, this.token)
73-
for (const release of releases) {
74-
if (release.tag_name === this.tag) {
75-
return release
76-
}
70+
const existingRelease = await this.getExistingRelease()
71+
if (existingRelease) {
72+
return existingRelease
7773
}
7874

7975
// Create new release if it doesn't exist
80-
if (this.options.publish === "always" || getCiTag() != null) {
81-
log.info(
82-
{
83-
reason: "release doesn't exist",
84-
...logFields,
85-
},
86-
`creating GitLab release`
87-
)
88-
return this.createRelease()
89-
}
90-
91-
this.releaseLogFields = {
92-
reason: 'release doesn\'t exist and not created because "publish" is not "always" and build is not on tag',
93-
...logFields,
94-
}
95-
return null
76+
return this.createRelease()
9677
} catch (error: any) {
9778
const errorInfo = this.categorizeGitlabError(error)
9879
log.error(
@@ -108,9 +89,22 @@ export class GitlabPublisher extends HttpPublisher {
10889
}
10990
}
11091

92+
private async getExistingRelease(): Promise<GitlabReleaseInfo | null> {
93+
const url = this.buildProjectUrl("/releases")
94+
const releases = await this.gitlabRequest<GitlabReleaseInfo[]>(url, this.token)
95+
96+
for (const release of releases) {
97+
if (release.tag_name === this.tag) {
98+
return release
99+
}
100+
}
101+
102+
return null
103+
}
104+
111105
private async getDefaultBranch(): Promise<string> {
112106
try {
113-
const url = new URL(`${this.baseApiPath}/projects/${encodeURIComponent(this.projectId)}`)
107+
const url = this.buildProjectUrl()
114108
const project = await this.gitlabRequest<{ default_branch: string }>(url, this.token)
115109
return project.default_branch || "main"
116110
} catch (error: any) {
@@ -139,17 +133,11 @@ export class GitlabPublisher extends HttpPublisher {
139133
"creating GitLab release"
140134
)
141135

142-
const url = new URL(`${this.baseApiPath}/projects/${encodeURIComponent(this.projectId)}/releases`)
136+
const url = this.buildProjectUrl("/releases")
143137
return this.gitlabRequest<GitlabReleaseInfo>(url, this.token, releaseData, "POST")
144138
}
145139

146-
protected async doUpload(
147-
fileName: string,
148-
arch: Arch,
149-
dataLength: number,
150-
requestProcessor: (request: ClientRequest, reject: (error: Error) => void) => void,
151-
_file: string
152-
): Promise<any> {
140+
protected async doUpload(fileName: string, arch: Arch, dataLength: number, requestProcessor: RequestProcessor, filePath: string): Promise<any> {
153141
const release = await this._release.value
154142
if (release == null) {
155143
log.warn({ file: fileName, ...this.releaseLogFields }, "skipped publishing")
@@ -165,32 +153,16 @@ export class GitlabPublisher extends HttpPublisher {
165153

166154
try {
167155
log.debug(logFields, "starting GitLab upload")
168-
// Default to project_upload method
169-
const uploadTarget = this.info.uploadTarget || "project_upload"
170-
171-
let uploadResult
172-
let assetUrl: string
173-
if (uploadTarget === "generic_package") {
174-
uploadResult = await this.uploadToGenericPackages(fileName, dataLength, requestProcessor, _file)
175-
// For generic packages, construct the download URL
176-
const projectId = encodeURIComponent(this.projectId)
177-
assetUrl = `${this.baseApiPath}/projects/${projectId}/packages/generic/releases/${this.version}/${fileName}`
178-
} else {
179-
// Default to project_upload
180-
uploadResult = await this.uploadToProjectUpload(fileName, _file)
181-
// For project uploads, construct full URL from relative path
182-
assetUrl = `https://${this.host}${uploadResult.url}`
183-
}
184-
156+
const assetPath = await this.uploadFileAndReturnAssetPath(fileName, dataLength, requestProcessor, filePath)
185157
// Add the uploaded file as a release asset link
186-
if (assetUrl) {
187-
await this.addReleaseAssetLink(fileName, assetUrl)
188-
log.info({ ...logFields, assetUrl }, "GitLab upload completed successfully")
158+
if (assetPath) {
159+
await this.addReleaseAssetLink(fileName, assetPath)
160+
log.info({ ...logFields, assetPath }, "GitLab upload completed successfully")
189161
} else {
190162
log.warn({ ...logFields }, "No asset URL found for file")
191163
}
192164

193-
return uploadResult
165+
return assetPath
194166
} catch (e: any) {
195167
const errorInfo = this.categorizeGitlabError(e)
196168
log.error(
@@ -206,6 +178,26 @@ export class GitlabPublisher extends HttpPublisher {
206178
}
207179
}
208180

181+
private async uploadFileAndReturnAssetPath(fileName: string, dataLength: number, requestProcessor: RequestProcessor, filePath: string) {
182+
// Default to project_upload method
183+
const uploadTarget = this.info.uploadTarget || "project_upload"
184+
185+
let assetPath: string
186+
if (uploadTarget === "generic_package") {
187+
await this.uploadToGenericPackages(fileName, dataLength, requestProcessor)
188+
// For generic packages, construct the download URL
189+
const projectId = encodeURIComponent(this.projectId)
190+
assetPath = `${this.baseApiPath}/projects/${projectId}/packages/generic/releases/${this.version}/${fileName}`
191+
} else {
192+
// Default to project_upload
193+
const uploadResult = await this.uploadToProjectUpload(fileName, filePath)
194+
// For project uploads, construct full URL from relative path
195+
assetPath = `https://${this.host}${uploadResult.url}`
196+
}
197+
198+
return assetPath
199+
}
200+
209201
private async addReleaseAssetLink(fileName: string, assetUrl: string): Promise<void> {
210202
try {
211203
const linkData = {
@@ -214,7 +206,7 @@ export class GitlabPublisher extends HttpPublisher {
214206
link_type: "other",
215207
}
216208

217-
const url = new URL(`${this.baseApiPath}/projects/${encodeURIComponent(this.projectId)}/releases/${this.tag}/assets/links`)
209+
const url = this.buildProjectUrl(`/releases/${this.tag}/assets/links`)
218210
await this.gitlabRequest(url, this.token, linkData, "POST")
219211

220212
log.debug({ fileName, assetUrl }, "Successfully linked asset to GitLab release")
@@ -224,25 +216,25 @@ export class GitlabPublisher extends HttpPublisher {
224216
}
225217
}
226218

227-
private async uploadToProjectUpload(fileName: string, _filePath: string): Promise<any> {
219+
private async uploadToProjectUpload(fileName: string, filePath: string): Promise<any> {
228220
const uploadUrl = `${this.baseApiPath}/projects/${encodeURIComponent(this.projectId)}/uploads`
229221
const parsedUrl = new URL(uploadUrl)
230222

231223
// Check file size to determine upload method
232-
const stats = await stat(_filePath)
224+
const stats = await stat(filePath)
233225
const fileSize = stats.size
234226
const STREAMING_THRESHOLD = 50 * 1024 * 1024 // 50MB
235227

236228
const form = new FormData()
237229
if (fileSize > STREAMING_THRESHOLD) {
238230
// Use streaming for large files
239231
log.debug({ fileName, fileSize }, "using streaming upload for large file")
240-
const fileStream = createReadStream(_filePath)
232+
const fileStream = createReadStream(filePath)
241233
form.append("file", fileStream, fileName)
242234
} else {
243235
// Use buffer for small files
244236
log.debug({ fileName, fileSize }, "using buffer upload for small file")
245-
const fileContent = await readFile(_filePath)
237+
const fileContent = await readFile(filePath)
246238
form.append("file", fileContent, fileName)
247239
}
248240

@@ -267,12 +259,7 @@ export class GitlabPublisher extends HttpPublisher {
267259
return JSON.parse(response)
268260
}
269261

270-
private async uploadToGenericPackages(
271-
fileName: string,
272-
dataLength: number,
273-
requestProcessor: (request: ClientRequest, reject: (error: Error) => void) => void,
274-
_filePath: string
275-
): Promise<any> {
262+
private async uploadToGenericPackages(fileName: string, dataLength: number, requestProcessor: RequestProcessor): Promise<any> {
276263
const uploadUrl = `${this.baseApiPath}/projects/${encodeURIComponent(this.projectId)}/packages/generic/releases/${this.version}/${fileName}`
277264
const parsedUrl = new URL(uploadUrl)
278265

@@ -294,6 +281,10 @@ export class GitlabPublisher extends HttpPublisher {
294281
)
295282
}
296283

284+
private buildProjectUrl(path: string = ""): URL {
285+
return new URL(`${this.baseApiPath}/projects/${encodeURIComponent(this.projectId)}${path}`)
286+
}
287+
297288
private resolveProjectId(): string {
298289
if (this.info.projectId) {
299290
return String(this.info.projectId)

packages/electron-updater/src/providers/GitLabProvider.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ export class GitLabProvider extends Provider<GitlabUpdateInfo> {
186186
return null
187187
}
188188

189-
private async getReleaseInfoByVersion(version: string): Promise<GitlabReleaseInfo | null> {
189+
private async fetchReleaseInfoByVersion(version: string): Promise<GitlabReleaseInfo | null> {
190190
const cancellationToken = new CancellationToken()
191191

192192
// Try v-prefixed version first, then fallback to plain version
@@ -230,7 +230,7 @@ export class GitLabProvider extends Provider<GitlabUpdateInfo> {
230230
}
231231

232232
// Fetch version info if not cached or version doesn't match
233-
const versionInfo = await this.getReleaseInfoByVersion(version)
233+
const versionInfo = await this.fetchReleaseInfoByVersion(version)
234234
if (versionInfo && versionInfo.assets) {
235235
return this.convertAssetsToMap(versionInfo.assets)
236236
}
@@ -262,8 +262,8 @@ export class GitLabProvider extends Provider<GitlabUpdateInfo> {
262262
}
263263

264264
async getBlockMapFiles(baseUrl: URL, oldVersion: string, newVersion: string, oldBlockMapFileBaseUrl: string | null = null): Promise<URL[]> {
265-
// If is `project_upload`, find blockmap files in GitLab assets
266-
// As each asset has a unique path that includes an identified hash code,
265+
// If is `project_upload`, find blockmap files from corresponding gitLab assets
266+
// Because each asset has an unique path that includes an identified hash code,
267267
// e.g. https://gitlab.com/-/project/71361100/uploads/051f27a925eaf679f2ad688105362acc/latest.yml
268268
if (this.options.uploadTarget === "project_upload") {
269269
// Get the base filename from the URL to find corresponding blockmap files

0 commit comments

Comments
 (0)