Moved git clone to a helper functions and added tests for preparers (#2112)
This commit is contained in:
committed by
GitHub
parent
5f9f41b789
commit
f6826d9107
@@ -15,6 +15,12 @@
|
||||
*/
|
||||
import { DirectoryPreparer } from './dir';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { checkoutGitRepository } from './helpers';
|
||||
|
||||
jest.mock('./helpers', () => ({
|
||||
...jest.requireActual<{}>('./helpers'),
|
||||
checkoutGitRepository: jest.fn(() => '/tmp/backstage-repo/org/name/branch/'),
|
||||
}));
|
||||
|
||||
const logger = getVoidLogger();
|
||||
|
||||
@@ -59,4 +65,19 @@ describe('directory preparer', () => {
|
||||
'/our-documentation/techdocs',
|
||||
);
|
||||
});
|
||||
|
||||
it('should merge managed-by-location and techdocs-ref when managed-by-location is a git repository', async () => {
|
||||
const directoryPreparer = new DirectoryPreparer(logger);
|
||||
|
||||
const mockEntity = createMockEntity({
|
||||
'backstage.io/managed-by-location':
|
||||
'github:https://github.com/spotify/backstage/blob/master/catalog-info.yaml',
|
||||
'backstage.io/techdocs-ref': 'dir:./docs',
|
||||
});
|
||||
|
||||
expect(await directoryPreparer.prepare(mockEntity)).toEqual(
|
||||
'/tmp/backstage-repo/org/name/branch/docs',
|
||||
);
|
||||
expect(checkoutGitRepository).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,14 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import { PreparerBase } from './types';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import path from 'path';
|
||||
import { parseReferenceAnnotation } from './helpers';
|
||||
import { parseReferenceAnnotation, checkoutGitRepository } from './helpers';
|
||||
import { InputError } from '@backstage/backend-common';
|
||||
import { Clone } from 'nodegit';
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
@@ -31,41 +28,6 @@ export class DirectoryPreparer implements PreparerBase {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
private async cloneGithubRepo(entity: Entity) {
|
||||
const { type, target } = parseReferenceAnnotation(
|
||||
'backstage.io/managed-by-location',
|
||||
entity,
|
||||
);
|
||||
|
||||
if (type !== 'github') {
|
||||
throw new InputError(`Wrong target type: ${type}, should be 'github'`);
|
||||
}
|
||||
|
||||
const parsedGitLocation = parseGitUrl(target);
|
||||
const repositoryTmpPath = path.join(
|
||||
// fs.realpathSync fixes a problem with macOS returning a path that is a symlink
|
||||
fs.realpathSync(os.tmpdir()),
|
||||
'backstage-repo',
|
||||
parsedGitLocation.source,
|
||||
parsedGitLocation.owner,
|
||||
parsedGitLocation.name,
|
||||
parsedGitLocation.ref,
|
||||
);
|
||||
if (fs.existsSync(repositoryTmpPath)) {
|
||||
return repositoryTmpPath;
|
||||
}
|
||||
const repositoryCheckoutUrl = parsedGitLocation.toString('https');
|
||||
|
||||
this.logger.debug(
|
||||
`[TechDocs] Checking out repository ${repositoryCheckoutUrl} to ${repositoryTmpPath}`,
|
||||
);
|
||||
|
||||
fs.mkdirSync(repositoryTmpPath, { recursive: true });
|
||||
await Clone.clone(repositoryCheckoutUrl, repositoryTmpPath, {});
|
||||
|
||||
return repositoryTmpPath;
|
||||
}
|
||||
|
||||
private async resolveManagedByLocationToDir(entity: Entity) {
|
||||
const { type, target } = parseReferenceAnnotation(
|
||||
'backstage.io/managed-by-location',
|
||||
@@ -78,7 +40,7 @@ export class DirectoryPreparer implements PreparerBase {
|
||||
switch (type) {
|
||||
case 'github': {
|
||||
const parsedGitLocation = parseGitUrl(target);
|
||||
const repoLocation = await this.cloneGithubRepo(entity);
|
||||
const repoLocation = await checkoutGitRepository(target);
|
||||
|
||||
return path.dirname(
|
||||
path.join(repoLocation, parsedGitLocation.filepath),
|
||||
|
||||
@@ -13,15 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { InputError } from '@backstage/backend-common';
|
||||
import { PreparerBase } from './types';
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
import { Clone } from 'nodegit';
|
||||
import { parseReferenceAnnotation } from './helpers';
|
||||
import { parseReferenceAnnotation, checkoutGitRepository } from './helpers';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
export class GithubPreparer implements PreparerBase {
|
||||
@@ -41,32 +38,14 @@ export class GithubPreparer implements PreparerBase {
|
||||
throw new InputError(`Wrong target type: ${type}, should be 'github'`);
|
||||
}
|
||||
|
||||
const parsedGitLocation = parseGitUrl(target);
|
||||
const repositoryTmpPath = path.join(
|
||||
// fs.realpathSync fixes a problem with macOS returning a path that is a symlink
|
||||
fs.realpathSync(os.tmpdir()),
|
||||
'backstage-repo',
|
||||
parsedGitLocation.source,
|
||||
parsedGitLocation.owner,
|
||||
parsedGitLocation.name,
|
||||
parsedGitLocation.ref,
|
||||
);
|
||||
try {
|
||||
const repoPath = await checkoutGitRepository(target);
|
||||
|
||||
if (fs.existsSync(repositoryTmpPath)) {
|
||||
this.logger.debug(
|
||||
`[TechDocs] Found repository already checked out at ${repositoryTmpPath}`,
|
||||
);
|
||||
return path.join(repositoryTmpPath, parsedGitLocation.filepath);
|
||||
const parsedGitLocation = parseGitUrl(target);
|
||||
return path.join(repoPath, parsedGitLocation.filepath);
|
||||
} catch (error) {
|
||||
this.logger.debug(`Repo checkout failed with error ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
const repositoryCheckoutUrl = parsedGitLocation.toString('https');
|
||||
|
||||
this.logger.debug(
|
||||
`[TechDocs] Checking out repository ${repositoryCheckoutUrl} to ${repositoryTmpPath}`,
|
||||
);
|
||||
|
||||
fs.mkdirSync(repositoryTmpPath, { recursive: true });
|
||||
await Clone.clone(repositoryCheckoutUrl, repositoryTmpPath, {});
|
||||
|
||||
return path.join(repositoryTmpPath, parsedGitLocation.filepath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { InputError } from '@backstage/backend-common';
|
||||
import { RemoteProtocol } from './types';
|
||||
import parseGitUrl from 'git-url-parse';
|
||||
import { Clone } from 'nodegit';
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
export type ParsedLocationAnnotation = {
|
||||
type: RemoteProtocol;
|
||||
@@ -52,3 +57,33 @@ export const parseReferenceAnnotation = (
|
||||
target,
|
||||
};
|
||||
};
|
||||
|
||||
export const clearGithubRepositoryCache = () => {
|
||||
fs.removeSync(path.join(fs.realpathSync(os.tmpdir()), 'backstage-repo'));
|
||||
};
|
||||
|
||||
export const checkoutGitRepository = async (
|
||||
repoUrl: string,
|
||||
): Promise<string> => {
|
||||
const parsedGitLocation = parseGitUrl(repoUrl);
|
||||
|
||||
const repositoryTmpPath = path.join(
|
||||
// fs.realpathSync fixes a problem with macOS returning a path that is a symlink
|
||||
fs.realpathSync(os.tmpdir()),
|
||||
'backstage-repo',
|
||||
parsedGitLocation.source,
|
||||
parsedGitLocation.owner,
|
||||
parsedGitLocation.name,
|
||||
parsedGitLocation.ref,
|
||||
);
|
||||
|
||||
if (fs.existsSync(repositoryTmpPath)) {
|
||||
return repositoryTmpPath;
|
||||
}
|
||||
const repositoryCheckoutUrl = parsedGitLocation.toString('https');
|
||||
|
||||
fs.mkdirSync(repositoryTmpPath, { recursive: true });
|
||||
await Clone.clone(repositoryCheckoutUrl, repositoryTmpPath, {});
|
||||
|
||||
return repositoryTmpPath;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user