Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 17 additions & 1 deletion src/resolve/forceIgnore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,23 @@ export class ForceIgnore {

private readonly parser?: Ignore;
private readonly forceIgnoreDirectory?: string;
private DEFAULT_IGNORE = ['**/*.dup', '**/.*', '**/package2-descriptor.json', '**/package2-manifest.json'];
private DEFAULT_IGNORE = [
'**/*.dup',
// I know it's ugly. But I want to be able to retrieve metadata to a local dir, segregated by org.
// and `.sf` is already ignored in projects, and we already have orgIds for STL
// so this nastiness is "ignore all dot files except this one directory"
// once you ignore a parent ex `**/.*` you can't unignore something inside that path, at least with the curent ignore library
'**/.*',
'!.sf',
'**/.sf/**',
'!**/.sf/orgs',
'!**/.sf/orgs/**',
'**/.sf/orgs/*/**',
'!**/.sf/orgs/*/remoteMetadata',
'!**/.sf/orgs/*/remoteMetadata/**',
'**/package2-descriptor.json',
'**/package2-manifest.json',
];

public constructor(forceIgnorePath = '') {
try {
Expand Down
11 changes: 6 additions & 5 deletions src/utils/fileSystemHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,23 @@ export const ensureFileExists = async (filePath: string): Promise<void> => {
};

/**
* Traverse up a file path and search for the given file name.
* Traverse up a file path and search for the given file name. Always returns an absolute path.
*
* @param start File or folder path to start searching from
* @param fileName File name to search for
*/
export function searchUp(start: SourcePath, fileName: string): string | undefined {
const filePath = path.join(start, fileName);
const absoluteStart = path.isAbsolute(start) ? start : path.join(process.cwd(), start);
const filePath = path.join(absoluteStart, fileName);
if (fs.existsSync(filePath)) {
return filePath;
}

const normalizedStart = path.normalize(start);
const parent = path.dirname(normalizedStart);
const normalizedAbsoluteStart = path.normalize(absoluteStart);
const parent = path.dirname(normalizedAbsoluteStart);

// If we're at root, stop (don't try to go up with ..)
if (parent === normalizedStart || normalizedStart === path.parse(normalizedStart).root) {
if (parent === normalizedAbsoluteStart || normalizedAbsoluteStart === path.parse(normalizedAbsoluteStart).root) {
return;
}

Expand Down
48 changes: 35 additions & 13 deletions test/nuts/local/searchUp/searchUp.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,41 +60,63 @@ describe('searchUp nut test', () => {

describe('relative paths', () => {
it('finds file in parent directory', () => {
const startPath = path.join(session.project.dir, 'level1', 'level2', 'startDir');
const result = searchUp(startPath, 'target.txt');
const relativeStartPath = path.relative(
session.project.dir,
path.join(session.project.dir, 'level1', 'level2', 'startDir')
);
expect(path.isAbsolute(relativeStartPath)).to.be.false;
const result = searchUp(relativeStartPath, 'target.txt');
const expected = path.join(session.project.dir, 'level1', 'level2', 'target.txt');

expect(result).to.equal(expected);
});

it('finds file multiple levels up', () => {
const startPath = path.join(session.project.dir, 'level1', 'level2', 'startDir');
const result = searchUp(startPath, '.gitignore');
const relativeStartPath = path.relative(
session.project.dir,
path.join(session.project.dir, 'level1', 'level2', 'startDir')
);
expect(path.isAbsolute(relativeStartPath)).to.be.false;
const result = searchUp(relativeStartPath, '.gitignore');
const expected = path.join(session.project.dir, '.gitignore');

expect(result).to.equal(expected);
});

it('finds file in current directory', () => {
const startPath = path.join(session.project.dir, 'level1', 'level2', 'startDir');
fs.writeFileSync(path.join(startPath, 'localFile.txt'), 'local content');
const result = searchUp(startPath, 'localFile.txt');
const expected = path.join(startPath, 'localFile.txt');
const relativeStartPath = path.relative(
session.project.dir,
path.join(session.project.dir, 'level1', 'level2', 'startDir')
);
expect(path.isAbsolute(relativeStartPath)).to.be.false;
const absoluteStartPath = path.resolve(session.project.dir, relativeStartPath);
fs.writeFileSync(path.join(absoluteStartPath, 'localFile.txt'), 'local content');
const result = searchUp(relativeStartPath, 'localFile.txt');
const expected = path.join(absoluteStartPath, 'localFile.txt');

expect(result).to.equal(expected);
});

it('returns undefined when file not found', () => {
const startPath = path.join(session.project.dir, 'level1', 'level2', 'startDir');
const result = searchUp(startPath, 'nonexistent.txt');
const relativeStartPath = path.relative(
session.project.dir,
path.join(session.project.dir, 'level1', 'level2', 'startDir')
);
expect(path.isAbsolute(relativeStartPath)).to.be.false;
const result = searchUp(relativeStartPath, 'nonexistent.txt');

expect(result).to.be.undefined;
});

it('works when starting from file path', () => {
const filePath = path.join(session.project.dir, 'level1', 'level2', 'startDir', 'someFile.txt');
fs.writeFileSync(filePath, 'content');
const result = searchUp(filePath, 'target.txt');
const relativeFilePath = path.relative(
session.project.dir,
path.join(session.project.dir, 'level1', 'level2', 'startDir', 'someFile.txt')
);
expect(path.isAbsolute(relativeFilePath)).to.be.false;
const absoluteFilePath = path.resolve(session.project.dir, relativeFilePath);
fs.writeFileSync(absoluteFilePath, 'content');
const result = searchUp(relativeFilePath, 'target.txt');
const expected = path.join(session.project.dir, 'level1', 'level2', 'target.txt');

expect(result).to.equal(expected);
Expand Down
25 changes: 24 additions & 1 deletion test/resolve/forceIgnore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,34 @@ describe('ForceIgnore', () => {

it('Should ignore files starting with a dot', () => {
const dotPath = join(root, '.xyz');

expect(forceIgnore.accepts(dotPath)).to.be.false;
expect(forceIgnore.denies(dotPath)).to.be.true;
});

it('Should NOT ignore .sf/orgs/<orgId>/remoteMetadata', () => {
const remoteMetadataPath = join(root, '.sf', 'orgs', '00D000000000000', 'remoteMetadata');
expect(forceIgnore.accepts(remoteMetadataPath)).to.be.true;
expect(forceIgnore.denies(remoteMetadataPath)).to.be.false;
});

it('Should NOT ignore stuff inside .sf/orgs/<orgId>/remoteMetadata', () => {
const remoteMetadataPath = join(root, '.sf', 'orgs', '00D000000000000', 'remoteMetadata', 'foo', 'bar');
expect(forceIgnore.accepts(remoteMetadataPath)).to.be.true;
expect(forceIgnore.denies(remoteMetadataPath)).to.be.false;
});

it('Should ignore .sf/orgs/<orgId>/anythingElse', () => {
const dotSfNotInRemoteMetadata = join(root, '.sf', 'orgs', '00D000000000000', 'foo');
expect(forceIgnore.accepts(dotSfNotInRemoteMetadata)).to.be.false;
expect(forceIgnore.denies(dotSfNotInRemoteMetadata)).to.be.true;
});

it('Should ignore .sf/anythingElse', () => {
const dotSfNotInRemoteMetadata = join(root, '.sf', 'foo');
expect(forceIgnore.accepts(dotSfNotInRemoteMetadata)).to.be.false;
expect(forceIgnore.denies(dotSfNotInRemoteMetadata)).to.be.true;
});

it('Should ignore files ending in .dup', () => {
const dupPath = join(root, 'abc.dup');

Expand Down
Loading