Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

appservice: Use vscode.workspace.findFiles rather than globby to get files to zip #1616

Merged
merged 8 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions appservice/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion appservice/package.json
bwateratmsft marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"@types/mocha": "^9.0.0",
"@types/node": "^16.0.0",
"@types/p-retry": "^2.0.0",
"@types/vscode": "1.76.0",
"@types/vscode": "1.82.0",
"@types/ws": "^8.5.3",
"@types/yazl": "^2.4.2",
"@typescript-eslint/eslint-plugin": "^5.53.0",
Expand Down
67 changes: 30 additions & 37 deletions appservice/src/deploy/runWithZipStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@
*--------------------------------------------------------------------------------------------*/

import { AzExtPipelineResponse } from '@microsoft/vscode-azext-azureutils';
import { IActionContext } from '@microsoft/vscode-azext-utils';
import { AzExtFsExtra, IActionContext } from '@microsoft/vscode-azext-utils';
import * as fse from 'fs-extra';
import * as globby from 'globby';
import * as path from 'path';
import * as prettybytes from 'pretty-bytes';
import { Readable } from 'stream';
import * as vscode from 'vscode';
import * as yazl from 'yazl';
import { ext } from '../extensionVariables';
import { ParsedSite } from '../SiteClient';
import { ext } from '../extensionVariables';
import { getFileExtension } from '../utils/pathUtils';

