1
+ import path from 'node:path' ;
2
+
1
3
import { PublisherBase , PublisherOptions } from '@electron-forge/publisher-base' ;
2
4
import { ForgeMakeResult } from '@electron-forge/shared-types' ;
5
+ import { RequestError } from '@octokit/request-error' ;
3
6
import { GetResponseDataTypeFromEndpointMethod } from '@octokit/types' ;
7
+ import chalk from 'chalk' ;
4
8
import fs from 'fs-extra' ;
9
+ import logSymbols from 'log-symbols' ;
5
10
import mime from 'mime-types' ;
6
11
7
12
import { PublisherGitHubConfig } from './Config' ;
@@ -97,9 +102,10 @@ export default class PublisherGithub extends PublisherBase<PublisherGitHubConfig
97
102
uploaded += 1 ;
98
103
updateUploadStatus ( ) ;
99
104
} ;
100
- const artifactName = GitHub . sanitizeName ( artifactPath ) ;
105
+ const artifactName = path . basename ( artifactPath ) ;
106
+ const sanitizedArtifactName = GitHub . sanitizeName ( artifactName ) ;
101
107
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
102
- const asset = release ! . assets . find ( ( item : OctokitReleaseAsset ) => item . name === artifactName ) ;
108
+ const asset = release ! . assets . find ( ( item : OctokitReleaseAsset ) => item . name === sanitizedArtifactName ) ;
103
109
if ( asset !== undefined ) {
104
110
if ( config . force === true ) {
105
111
await github . getGitHub ( ) . repos . deleteReleaseAsset ( {
@@ -111,21 +117,36 @@ export default class PublisherGithub extends PublisherBase<PublisherGitHubConfig
111
117
return done ( ) ;
112
118
}
113
119
}
114
- await github . getGitHub ( ) . repos . uploadReleaseAsset ( {
115
- owner : config . repository . owner ,
116
- repo : config . repository . name ,
117
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
118
- release_id : release ! . id ,
119
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
120
- url : release ! . upload_url ,
121
- // https://github.com/octokit/rest.js/issues/1645
122
- data : ( await fs . readFile ( artifactPath ) ) as unknown as string ,
123
- headers : {
124
- 'content-type' : mime . lookup ( artifactPath ) || 'application/octet-stream' ,
125
- 'content-length' : ( await fs . stat ( artifactPath ) ) . size ,
126
- } ,
127
- name : artifactName ,
128
- } ) ;
120
+ try {
121
+ const { data : uploadedAsset } = await github . getGitHub ( ) . repos . uploadReleaseAsset ( {
122
+ owner : config . repository . owner ,
123
+ repo : config . repository . name ,
124
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
125
+ release_id : release ! . id ,
126
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
127
+ url : release ! . upload_url ,
128
+ // https://github.com/octokit/rest.js/issues/1645
129
+ data : ( await fs . readFile ( artifactPath ) ) as unknown as string ,
130
+ headers : {
131
+ 'content-type' : mime . lookup ( artifactPath ) || 'application/octet-stream' ,
132
+ 'content-length' : ( await fs . stat ( artifactPath ) ) . size ,
133
+ } ,
134
+ name : artifactName ,
135
+ } ) ;
136
+ if ( uploadedAsset . name !== sanitizedArtifactName ) {
137
+ // There's definitely a bug with GitHub.sanitizeName
138
+ console . warn ( logSymbols . warning , chalk . yellow ( `Expected artifact's name to be '${ sanitizedArtifactName } ' - got '${ uploadedAsset . name } '` ) ) ;
139
+ }
140
+ } catch ( err ) {
141
+ // If an asset with that name already exists, it's either a bug with GitHub.sanitizeName
142
+ // where it did not sanitize the artifact name in the same way as GitHub did, or there
143
+ // was simply a race condition with uploading artifacts with the same name
144
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
145
+ if ( err instanceof RequestError && err . status === 422 && ( err . response ?. data as any ) ?. errors ?. [ 0 ] . code === 'already_exists' ) {
146
+ console . error ( `Asset with name '${ artifactName } ' already exists - there may be a bug with Forge's GitHub.sanitizeName util` ) ;
147
+ }
148
+ throw err ;
149
+ }
129
150
return done ( ) ;
130
151
} )
131
152
) ;
0 commit comments