Skip to content

Commit

Permalink
fix: s3 upload index.html at last (#12852)
Browse files Browse the repository at this point in the history
* fix: s3 upload index.html at last

* fix: refactor

* fix: sort fileList

* refactor: create sortUploadFiles

* test: unit test sortUploadFiles

* test: revert test

* test: add test for uploadFileCalls

* chore: run prettier-write

* chore: clearAllMocks

* chore: remove unnecessary async

---------

Co-authored-by: MJ☔ <zhamujun@amazon.com>
  • Loading branch information
0618 and zhamujun committed Jun 26, 2023
1 parent 8e8f4a2 commit 99aff47
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ jest.mock('mime-types');
jest.mock('../../../../lib/S3AndCloudFront/helpers/file-scanner', () => {
return {
scan: jest.fn(() => {
return ['filePath1', 'filePath2'];
return ['assets/index-4e7fb3f6.js', 'index.html', 'assets/mapbox-gl-d152561b.js', 'assets/index-d41dc7ea.css', 'vite.svg'];
}),
};
});
jest.mock('../../../../lib/S3AndCloudFront/helpers/upload-file', () => {
return { uploadFile: jest.fn() };
});

const fs = require('fs-extra');
const mime = require('mime-types');

const fileScanner = require('../../../../lib/S3AndCloudFront/helpers/file-scanner');
const { uploadFile } = require('../../../../lib/S3AndCloudFront/helpers/upload-file');

const mockTemplate = require('../../../../__mocks__/mockTemplate');
const mockParameters = require('../../../../__mocks__/mockParameters');
Expand Down Expand Up @@ -89,10 +93,21 @@ describe('cloudfront-manager', () => {
});
});

beforeEach(() => {});
beforeEach(() => {
jest.clearAllMocks();
});

test('run', async () => {
test('file scanner should be called', async () => {
await fileUploader.run(mockContext, 'mockDistributionFolder');
expect(fileScanner.scan).toBeCalled();
});

test('uploadFileCalls should have the index.html at the end', async () => {
await fileUploader.run(mockContext, 'mockDistributionFolder');
expect(uploadFile).toHaveBeenCalled();
const uploadFileCalls = uploadFile.mock.calls;

expect(uploadFileCalls.length).toBe(5);
expect(uploadFileCalls[4][3]).toBe('index.html');
});
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
const fs = require('fs-extra');
const path = require('path');
const Ora = require('ora');
const mime = require('mime-types');
const sequential = require('promise-sequential');
const fileScanner = require('./file-scanner');
const constants = require('../../constants');
const { uploadFile } = require('./upload-file');

const serviceName = 'S3AndCloudFront';
const providerName = 'awscloudformation';
Expand All @@ -13,15 +11,13 @@ async function run(context, distributionDirPath) {
const { WebsiteConfiguration } = context.exeInfo.template.Resources.S3Bucket.Properties;
const fileList = fileScanner.scan(context, distributionDirPath, WebsiteConfiguration);

const uploadFileTasks = [];
const s3Client = await getS3Client(context, 'update');
const hostingBucketName = getHostingBucketName(context);

const hasCloudFront = !!context?.exeInfo?.template?.Resources?.CloudFrontDistribution;

fileList.forEach(filePath => {
uploadFileTasks.push(() => uploadFile(s3Client, hostingBucketName, distributionDirPath, filePath, hasCloudFront));
});
const uploadFileTasks = sortUploadFiles(fileList)
.map(filePath => () => uploadFile(s3Client, hostingBucketName, distributionDirPath, filePath, hasCloudFront));

const spinner = new Ora('Uploading files.');
try {
Expand All @@ -34,6 +30,13 @@ async function run(context, distributionDirPath) {
}
}

function sortUploadFiles(fileList) {
const filesToUploadLast = "index.html";
const sortFiles = (fileA, fileB) => fileA.includes(filesToUploadLast) ? 1 : fileB.includes(filesToUploadLast) ? -1 : 0;

return fileList.sort(sortFiles);
}

async function getS3Client(context, action) {
const providerPlugins = context.amplify.getProviderPlugins(context);
const provider = require(providerPlugins[providerName]);
Expand All @@ -46,29 +49,6 @@ function getHostingBucketName(context) {
return amplifyMeta[constants.CategoryName][serviceName].output.HostingBucketName;
}

async function uploadFile(s3Client, hostingBucketName, distributionDirPath, filePath, hasCloudFront) {
let relativeFilePath = path.relative(distributionDirPath, filePath);
// make Windows-style relative paths compatible to S3
relativeFilePath = relativeFilePath.replace(/\\/g, '/');

const fileStream = fs.createReadStream(filePath);
const contentType = mime.lookup(relativeFilePath);
const uploadParams = {
Bucket: hostingBucketName,
Key: relativeFilePath,
Body: fileStream,
ContentType: contentType || 'text/plain',
};

if (!hasCloudFront) {
uploadParams.ACL = 'public-read';
}

const data = await s3Client.upload(uploadParams).promise();

return data;
}

module.exports = {
run,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const fs = require('fs-extra');
const path = require('path');
const mime = require('mime-types');


async function uploadFile(s3Client, hostingBucketName, distributionDirPath, filePath, hasCloudFront) {
let relativeFilePath = path.relative(distributionDirPath, filePath);
// make Windows-style relative paths compatible to S3
relativeFilePath = relativeFilePath.replace(/\\/g, '/');
const fileStream = fs.createReadStream(filePath);
const contentType = mime.lookup(relativeFilePath);
const uploadParams = {
Bucket: hostingBucketName,
Key: relativeFilePath,
Body: fileStream,
ContentType: contentType || 'text/plain',
};

if (!hasCloudFront) {
uploadParams.ACL = 'public-read';
}

const data = await s3Client.upload(uploadParams).promise();

return data;
}

module.exports = {
uploadFile
};

0 comments on commit 99aff47

Please sign in to comment.