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
32 changes: 32 additions & 0 deletions .github/scripts/prod-invocation/create-test-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { execSync } from 'child_process';

const TEST_APP_SOURCE_FILE_PATH = './integration-tests/test-application/test-app.js';
const TEST_APP_WASM_FILE_PATH = './integration-tests/test-application/test-app.wasm';

export default async ({ github, context, core }) => {
// Ensure this is running in GitHub Actions
if (!process.env.GITHUB_ENV) {
throw new Error(
'GITHUB_ENV is not defined. This script must be run in a GitHub Actions environment.',
);
}

const workspaceDir = process.env.GITHUB_WORKSPACE || process.cwd();

// Build the testAppcode into a wasm binary
const buildResponse = execSync(
'./bin/fastedge-build.js --input ' +
TEST_APP_SOURCE_FILE_PATH +
' --output ' +
TEST_APP_WASM_FILE_PATH,
{ encoding: 'utf8', cwd: workspaceDir },
);

core.info(`Build output: ${buildResponse}`);

if (!buildResponse.includes('Build success!!')) {
throw new Error('Failed to build test application into wasm binary');
}

core.info(`Test application built into wasm binary at ${TEST_APP_WASM_FILE_PATH}`);
};
64 changes: 64 additions & 0 deletions .github/scripts/prod-invocation/invoke-test-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const MAX_RETRIES = 3;
const INITIAL_WAIT_FOR_DEPLOYMENT_SECONDS = 15;
const RETRY_DELAY_SECONDS = 5;
const DATA_IS_VALID = 'DATA_IS_VALID';

const sleep = (secs = RETRY_DELAY_SECONDS) =>
new Promise((resolve) => setTimeout(resolve, secs * 1000));

const isResponseDataValid = (data, build_sha) => {
if (data.build_sha !== build_sha) {
return `prod environment build_sha mismatch: expected ${build_sha}, got ${data.build_sha}`;
}

return DATA_IS_VALID;
};

export default async ({ github, context, core }) => {
// Ensure this is running in GitHub Actions
if (!process.env.GITHUB_ENV) {
throw new Error(
'GITHUB_ENV is not defined. This script must be run in a GitHub Actions environment.',
);
}

const appUrl = process.env.APP_URL;
const build_sha = context.sha;

// Give the production environment some time to update with the new test application
await sleep(INITIAL_WAIT_FOR_DEPLOYMENT_SECONDS);

for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
// Pause between attempts
await sleep(RETRY_DELAY_SECONDS);
try {
const res = await fetch(appUrl);
if (res.status !== 200) {
throw new Error(`prod environment bad response: ${res.status}`);
}
const data = await res.json();
core.info(`Response data: ${JSON.stringify(data)}`);

// validate response data matches what we expect
const validationResult = isResponseDataValid(data, build_sha);
if (validationResult === DATA_IS_VALID) {
// Response is as we expected
break;
}

throw new Error(validationResult);
} catch (error) {
// Log the error and retry again after a delay
core.warning(`Attempt ${attempt} failed: ${error.message}`);

if (attempt === MAX_RETRIES) {
// If we've reached the max retries, re-throw an error to kill the workflow
throw new Error(
`Test application invocation failed after ${MAX_RETRIES} attempts: ${error.message}`,
);
}
}
}

core.info(`Test application invocation succeeded with status 200 and valid response data.`);
};
5 changes: 5 additions & 0 deletions .github/workflows/build-libs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ jobs:
if: steps.restore-build-cache.outputs.cache-hit != 'true'
run: npm run build:js

