Skip to content

Commit

Permalink
feat: support e2e workflow on codebuild
Browse files Browse the repository at this point in the history
  • Loading branch information
phani-srikar committed Jul 13, 2023
1 parent ee9ac44 commit b435d50
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 36 deletions.
27 changes: 18 additions & 9 deletions .codebuild/e2e_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
version: 0.2
env:
shell: bash
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
batch:
fast-fail: false
build-graph:
Expand All @@ -28,11 +28,20 @@ batch:
compute-type: BUILD_GENERAL1_MEDIUM
depend-on:
- build_linux
- identifier: build_app_swift
buildspec: .codebuild/run_ios_modelgen_e2e_test.yml
env:
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: src/__tests__/build-app-swift.test.ts
CLI_REGION: us-east-2
depend-on:
- publish_to_local_registry
- identifier: >-
add_codegen_ios_configure_codegen_android_configure_codegen_js_graphql_codegen_android
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/add-codegen-ios.test.ts|src/__tests__/configure-codegen-android.test.ts|src/__tests__/configure-codegen-js.test.ts|src/__tests__/graphql-codegen-android.test.ts
Expand All @@ -43,7 +52,7 @@ batch:
graphql_codegen_js_remove_codegen_android_remove_codegen_ios_add_codegen_android
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/graphql-codegen-js.test.ts|src/__tests__/remove-codegen-android.test.ts|src/__tests__/remove-codegen-ios.test.ts|src/__tests__/add-codegen-android.test.ts
Expand All @@ -54,7 +63,7 @@ batch:
configure_codegen_ios_datastore_modelgen_android_datastore_modelgen_js_feature_flags
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/configure-codegen-ios.test.ts|src/__tests__/datastore-modelgen-android.test.ts|src/__tests__/datastore-modelgen-js.test.ts|src/__tests__/feature-flags.test.ts
Expand All @@ -65,7 +74,7 @@ batch:
graphql_codegen_ios_add_codegen_js_datastore_modelgen_ios_remove_codegen_js
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/graphql-codegen-ios.test.ts|src/__tests__/add-codegen-js.test.ts|src/__tests__/datastore-modelgen-ios.test.ts|src/__tests__/remove-codegen-js.test.ts
Expand All @@ -76,7 +85,7 @@ batch:
datastore_modelgen_flutter_env_codegen_model_introspection_codegen_pull_codegen
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/datastore-modelgen-flutter.test.ts|src/__tests__/env-codegen.test.ts|src/__tests__/model-introspection-codegen.test.ts|src/__tests__/pull-codegen.test.ts
Expand All @@ -87,7 +96,7 @@ batch:
push_codegen_ios_push_codegen_android_graphql_documents_generator_push_codegen_js
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: >-
src/__tests__/push-codegen-ios.test.ts|src/__tests__/push-codegen-android.test.ts|src/__tests__/graphql-documents-generator.test.ts|src/__tests__/push-codegen-js.test.ts
Expand All @@ -97,7 +106,7 @@ batch:
- identifier: build_app_ts
buildspec: .codebuild/run_e2e_tests.yml
env:
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: src/__tests__/build-app-ts.test.ts
CLI_REGION: ap-southeast-1
Expand All @@ -106,7 +115,7 @@ batch:
- identifier: cleanup_e2e_resources
buildspec: .codebuild/cleanup_e2e_resources.yml
env:
compute-type: BUILD_GENERAL1_SMALL
compute-type: BUILD_GENERAL1_MEDIUM
depend-on:
- >-
add_codegen_ios_configure_codegen_android_configure_codegen_js_graphql_codegen_android
11 changes: 10 additions & 1 deletion .codebuild/e2e_workflow_base.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 0.2
env:
shell: bash
compute-type: BUILD_GENERAL1_MEDIUM
compute-type: BUILD_GENERAL1_LARGE