export async function runWithZipStream(context: IActionContext, options: {
Expand Down Expand Up @@ -62,7 +61,7 @@ export async function runWithZipStream(context: IActionContext, options: {
if (site.isFunctionApp) {
filesToZip = await getFilesFromGitignore(fsPath, '.funcignore');
} else {
filesToZip = await getFilesFromGlob(fsPath, site);
filesToZip = await getFilesFromGlob(fsPath, site.fullName);
}

for (const file of filesToZip) {
Expand All @@ -83,60 +82,54 @@ function getPathFromMap(realPath: string, pathfileMap?: Map<string, string>): st
return pathfileMap?.get(realPath) || realPath;
}

const commonGlobSettings: Partial<globby.GlobbyOptions> = {
dot: true, // Include paths starting with '.'
followSymbolicLinks: true, // Follow symlinks to get all sub folders https://github.com/microsoft/vscode-azurefunctions/issues/1289
};

/**
* Adds files using glob filtering
*/
async function getFilesFromGlob(folderPath: string, site: ParsedSite): Promise<string[]> {
const zipDeployConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(ext.prefix, vscode.Uri.file(folderPath));
const globOptions = { cwd: folderPath, followSymbolicLinks: true, dot: true };
export async function getFilesFromGlob(folderPath: string, resourceName: string): Promise<string[]> {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of this weird new logics is because a lot of these previous assumptions will break the appservice package when running the tests.

// App Service is the only extension with the zipIgnorePattern setting, so if ext.prefix is undefined, use 'appService'
const zipDeployConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration(ext.prefix ?? 'appService', vscode.Uri.file(folderPath));
// const globOptions = { cwd: folderPath, followSymbolicLinks: true, dot: true };
const globPattern: string = zipDeployConfig.get<string>('zipGlobPattern') || '**/*';
const filesToInclude: string[] = await globby(globPattern, globOptions);
const zipIgnorePatternStr = 'zipIgnorePattern';
const zipIgnorePattern: string[] | string | undefined = zipDeployConfig.get<string | string[]>(zipIgnorePatternStr);
const ignorePatternList: string[] | undefined = typeof zipIgnorePattern === 'string' ? [zipIgnorePattern] : zipIgnorePattern;

let ignorePatternList: string | string[] = zipDeployConfig.get<string | string[]>(zipIgnorePatternStr) || '';
const filesToIgnore: string[] = await globby(ignorePatternList, globOptions);

// first find all files without any ignorePatterns
let files: vscode.Uri[] = await vscode.workspace.findFiles(globPattern);
if (ignorePatternList) {
if (typeof ignorePatternList === 'string') {
ignorePatternList = [ignorePatternList];
try {
// not all ouptut channels _have_ to support appendLog, so catch the error
ext.outputChannel.appendLog(vscode.l10n.t(`Ignoring files from \"{0}.{1}\"`, ext.prefix, zipIgnorePatternStr), { resourceName });
} catch (error) {
ext.outputChannel.appendLine(vscode.l10n.t(`Ignoring files from \"{0}.{1}\"`, ext.prefix, zipIgnorePatternStr));
}
if (ignorePatternList.length > 0) {
ext.outputChannel.appendLog(vscode.l10n.t(`Ignoring files from \"{0}.{1}\"`, ext.prefix, zipIgnorePatternStr), { resourceName: site.fullName });
for (const pattern of ignorePatternList) {
ext.outputChannel.appendLine(`\"${pattern}\"`);
}

// if there is anything to ignore, accumulate a list of ignored files and take the union of the lists
for (const pattern of ignorePatternList) {
const filesIgnored = (await vscode.workspace.findFiles(globPattern, pattern)).map(uri => uri.fsPath);
// only leave in files that are in both lists
files = files.filter(uri => filesIgnored.includes(uri.fsPath));
ext.outputChannel.appendLine(`\"${pattern}\"`);
}
}

return filesToInclude.filter(file => {
return !filesToIgnore.includes(file);
})
return files.filter(f => f.fsPath.includes(folderPath)).map(f => path.relative(folderPath, f.fsPath));
}

/**
* Adds files using gitignore filtering
*/
async function getFilesFromGitignore(folderPath: string, gitignoreName: string): Promise<string[]> {
export async function getFilesFromGitignore(folderPath: string, gitignoreName: string): Promise<string[]> {
let ignore: string[] = [];
const gitignorePath: string = path.join(folderPath, gitignoreName);
if (await fse.pathExists(gitignorePath)) {
const funcIgnoreContents: string = (await fse.readFile(gitignorePath)).toString();
if (await AzExtFsExtra.pathExists(gitignorePath)) {
const funcIgnoreContents: string = await AzExtFsExtra.readFile(gitignorePath);
ignore = funcIgnoreContents
.split('\n')
.map(l => l.trim())
.filter(s => s !== '');
}

return await globby('**/*', {
// We can replace this option and the above logic with `ignoreFiles` if we upgrade to globby^13 (ESM)
// see https://github.com/sindresorhus/globby#ignorefiles
ignore,
cwd: folderPath,
...commonGlobSettings
});
return (await vscode.workspace.findFiles('**/*', `{${ignore.join(',')}}`))
.filter(f => f.fsPath.includes(folderPath))
.map(f => path.relative(folderPath, f.fsPath));
}
70 changes: 70 additions & 0 deletions appservice/test/getFilesFrom.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AzExtFsExtra } from '@microsoft/vscode-azext-utils';
import { getFilesFromGitignore, getFilesFromGlob } from '../src/deploy/runWithZipStream';
import { testWorkspaceRoot } from './global.test';
import * as path from 'path';
import assert = require('assert');

suite("getDeployFsPath", () => {
type TestFolder = { name: string; path?: string; }
const testFolder: TestFolder = { name: 'getFilesFromTestFolder' };
const dummyFolders: string[] = ['dir1', 'dir2', 'dir3'];
const dummyNestedFolders: string[] = ['sub1', 'sub2'];

const rootPath = path.join(testWorkspaceRoot, testFolder.name);

suiteSetup(async () => {
await AzExtFsExtra.ensureDir(rootPath);
for (const folder of dummyFolders) {
const folderPath = path.join(rootPath, folder);
await AzExtFsExtra.ensureDir(folderPath);
// add some dummy files
await AzExtFsExtra.writeFile(path.join(folderPath, 'file.txt'), '');
for (const nestedFolder of dummyNestedFolders) {
await AzExtFsExtra.ensureDir(path.join(folderPath, nestedFolder));
await AzExtFsExtra.writeFile(path.join(folderPath, nestedFolder, 'file.txt'), '');
}
}

await AzExtFsExtra.ensureFile(path.join(rootPath, '.gitignore'));
await AzExtFsExtra.writeFile(path.join(rootPath, '.gitignore'), gitignoreContent);
});

suite('getFilesFrom', () => {
test('getFilesFromGlob', async () => {
const files = await getFilesFromGlob(rootPath, 'testApp');
assert.strictEqual(files.length, expectedFiles.length);
for (const file of files) {
assert.strictEqual(expectedFiles.includes(file), true);
}

});

test('getFilesFromGitignore', async () => {
const files = await getFilesFromGitignore(rootPath, '.gitignore');
assert.strictEqual(files.length, expectedFiles.length);
for (const file of files) {
assert.strictEqual(expectedFiles.includes(file), true);
}
});
})

});

const gitignoreContent = `
dir2
dir3/sub1
`;

const expectedFiles = [
".gitignore",
"dir3\\sub2\\file.txt",
"dir1\\file.txt",
"dir1\\sub2\\file.txt",
"dir1\\sub1\\file.txt",
"dir3\\file.txt",
];
10 changes: 9 additions & 1 deletion appservice/test/test.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@
},
{
"path": "../testWorkspace/deploy2"
},
{
"path": "../testWorkspace/getFilesFromTestFolder"
}
],
"settings": {}
"settings": {
"appService.zipIgnorePattern": [
"dir2{,/**}",
"dir3/sub1{,/**}"
]
}
}
Loading