Skip to content

Commit

Permalink
feat: update imports generated for flutter datastore plugin dependency (
Browse files Browse the repository at this point in the history
#382) (#388)

* chore(amplify-codegen): change flutter import path from datastore to core (#380)

* feat(appsync-modelgen-plugin): Change flutter datastore models dependency to use amplify_core

* feat(appsync-modelgen-plugin): add amplify_flutter version check to determine datastore dependency import

* fix(appsync-modelgen-plugin): correct indentation for error message

* fix(appsync-modelgen-plugin): run linter

* fix(amplify-codegen): update unit tests

* fix(amplify-codegen): lower minimum version to 0.4.0-rc.1

* fix(appsync-modelgen-plugin): remove duplicate .dart from imports

Co-authored-by: Travis Sheppard <[email protected]>
Co-authored-by: Dane Pilcher <[email protected]>

Co-authored-by: Phani Srikar Edupuganti <[email protected]>
Co-authored-by: Travis Sheppard <[email protected]>
  • Loading branch information
3 people authored Feb 3, 2022
1 parent ec68b8e commit 329e513
Show file tree
Hide file tree
Showing 11 changed files with 1,046 additions and 358 deletions.
5 changes: 5 additions & 0 deletions packages/amplify-codegen/src/commands/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const gqlCodeGen = require('@graphql-codegen/core');
const { getModelgenPackage } = require('../utils/getModelgenPackage');
const { validateDartSDK } = require('../utils/validateDartSDK');
const { validateAmplifyFlutterCapableZeroThreeFeatures } = require('../utils/validateAmplifyFlutterCapableZeroThreeFeatures');
const { validateAmplifyFlutterCoreLibraryDependency } = require('../utils/validateAmplifyFlutterCoreLibraryDependency');

const platformToLanguageMap = {
android: 'java',
Expand Down Expand Up @@ -90,6 +91,7 @@ async function generateModels(context) {
let isTimestampFieldsAdded = readFeatureFlag('codegen.addTimestampFields');
let enableDartNullSafety = readFeatureFlag('codegen.enableDartNullSafety');
let enableDartZeroThreeFeatures = false;
let dartUpdateAmplifyCoreDependency = false;

if (projectConfig.frontend === 'flutter') {
const isMinimumDartVersionSatisfied = validateDartSDK(context, projectRoot);
Expand All @@ -107,6 +109,8 @@ async function generateModels(context) {
// override isTimestampFieldsAdded to true when using amplify-flutter > 0.3.0 || > 0.3.0-rc.2
isTimestampFieldsAdded = validateAmplifyFlutterCapableZeroThreeFeatures(projectRoot);
enableDartZeroThreeFeatures = validateAmplifyFlutterCapableZeroThreeFeatures(projectRoot);
// This feature is supported only for users using amplify-flutter > 0.4.0 || > 0.4.0-rc.1
dartUpdateAmplifyCoreDependency = validateAmplifyFlutterCoreLibraryDependency(projectRoot);
}

const handleListNullabilityTransparently = readFeatureFlag('codegen.handleListNullabilityTransparently');
Expand All @@ -124,6 +128,7 @@ async function generateModels(context) {
usePipelinedTransformer,
enableDartZeroThreeFeatures,
transformerVersion,
dartUpdateAmplifyCoreDependency
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,9 @@
const yaml = require('js-yaml');
const path = require('path');
const fs = require('fs-extra');
const semver = require('semver');
const { validateAmplifyFlutterVersion } = require('./validateAmplifyFlutterVersion');

const PUBSPEC_LOCK_FILE_NAME = 'pubspec.lock';
const MINIMUM_VERSION_CONSTRAIN = '>= 0.3.0 || >= 0.3.0-rc.2';
const MINIMUM_VERSION_CONSTRAINT = '>= 0.3.0 || >= 0.3.0-rc.2';

function validateAmplifyFlutterCapableZeroThreeFeatures(projectRoot) {
try {
const lockFile = yaml.load(fs.readFileSync(path.join(projectRoot, PUBSPEC_LOCK_FILE_NAME), 'utf8'));
// check resolved dependency version written pubspec.lock file
const { version } = lockFile.packages.amplify_flutter || {};
// For this util function it check only if the amplify_flutter version is great than the minimum version
// and it's not concerned with prerelease range, hence including prerelease to ensure
// 0.4.0-rc.2 > 0.3.0-rc.2 is true
if (semver.satisfies(version, MINIMUM_VERSION_CONSTRAIN, { includePrerelease: true })) {
return true;
}
return false;
} catch (e) {
if (e.stack) {
console.log(e.stack);
console.log(e.message);
}

console.log('An error occurred while parsing ' + PUBSPEC_LOCK_FILE_NAME + '.');
return false;
}
return validateAmplifyFlutterVersion(projectRoot, MINIMUM_VERSION_CONSTRAINT);
}

module.exports = { validateAmplifyFlutterCapableZeroThreeFeatures, PUBSPEC_LOCK_FILE_NAME, MINIMUM_VERSION_CONSTRAIN };
module.exports = { validateAmplifyFlutterCapableZeroThreeFeatures };
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { validateAmplifyFlutterVersion } = require('./validateAmplifyFlutterVersion');

const MINIMUM_VERSION_CONSTRAINT = '>= 0.4.0 || >= 0.4.0-rc.1';

function validateAmplifyFlutterCoreLibraryDependency(projectRoot) {
return validateAmplifyFlutterVersion(projectRoot, MINIMUM_VERSION_CONSTRAINT);
}

module.exports = { validateAmplifyFlutterCoreLibraryDependency };
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const yaml = require('js-yaml');
const path = require('path');
const fs = require('fs-extra');
const semver = require('semver');

const PUBSPEC_LOCK_FILE_NAME = 'pubspec.lock';

function validateAmplifyFlutterVersion(projectRoot, versionConstraint) {
try {
const lockFile = yaml.load(fs.readFileSync(path.join(projectRoot, PUBSPEC_LOCK_FILE_NAME), 'utf8'));
// check resolved dependency version written pubspec.lock file
const { version } = lockFile.packages.amplify_flutter || {};
// For this util function it check only if the amplify_flutter version satisfies the given version constraint
if (semver.satisfies(version, versionConstraint, { includePrerelease: true })) {
return true;
}
return false;
} catch (e) {
if (e.stack) {
console.log(e.stack);
console.log(e.message);
}

console.log('An error occurred while parsing ' + PUBSPEC_LOCK_FILE_NAME + '.');
return false;
}
}

module.exports = { validateAmplifyFlutterVersion, PUBSPEC_LOCK_FILE_NAME };
84 changes: 0 additions & 84 deletions packages/amplify-codegen/tests/commands/models.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const MOCK_PROJECT_ROOT = 'project';
const MOCK_PROJECT_NAME = 'myapp';
const MOCK_BACKEND_DIRECTORY = 'backend';
const MOCK_GENERATED_CODE = 'This code is auto-generated!';
const MOCK_PRE_EXISTING_FILE = 'preexisting.txt';

// Mock the Feature flag to use migrated moldegen
jest.mock('amplify-cli-core', MOCK_PROJECT_ROOT => {
Expand Down Expand Up @@ -109,89 +108,6 @@ describe('command-models-generates models in expected output path', () => {
afterEach(mockFs.restore);
});

describe('codegen models respects cleanGeneratedModelsDirectory', () => {
beforeEach(() => {
jest.resetAllMocks();
addMocksToContext();
graphqlCodegen.codegen.mockReturnValue(MOCK_GENERATED_CODE);
});

for (const frontend in OUTPUT_PATHS) {
it(frontend + ': Should clear the output directory before generation if cleanGeneratedModelsDirectory is true', async () => {
MOCK_CONTEXT.amplify.getProjectConfig.mockReturnValue({ frontend: frontend });
require('amplify-cli-core').FeatureFlags.getBoolean.mockImplementation((name, defaultValue) => {
if (name === 'codegen.useappsyncmodelgenplugin' || name === 'codegen.cleanGeneratedModelsDirectory') {
return true;
}
});

const outputDirectory = path.join(MOCK_PROJECT_ROOT, OUTPUT_PATHS[frontend]);
const preExistingFilePath = path.join(outputDirectory, MOCK_PRE_EXISTING_FILE);
createMockFS(outputDirectory);

// assert output directory has a mock file to be cleared
expect(fs.readdirSync(outputDirectory).length).toEqual(1);
expect(fs.existsSync(preExistingFilePath));

await generateModels(MOCK_CONTEXT);

// assert model generation succeeds
expect(graphqlCodegen.codegen).toBeCalled();

// assert that codegen generated in correct place
expect(fs.readdirSync(outputDirectory).length).toBeGreaterThan(0);

// assert that the pre-existing file is deleted
expect(fs.existsSync(preExistingFilePath)).toBeFalsy;
});

it(frontend + ': Should not clear the output directory before generation if cleanGeneratedModelsDirectory is false', async () => {
MOCK_CONTEXT.amplify.getProjectConfig.mockReturnValue({ frontend: frontend });
require('amplify-cli-core').FeatureFlags.getBoolean.mockImplementation((name, defaultValue) => {
if (name === 'codegen.useappsyncmodelgenplugin') {
return true;
}
if (name === 'codegen.cleanGeneratedModelsDirectory') {
return false;
}
});

const outputDirectory = path.join(MOCK_PROJECT_ROOT, OUTPUT_PATHS[frontend]);
const preExistingFilePath = path.join(outputDirectory, MOCK_PRE_EXISTING_FILE);
createMockFS(outputDirectory);

// assert output directory has a mock file to be cleared
expect(fs.readdirSync(outputDirectory).length).toEqual(1);
expect(fs.existsSync(preExistingFilePath));

await generateModels(MOCK_CONTEXT);

// assert model generation succeeds
expect(graphqlCodegen.codegen).toBeCalled();

// assert that codegen generated in correct place
expect(fs.readdirSync(outputDirectory).length).toBeGreaterThan(1);

// assert that the pre-existing file is retained
expect(fs.existsSync(preExistingFilePath)).toBeTruthy;
});
}

function createMockFS(outputDirectory) {
// mock the input and output file structure
const schemaFilePath = path.join(MOCK_BACKEND_DIRECTORY, 'api', MOCK_PROJECT_NAME);
const mockedFiles = {};
mockedFiles[schemaFilePath] = {
'schema.graphql': ' type SimpleModel { id: ID! status: String } ',
};
mockedFiles[outputDirectory] = {};
mockedFiles[outputDirectory][MOCK_PRE_EXISTING_FILE] = 'A pre-existing mock file';
mockFs(mockedFiles);
}

afterEach(mockFs.restore);
});

// Add models generation specific mocks to Amplify Context
function addMocksToContext() {
MOCK_CONTEXT.amplify.getEnvInfo.mockReturnValue({ projectPath: MOCK_PROJECT_ROOT });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
const {
validateAmplifyFlutterCapableZeroThreeFeatures,
PUBSPEC_LOCK_FILE_NAME,
MINIMUM_VERSION_CONSTRAIN,
validateAmplifyFlutterCapableZeroThreeFeatures
} = require('../../src/utils/validateAmplifyFlutterCapableZeroThreeFeatures');
const { PUBSPEC_LOCK_FILE_NAME } = require('../../src/utils/validateAmplifyFlutterVersion');
const mockFs = require('mock-fs');
const { join } = require('path');
const yaml = require('js-yaml');

const MOCK_PROJECT_ROOT = 'project';
const MOCK_PUBSPEC_FILE_PATH = join(MOCK_PROJECT_ROOT, PUBSPEC_LOCK_FILE_NAME);
const MINIMUM_VERSION_CONSTRAINT = '>= 0.3.0 || >= 0.3.0-rc.2';
global.console = {log: jest.fn()}
const mockErrorPrinter = console.log;

Expand All @@ -17,7 +17,7 @@ describe('Validate amplify flutter version tests', () => {
mockFs.restore();
});

describe(`should return true if the resolved version meets the version constrain: ${MINIMUM_VERSION_CONSTRAIN}`, () => {
describe(`should return true if the resolved version meets the version constrain: ${MINIMUM_VERSION_CONSTRAINT}`, () => {
['0.3.0', '0.3.1', '1.0.0', '0.3.0-rc.2', '0.4.0', '0.4.0-rc.2'].forEach(version => {
test(`when the resolved version is ${version}`, () => {
const lockFile = {
Expand All @@ -33,7 +33,7 @@ describe('Validate amplify flutter version tests', () => {
});
});

describe(`should return false if the resolved version does NOT meet the version constrain: ${MINIMUM_VERSION_CONSTRAIN}`, () => {
describe(`should return false if the resolved version does NOT meet the version constrain: ${MINIMUM_VERSION_CONSTRAINT}`, () => {
['0.2.0', '0.2.9', '0.3.0-rc.1'].forEach(version => {
test(`when the resolved version is ${version}`, () => {
const lockFile = {
Expand Down
Loading

0 comments on commit 329e513

Please sign in to comment.