batch:
fast-fail: false
Expand All @@ -28,3 +28,12 @@ batch:
compute-type: BUILD_GENERAL1_MEDIUM
depend-on:
- build_linux
- identifier: build_app_swift
buildspec: .codebuild/run_ios_modelgen_e2e_test.yml
env:
compute-type: BUILD_GENERAL1_LARGE
variables:
TEST_SUITE: src/__tests__/build-app-swift.test.ts
CLI_REGION: us-east-2
depend-on:
- publish_to_local_registry
5 changes: 1 addition & 4 deletions .codebuild/run_e2e_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ env:
CI: true
CODEBUILD: true
NODE_OPTIONS: --max-old-space-size=8096
# mock values to test artifact scanning
ENV_VAR_WITH_SECRETS: 'MOCK_ENV_VAR_FOR_SCANNING_SECRETS'
MOCK_ENV_VAR_FOR_SCANNING_SECRETS: 'abc123xyz'

phases:
build:
commands:
# you can provide a codebuild source version to use old cache and skip all other jobs :)
- source ./shared-scripts.sh && _runE2ETestsLinux
post_build:
commands:
Expand Down
27 changes: 27 additions & 0 deletions .codebuild/run_ios_modelgen_e2e_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: 0.2
env:
shell: bash
variables:
AMPLIFY_DIR: /root/.npm-global/lib/node_modules/@aws-amplify/cli-internal/bin
AMPLIFY_PATH: /root/.npm-global/lib/node_modules/@aws-amplify/cli-internal/bin/amplify
CI: true
CODEBUILD: true
NODE_OPTIONS: --max-old-space-size=8096
phases:
build:
commands:
- source ./shared-scripts.sh && _runE2ETestsLinux
- export PATH_TO_MODELS=$CODEBUILD_SRC_DIR/packages/amplify-codegen-e2e-tests/test-apps/swift/amplify/generated
- cd $PATH_TO_MODELS && zip -r models.zip models
- aws s3 cp $PATH_TO_MODELS/models.zip s3://$ARTIFACT_BUCKET_NAME/models.zip
- export MODELS_S3_URL=$(aws s3 presign s3://$ARTIFACT_BUCKET_NAME/models.zip --expires-in 3600)
- cd $CODEBUILD_SRC_DIR && ./.codebuild/scripts/run-ios-modelgen-e2e-test.sh
post_build:
commands:
- aws sts get-caller-identity
- source ./shared-scripts.sh && _scanArtifacts

artifacts:
files:
- $CODEBUILD_SRC_DIR/packages/amplify-codegen-e2e-tests/amplify-e2e-reports/*
discard-paths: yes
68 changes: 68 additions & 0 deletions .codebuild/scripts/run-ios-modelgen-e2e-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash

REPO_OWNER="aws-amplify"
REPO_NAME="amplify-codegen"

# Function to get the latest workflow run ID
get_latest_run_id() {
latest_run_id=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/actions/runs?event=workflow_dispatch&per_page=1" | \
jq -r '.workflow_runs[0].id')
echo "$latest_run_id"
}

# Function to get the status of a workflow run
get_run_status() {
run_id="$1"
run_status=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/actions/runs/$run_id" | \
jq -r '.status')
echo "$run_status"
}

# Function to trigger a workflow dispatch event to run the e2e test
trigger_workflow() {
curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/actions/workflows/build-swift-modelgen.yml/dispatches" \
-d "{\"ref\":\"main\", \"inputs\":{\"MODELS_S3_URL\":\"${MODELS_S3_URL}\"}}"
}

main() {
trigger_workflow
sleep 10 # Wait to allow for the workflow to be triggered

# Get the latest run ID and initial status
latest_run_id=$(get_latest_run_id)
echo "Latest run ID: $latest_run_id"
latest_status=$(get_run_status "$latest_run_id")
timeout=$((SECONDS + 600)) # 600 seconds = 10 minutes

# Continuously check for status until completion
while [[ "$latest_status" != "completed" && "$SECONDS" -lt "$timeout" ]]; do
echo "Test run status: $latest_status"
sleep 10 # Wait before checking again
latest_status=$(get_run_status "$latest_run_id")
done

# Check if the run completed within the specified duration
if [[ "$latest_status" != "completed" ]]; then
echo "The test run did not complete within the specified duration."
exit 1
fi

# Check if the run failed and throw an error if it did
if [[ "$latest_status" == "failure" ]]; then
echo "The test run failed."
exit 1
else
echo "The test run succeeded."
fi
}

main
6 changes: 5 additions & 1 deletion packages/amplify-codegen-e2e-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@
"rimraf": "^3.0.0",
"strip-ansi": "^6.0.0",
"throat": "^5.0.0",
"uuid": "7.0.1"
"uuid": "7.0.1",
"ini": "^3.0.1"
},
"devDependencies": {
"@types/ini": "^1.3.31"
},
"peerDependencies": {
"@aws-amplify/amplify-cli-core": "^4.0.0",
Expand Down
14 changes: 14 additions & 0 deletions packages/amplify-codegen-e2e-core/src/categories/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,20 @@ export function generateModelIntrospection(cwd: string, settings: { outputDir?:
});
}

export function generateModelIntrospectionWithError(cwd: string, errMessage: string, settings: { outputDir?: string} = {}): Promise<void> {
return new Promise((resolve, reject) => {
spawn(getCLIPath(), ['codegen', 'model-introspection', '--output-dir', settings.outputDir ?? ''], { cwd, stripColors: true })
.wait(errMessage)
.run((err: Error) => {
if (!err) {
resolve();
} else {
reject(err);
}
});
});
}

// CLI workflow to add codegen to non-Amplify JS project
export function addCodegenNonAmplifyJS(cwd: string): Promise<void> {
return new Promise((resolve, reject) => {
Expand Down
11 changes: 10 additions & 1 deletion packages/amplify-codegen-e2e-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import * as path from 'path';
import * as fs from 'fs-extra';
import { spawnSync, execSync } from 'child_process';
import { v4 as uuid } from 'uuid';
import * as ini from 'ini';
import { pathManager } from '@aws-amplify/amplify-cli-core';

export * from './configure/';
export * from './init/';
Expand All @@ -29,7 +31,14 @@ export function getCLIPath(testingWithLatestCodebase = false) {
}

export function isCI(): boolean {
return process.env.CI && process.env.CIRCLECI ? true : false;
return process.env.CI && (process.env.CIRCLECI || process.env.CODEBUILD) ? true : false;
}

export function injectSessionToken(profileName: string) {
const credentialsContents = ini.parse(fs.readFileSync(pathManager.getAWSCredentialsFilePath()).toString());
credentialsContents[profileName] = credentialsContents[profileName] || {};
credentialsContents[profileName].aws_session_token = process.env.AWS_SESSION_TOKEN;
fs.writeFileSync(pathManager.getAWSCredentialsFilePath(), ini.stringify(credentialsContents));
}

export function npmInstall(cwd: string) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import {
initProjectWithQuickstart,
DEFAULT_IOS_CONFIG,
addApiWithBlankSchemaAndConflictDetection,
updateApiSchemaWithText,
generateModels,
swiftBuild,
} from '@aws-amplify/amplify-codegen-e2e-core';
const { schemas } = require('@aws-amplify/graphql-schema-test-library');
import { existsSync, writeFileSync, readdirSync, rmSync, readFileSync } from 'fs';
import { writeFileSync, readdirSync, readFileSync } from 'fs';
import path from 'path';

const skip = new Set([
Expand All @@ -30,31 +28,25 @@ describe('build app - Swift', () => {
});

afterEach(async () => {
await rmSync(path.join(projectRoot, 'amplify', 'generated', 'models'), { recursive: true, force: true });
writeFileSync(path.join(projectRoot, 'swift.xcodeproj', 'project.pbxproj'), projectPBXProjCache);
});

Object.entries(schemas).forEach(([schemaName, schema]) => {
// @ts-ignore
const testName = `builds with ${schemaName}: ${schema.description}`;
const schemaFolderName = schemaName.replace(/[^a-zA-Z0-9]/g, '');
const outputDir = path.join(projectRoot, 'amplify', 'generated', 'models', schemaFolderName);
const testFunction = async () => {
// @ts-ignore
const schemaText = `input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }\n${schema.sdl}`;
console.log(schemaText); // log so that circleci does not timeout
updateApiSchemaWithText(projectRoot, 'amplifyDatasource', schemaText);
await generateModels(projectRoot);
await swiftBuild(projectRoot, { ...config, scheme: 'swift' });
await generateModels(projectRoot, outputDir);
};
if (skip.has(schemaName)) {
it.skip(testName, testFunction);
} else {
it(testName, testFunction);
}
});

it('fails build with syntax error', async () => {
await generateModels(projectRoot);
await writeFileSync(path.join(projectRoot, 'amplify', 'generated', 'models', 'AmplifyModels.swift'), 'foo\nbar');
await expect(swiftBuild(projectRoot, { ...config })).rejects.toThrowError();
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addApiWithoutSchema, createNewProjectDir, generateModelIntrospection, initJSProjectWithProfile, updateApiSchema } from "@aws-amplify/amplify-codegen-e2e-core";
import { addApiWithoutSchema, createNewProjectDir, generateModelIntrospection, initJSProjectWithProfile, updateApiSchema, generateModelIntrospectionWithError } from "@aws-amplify/amplify-codegen-e2e-core";
import { deleteAmplifyProject } from '../codegen-tests-base';
import { isNotEmptyDir } from "../utils";
import { join } from 'path';
Expand Down Expand Up @@ -35,7 +35,7 @@ describe('Model Introspection Codegen test', () => {
await addApiWithoutSchema(projectRoot, { apiName });
await updateApiSchema(projectRoot, apiName, schema);
//generate introspection schema
await expect(generateModelIntrospection(projectRoot)).rejects.toThrowError();
await generateModelIntrospectionWithError(projectRoot, 'Expected --output-dir flag to be set');
});

it('should throw error if the GraphQL schema is invalid', async () => {
Expand All @@ -46,7 +46,7 @@ describe('Model Introspection Codegen test', () => {
await updateApiSchema(projectRoot, apiName, invalidSchema);
const outputDir = 'output';
//generate introspection schema
await expect(generateModelIntrospection(projectRoot, { outputDir })).rejects.toThrowError();
await generateModelIntrospectionWithError(projectRoot, 'Unknown type', { outputDir });
});

it(`should handle a schema with connected PK`, async () => {
Expand Down
9 changes: 7 additions & 2 deletions packages/amplify-codegen-e2e-tests/src/configure_tests.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { amplifyConfigure as configure, isCI } from '@aws-amplify/amplify-codegen-e2e-core';
import { amplifyConfigure as configure, injectSessionToken, isCI } from '@aws-amplify/amplify-codegen-e2e-core';

async function setupAmplify() {
if (isCI()) {
Expand All @@ -11,9 +11,13 @@ async function setupAmplify() {
await configure({
accessKeyId: AWS_ACCESS_KEY_ID,
secretAccessKey: AWS_SECRET_ACCESS_KEY,
profileName: 'e2e-test-user',
profileName: 'amplify-integ-test-user',
region: REGION,
});

if (process.env.AWS_SESSION_TOKEN) {
injectSessionToken('amplify-integ-test-user');
}
}
else {
console.log('AWS Profile is already configured');
Expand All @@ -27,4 +31,5 @@ process.nextTick(async () => {
console.log(e.stack);
process.exit(1);
}
process.exit();
});
Loading

0 comments on commit b435d50

Please sign in to comment.