@@ -10,6 +10,8 @@ const CLI = resolve("bin/github-attach.mjs");
1010const FIXTURE = resolve ( "test/fixtures/cli-fixture.txt" ) ;
1111const SKILL_UPLOADER = resolve ( "skills/attach-github-pr-files/scripts/upload.sh" ) ;
1212const EXPECTED_MARKDOWN = "[cli-fixture.txt](https://example.test/a/id/cli-fixture.txt)\n" ;
13+ const UNICODE_FILENAME = "日本語.txt" ;
14+ const UNICODE_MARKDOWN = `[${ UNICODE_FILENAME } ](https://example.test/a/id/${ encodeURIComponent ( UNICODE_FILENAME ) } )\n` ;
1315
1416test ( "CLI uploads raw bytes and prints only Markdown" , async ( context ) => {
1517 const serviceUrl = await startServer ( context , { alt : "CLI fixture" , token : "test-token" } ) ;
@@ -70,6 +72,29 @@ test("CLI reads the user-level service profile", async (context) => {
7072 assert . equal ( result . stdout , EXPECTED_MARKDOWN ) ;
7173} ) ;
7274
75+ test ( "CLI percent-encodes UTF-8 filenames" , async ( context ) => {
76+ const repository = await temporaryRepository ( context ) ;
77+ const file = join ( repository , UNICODE_FILENAME ) ;
78+ await writeFile ( file , "unicode attachment\n" ) ;
79+ const serviceUrl = await startServer ( context , {
80+ alt : "Unicode CLI" ,
81+ body : "unicode attachment\n" ,
82+ filename : UNICODE_FILENAME ,
83+ markdown : UNICODE_MARKDOWN . trim ( ) ,
84+ token : "unicode-cli-token" ,
85+ } ) ;
86+
87+ const result = await run ( process . execPath , [ CLI , file , "--alt" , "Unicode CLI" ] , {
88+ ...process . env ,
89+ GITHUB_ATTACHMENTS_TOKEN : "unicode-cli-token" ,
90+ GITHUB_ATTACHMENTS_URL : serviceUrl ,
91+ } ) ;
92+
93+ assert . equal ( result . stderr , "" ) ;
94+ assert . equal ( result . exitCode , 0 ) ;
95+ assert . equal ( result . stdout , UNICODE_MARKDOWN ) ;
96+ } ) ;
97+
7398test ( "skill uploader uses the repository override" , async ( context ) => {
7499 const serviceUrl = await startServer ( context , { alt : "Skill" , token : "skill-repo-token" } ) ;
75100 const repository = await temporaryRepository ( context ) ;
@@ -94,6 +119,34 @@ test("skill uploader uses the repository override", async (context) => {
94119 assert . equal ( result . stdout , EXPECTED_MARKDOWN ) ;
95120} ) ;
96121
122+ test ( "skill uploader percent-encodes UTF-8 filenames" , async ( context ) => {
123+ const repository = await temporaryRepository ( context ) ;
124+ const file = join ( repository , UNICODE_FILENAME ) ;
125+ await writeFile ( file , "unicode attachment\n" ) ;
126+ const serviceUrl = await startServer ( context , {
127+ alt : "Unicode skill" ,
128+ body : "unicode attachment\n" ,
129+ filename : UNICODE_FILENAME ,
130+ markdown : UNICODE_MARKDOWN . trim ( ) ,
131+ token : "unicode-skill-token" ,
132+ } ) ;
133+
134+ const result = await run (
135+ SKILL_UPLOADER ,
136+ [ file , "Unicode skill" ] ,
137+ {
138+ ...process . env ,
139+ GITHUB_ATTACHMENTS_TOKEN : "unicode-skill-token" ,
140+ GITHUB_ATTACHMENTS_URL : serviceUrl ,
141+ } ,
142+ repository ,
143+ ) ;
144+
145+ assert . equal ( result . stderr , "" ) ;
146+ assert . equal ( result . exitCode , 0 ) ;
147+ assert . equal ( result . stdout , UNICODE_MARKDOWN ) ;
148+ } ) ;
149+
97150test ( "skill uploader reads the user-level service profile" , async ( context ) => {
98151 const serviceUrl = await startServer ( context , { alt : "Skill user" , token : "skill-user-token" } ) ;
99152 const repository = await temporaryRepository ( context ) ;
@@ -142,18 +195,23 @@ async function startServer(context, expected) {
142195 assert . equal ( request . method , "POST" ) ;
143196 assert . equal ( request . url , "/v1/attachments" ) ;
144197 assert . equal ( request . headers . authorization , `Bearer ${ expected . token } ` ) ;
145- assert . equal ( request . headers [ "x-filename" ] , "cli-fixture.txt" ) ;
198+ const filename = expected . filename ?? "cli-fixture.txt" ;
199+ assert . equal ( request . headers [ "x-filename" ] , encodeURIComponent ( filename ) ) ;
200+ assert . equal ( request . headers [ "x-filename-encoding" ] , "percent" ) ;
146201 assert . equal ( request . headers [ "x-alt-text" ] , expected . alt ) ;
147202 assert . equal ( request . headers [ "content-type" ] , "text/plain" ) ;
148203
149204 const chunks = [ ] ;
150205 for await ( const chunk of request ) {
151206 chunks . push ( chunk ) ;
152207 }
153- assert . equal ( Buffer . concat ( chunks ) . toString ( "utf8" ) , "attachment CLI fixture\n" ) ;
208+ assert . equal (
209+ Buffer . concat ( chunks ) . toString ( "utf8" ) ,
210+ expected . body ?? "attachment CLI fixture\n" ,
211+ ) ;
154212
155213 response . writeHead ( 201 , { "content-type" : "application/json" } ) ;
156- response . end ( JSON . stringify ( { markdown : EXPECTED_MARKDOWN . trim ( ) } ) ) ;
214+ response . end ( JSON . stringify ( { markdown : expected . markdown ?? EXPECTED_MARKDOWN . trim ( ) } ) ) ;
157215 } ) ;
158216 server . listen ( 0 , "127.0.0.1" ) ;
159217 await once ( server , "listening" ) ;
0 commit comments