- name: Ensure bin files have execute permissions
shell: bash
run: |
chmod +x ./bin/*.js

- name: Run Integration Tests
run: npm run test:integration

Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,14 @@ jobs:
secrets:
VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }}

npm_release:
test_prod_invocation:
needs: [build_fastedge_artifacts]
uses: ./.github/workflows/prod-invocation.yaml
secrets:
VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }}

npm_release:
needs: [test_prod_invocation]
uses: ./.github/workflows/release.yaml
with:
dry_run: ${{ github.event.inputs.dry_run || 'true' }}
Expand Down
105 changes: 105 additions & 0 deletions .github/workflows/prod-invocation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: Build and run application

on:
workflow_call:
secrets:
VAULT_TOKEN:
required: true

jobs:
live-test-invocation:
runs-on: [self-hosted, ubuntu-22-04, regular]

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Setup Node Environment
uses: ./.github/setup-node

- name: Clean up test-app.wasm
shell: bash
run: |
rm -f ./integration-tests/test-application/test-app.wasm

- name: Restore build cache
id: restore-build-cache
uses: actions/cache/restore@v4
with:
path: |
lib/
bin/
types/
key: ${{ runner.os }}-libs-artifact-${{ github.sha }}

- name: Ensure build folders are valid
shell: bash
run: |
if [ ! -d "lib" ] || [ ! -d "bin" ] || [ ! -d "types" ]; then
echo "Build folders are missing. Please run the build-libs workflow before releasing."
exit 1
fi

- name: Create and build test application
uses: actions/github-script@v8
with:
script: |
const script = await import('${{ github.workspace }}/.github/scripts/prod-invocation/create-test-app.js')
await script.default({github, context, core})

- name: Import Secrets
uses: hashicorp/vault-action@v3
if: steps.restore-build-cache.outputs.cache-hit != 'true'
id: secrets
with:
url: https://puppet-vault.gc.onl
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/project_fastedge/team_account/prod token | PROD_GCORE_API_TOKEN ;
secret/project_fastedge/team_account/prod hostname | PROD_GCORE_API_HOSTNAME ;
secret/project_fastedge/team_account/preprod token | PREPROD_GCORE_API_TOKEN ;
secret/project_fastedge/team_account/preprod hostname | PREPROD_GCORE_API_HOSTNAME ;

- name: Decipher test environment from branch
id: env-check
shell: bash
run: |
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
echo "Run against production environment"
echo "is_prod=true" >> $GITHUB_OUTPUT
else
echo "Run in preprod environment"
echo "is_prod=false" >> $GITHUB_OUTPUT
fi

- name: Debug env-check
shell: bash
run: |
echo "is_prod ${{ steps.env-check.outputs.is_prod }}"

- name: Deploy Test App to Gcore
id: deploy-app
uses: gcore-github-actions/fastedge/deploy-app@v1
with:
api_key:
${{ steps.env-check.outputs.is_prod == 'true' &&
steps.secrets.outputs.PROD_GCORE_API_TOKEN ||
steps.secrets.outputs.PREPROD_GCORE_API_TOKEN }}
api_url:
${{ steps.env-check.outputs.is_prod == 'true' &&
steps.secrets.outputs.PROD_GCORE_API_HOSTNAME ||
steps.secrets.outputs.PREPROD_GCORE_API_HOSTNAME }}
wasm_file: integration-tests/test-application/test-app.wasm
app_name: 'fastedge-sdk-js-test-app'
comment: 'Deployed by prod-invocation workflow'
env: |
BUILD_SHA=${{ github.sha }}

- name: Invoke test application
uses: actions/github-script@v8
env:
APP_URL: ${{ steps.deploy-app.outputs.app_url }}
with:
script: |
const script = await import('${{ github.workspace }}/.github/scripts/prod-invocation/invoke-test-app.js')
await script.default({github, context, core})
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ bin/
dist/
lib/
integration-tests/test-files/output.wasm
integration-tests/test-application/test-app.wasm
# *.o
# *.d
/rusturl/
Expand Down
2 changes: 1 addition & 1 deletion config/eslint/repo/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = {
'dist/**',
'build/**',
'types/**',
'integration-tests/test-files/**',
'integration-tests/**',
'bin/**',
'lib/**',
'**/runtime/fastedge/**',
Expand Down
10 changes: 7 additions & 3 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ export default defineConfig({
starlight({
title: '@gcoredev/fastedge-sdk-js',
customCss: ['./src/styles/custom.css'],
social: {
github: 'https://github.com/G-Core/FastEdge-sdk-js',
},
social: [
{
icon: 'github',
label: 'GitHub',
href: 'https://github.com/G-Core/FastEdge-sdk-js',
},
],
sidebar: [
{
label: 'Getting Started',
Expand Down
4 changes: 2 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/starlight": "^0.26.1",
"astro": "^4.14.3",
"@astrojs/starlight": "^0.37.2",
"astro": "^5.15.9",
"sharp": "^0.34.5"
}
}
Empty file.
14 changes: 14 additions & 0 deletions integration-tests/test-application/test-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getEnv } from 'fastedge::env';

async function eventHandler(event) {
const build_sha = getEnv('BUILD_SHA');

return Response.json({
message: 'app running on production',
build_sha: `${build_sha}`,
});
}

addEventListener('fetch', (event) => {
event.respondWith(eventHandler(event));
});
Loading