scaffolder: fix binary file uploads during dry-run

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2022-06-03 13:37:25 +02:00
parent 0a4b1f0379
commit fd505f40c0
3 changed files with 74 additions and 1 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Handle binary files and files that are too large during dry-run content upload.
@@ -0,0 +1,44 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { base64EncodeContent } from './DryRunContext';
// eslint-disable-next-line no-restricted-imports
import { TextEncoder } from 'util';
window.TextEncoder = TextEncoder;
describe('base64EncodeContent', () => {
it('encodes text files', () => {
expect(base64EncodeContent('abc')).toBe('YWJj');
expect(base64EncodeContent('abc'.repeat(1000000))).toBe(
btoa('<file too large>'),
);
});
it('encodes binary files', () => {
expect(base64EncodeContent('\x00\x01\x02')).toBe('AAEC');
expect(base64EncodeContent('😅')).toBe('8J+YhQ==');
// Triggers chunking
expect(base64EncodeContent('😅'.repeat(18000))).toBe(
'8J+YhfCfmIXwn5iF8J+YhfCfmIXwn5iF'.repeat(3000),
);
// Triggers size check
expect(base64EncodeContent('😅'.repeat(1000000))).toBe(
btoa('<file too large>'),
);
});
});
@@ -29,6 +29,9 @@ import React, {
import { scaffolderApiRef } from '../../api';
import { ScaffolderDryRunResponse } from '../../types';
const MAX_CONTENT_SIZE = 256 * 1024;
const CHUNK_SIZE = 0x8000;
interface DryRunOptions {
templateContent: string;
values: JsonObject;
@@ -54,6 +57,27 @@ interface DryRunProviderProps {
children: ReactNode;
}
export function base64EncodeContent(content: string): string {
if (content.length > MAX_CONTENT_SIZE) {
return btoa('<file too large>');
}
try {
return btoa(content);
} catch {
const decoder = new TextEncoder();
const buffer = decoder.encode(content);
const chunks = new Array<string>();
for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {
chunks.push(
String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE)),
);
}
return btoa(chunks.join(''));
}
}
export function DryRunProvider(props: DryRunProviderProps) {
const scaffolderApi = useApi(scaffolderApiRef);
@@ -110,7 +134,7 @@ export function DryRunProvider(props: DryRunProviderProps) {
secrets: {},
directoryContents: options.files.map(file => ({
path: file.path,
base64Content: btoa(file.content),
base64Content: base64EncodeContent(file.content),
})),
});