Skip to content

Commit

Permalink
Merge branch 'master' of github.com:apptension/saas-boilerplate into …
Browse files Browse the repository at this point in the history
…feature/rewrite-graphql-subscriptions
  • Loading branch information
pziemkowski committed Feb 27, 2024
2 parents cec80ef + d50c53b commit f2ded1f
Show file tree
Hide file tree
Showing 17 changed files with 133 additions and 30 deletions.
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@graphql-codegen/cli": "^5.0.0",
"@graphql-typed-document-node/core": "^3.2.0",
"@nx/devkit": "17.1.3",
"@nx/eslint": "17.1.3",
"@nx/eslint-plugin": "17.1.3",
"@nx/jest": "17.1.3",
"@nx/js": "17.1.3",
Expand Down Expand Up @@ -83,8 +84,7 @@
"vite": "^4.5.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-svgr": "^3.3.0",
"vite-tsconfig-paths": "^4.2.1",
"@nx/eslint": "17.1.3"
"vite-tsconfig-paths": "^4.2.1"
},
"dependencies": {
"@aws-sdk/client-cloudformation": "^3.462.0",
Expand Down Expand Up @@ -113,5 +113,10 @@
"react-router-dom": "6.16.0",
"regenerator-runtime": "^0.14.0",
"styled-components": "6.0.8"
},
"pnpm": {
"patchedDependencies": {
"[email protected]": "patches/[email protected]"
}
}
}
3 changes: 2 additions & 1 deletion packages/backend/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const AWS_DEFAULT_REGION = process.env.AWS_DEFAULT_REGION;
const PROJECT_NAME = process.env.PROJECT_NAME;
const VERSION = process.env.VERSION;
const SB_MIRROR_REPOSITORY = process.env.SB_MIRROR_REPOSITORY ?? '';
const SB_PULL_THROUGH_CACHE_REPOSITORY = process.env.SB_PULL_THROUGH_CACHE_REPOSITORY ?? '';
const SB_PULL_THROUGH_CACHE_REPOSITORY =
process.env.SB_PULL_THROUGH_CACHE_REPOSITORY ?? '';

const stsClient = new STSClient();

Expand Down
17 changes: 17 additions & 0 deletions packages/infra/infra-core/src/lib/env-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ declare const process: {
SB_TOOLS_HOSTED_ZONE_NAME: string;
SB_TOOLS_HOSTED_ZONE_ID: string;
SB_TOOLS_DOMAIN_VERSION_MATRIX: string;
SB_CI_MODE: string;
};
};

Expand Down Expand Up @@ -64,6 +65,15 @@ interface WebAppConfig {
envVariables: EnvironmentVariables;
}

export enum CI_MODE {
PARALLEL = 'parallel',
SIMPLE = 'simple',
}

interface CIConfig {
mode: CI_MODE;
}

export interface EnvironmentSettings {
appBasicAuth: string | null | undefined;
deployBranches: Array<string>;
Expand All @@ -77,11 +87,13 @@ export interface EnvironmentSettings {
version: string;
webAppEnvVariables: EnvironmentVariables;
certificates: CertificatesConfig;
CIConfig: CIConfig;
}

interface ConfigFileContent {
toolsConfig: ToolsConfig;
webAppConfig: WebAppConfig;
CIConfig: CIConfig;
}

export interface EnvConfigFileContent {
Expand Down Expand Up @@ -109,6 +121,10 @@ async function readConfig(): Promise<ConfigFileContent> {
versionMatrix: process.env.SB_TOOLS_DOMAIN_VERSION_MATRIX,
},
},
CIConfig: {
mode: process.env.SB_CI_MODE === CI_MODE.SIMPLE
? CI_MODE.SIMPLE : CI_MODE.PARALLEL,
}
};
}

Expand Down Expand Up @@ -176,5 +192,6 @@ export async function loadEnvSettings(): Promise<EnvironmentSettings> {
...(envConfig?.webAppConfig?.envVariables || {}),
},
certificates: envConfig.certificates,
CIConfig: config.CIConfig,
};
}
11 changes: 11 additions & 0 deletions packages/infra/infra-core/src/lib/patterns/serviceCiConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Construct } from 'constructs';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import { EnvConstructProps } from '../constructs';
import { CI_MODE } from '../env-config';
import { IStage } from 'aws-cdk-lib/aws-codepipeline';

export interface IServiceCiConfig {
defaultEnvVariables: {
Expand All @@ -22,9 +24,11 @@ export enum PnpmWorkspaceFilters {
export class ServiceCiConfig extends Construct implements IServiceCiConfig {
defaultEnvVariables: { [p: string]: codebuild.BuildEnvironmentVariable };
defaultCachePaths: string[];
props: EnvConstructProps;

constructor(scope: Construct, id: string, props: EnvConstructProps) {
super(scope, id);
this.props = props;

this.defaultEnvVariables = {
CI: {
Expand Down Expand Up @@ -69,4 +73,11 @@ export class ServiceCiConfig extends Construct implements IServiceCiConfig {
'export AWS_SESSION_TOKEN=$(echo "${TEMP_ROLE}" | jq -r \'.Credentials.SessionToken\')',
];
}

protected getRunOrder(stage: IStage, defaultRunOrder?: number) {
if (this.props.envSettings.CIConfig.mode === CI_MODE.PARALLEL) {
return defaultRunOrder;
}
return stage.actions.length + 1;
}
}
17 changes: 9 additions & 8 deletions packages/infra/infra-shared/src/stacks/ci/ciBackend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,25 @@ export class BackendCiConfig extends ServiceCiConfig {
),
);

const apiDeployProject = this.createApiDeployProject(props);
const migrationsDeployProject = this.createMigrationsDeployProject(props);
props.deployStage.addAction(
this.createDeployAction(
'api',
'migrations',
{
project: apiDeployProject,
runOrder: 2,
project: migrationsDeployProject,
runOrder: this.getRunOrder(props.deployStage, 2),
},
props,
),
);

const migrationsDeployProject = this.createMigrationsDeployProject(props);
const apiDeployProject = this.createApiDeployProject(props);
props.deployStage.addAction(
this.createDeployAction(
'migrations',
'api',
{
project: migrationsDeployProject,
runOrder: 2,
project: apiDeployProject,
runOrder: this.getRunOrder(props.deployStage, 2),
},
props,
),
Expand All @@ -72,6 +72,7 @@ export class BackendCiConfig extends ServiceCiConfig {
actionName: `${props.envSettings.projectEnvName}-build-${name}`,
project: actionProps.project,
input: props.inputArtifact,
runOrder: this.getRunOrder(props.buildStage),
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/infra/infra-shared/src/stacks/ci/ciComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class ComponentsCiConfig extends ServiceCiConfig {
project: actionProps.project,
actionName: `${props.envSettings.projectEnvName}-deploy-components`,
input: props.inputArtifact,
runOrder: 1,
runOrder: this.getRunOrder(props.deployStage, 1),
});
}

Expand Down
3 changes: 2 additions & 1 deletion packages/infra/infra-shared/src/stacks/ci/ciDocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class DocsCiConfig extends ServiceCiConfig {
{
project: deployProject,
input: buildArtifact,
runOrder: 2,
runOrder: this.getRunOrder(props.deployStage, 2),
},
props,
),
Expand All @@ -61,6 +61,7 @@ export class DocsCiConfig extends ServiceCiConfig {
>{
...actionProps,
actionName: `${props.envSettings.projectEnvName}-build-docs`,
runOrder: this.getRunOrder(props.buildStage)
});
}

Expand Down
16 changes: 9 additions & 7 deletions packages/infra/infra-shared/src/stacks/ci/ciPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,27 @@ export class CiPipeline extends Construct {
inputArtifact: sourceOutputArtifact,
});

new DocsCiConfig(this, 'DocsConfig', {
new ServerlessCiConfig(this, 'WorkersConfig', {
envSettings: props.envSettings,
buildStage,
deployStage,
inputArtifact: sourceOutputArtifact,
});

new ServerlessCiConfig(this, 'WorkersConfig', {
new DocsCiConfig(this, 'DocsConfig', {
envSettings: props.envSettings,
buildStage,
deployStage,
inputArtifact: sourceOutputArtifact,
});

new UploadVersionCiConfig(this, 'UploadVersionConfig', {
envSettings: props.envSettings,
stage: deployStage,
inputArtifact: sourceOutputArtifact,
});
if (props.envSettings.tools.enabled) {
new UploadVersionCiConfig(this, 'UploadVersionConfig', {
envSettings: props.envSettings,
stage: deployStage,
inputArtifact: sourceOutputArtifact,
});
}
}

private selectStage(name: string, pipeline: Pipeline) {
Expand Down
3 changes: 2 additions & 1 deletion packages/infra/infra-shared/src/stacks/ci/ciServerless.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class ServerlessCiConfig extends ServiceCiConfig {
{
project: deployProject,
input: buildArtifact,
runOrder: 2,
runOrder: this.getRunOrder(props.buildStage, 2),
},
props,
),
Expand All @@ -61,6 +61,7 @@ export class ServerlessCiConfig extends ServiceCiConfig {
>{
...actionProps,
actionName: `${props.envSettings.projectEnvName}-build-workers`,
runOrder: this.getRunOrder(props.deployStage),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class UploadVersionCiConfig extends ServiceCiConfig {
{
project: deployProject,
input: props.inputArtifact,
runOrder: 3,
runOrder: this.getRunOrder(props.stage, 3),
},
props
)
Expand Down
3 changes: 2 additions & 1 deletion packages/infra/infra-shared/src/stacks/ci/ciWebApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class WebappCiConfig extends ServiceCiConfig {
{
project: deployProject,
input: buildArtifact,
runOrder: 2,
runOrder: this.getRunOrder(props.deployStage, 2),
},
props,
),
Expand All @@ -61,6 +61,7 @@ export class WebappCiConfig extends ServiceCiConfig {
>{
...actionProps,
actionName: `${props.envSettings.projectEnvName}-build-webapp`,
runOrder: this.getRunOrder(props.buildStage)
});
}

Expand Down
4 changes: 4 additions & 0 deletions packages/internal/cli/src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export async function loadVersionEnv() {
return version;
}

export const disableNxEnvFiles = () => {
process.env.NX_LOAD_DOT_ENV_FILES = 'false';
};

export async function validateStageEnv() {
return envalid.cleanEnv(process.env, {
PROJECT_NAME: envalid.str({
Expand Down
3 changes: 2 additions & 1 deletion packages/internal/cli/src/config/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from '@oclif/core';
import { color } from '@oclif/color';
import { trace } from '@opentelemetry/api';

import { ENV_STAGE_LOCAL, getRootPath, loadVersionEnv } from './env';
import { ENV_STAGE_LOCAL, getRootPath, loadVersionEnv, disableNxEnvFiles } from './env';
import { initAWS } from './aws';
import { loadEnvStage } from './storage';

Expand All @@ -26,6 +26,7 @@ export const initConfig = async (
const rootPath = await getRootPath();
const version = await loadVersionEnv();
const envStage = await loadEnvStage();
disableNxEnvFiles();
const projectName = process.env.PROJECT_NAME;

if (!projectName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ CNAME DNS records pointing to CloudFront distribution and Load Balancer need to

### \[Optional\] Configure production domain

SaaS Boilerplate creates a certificate that supports `*.[ENV_STAGE].example.com` domains, like
<ProjectName /> creates a certificate that supports `*.[ENV_STAGE].example.com` domains, like
`app.production.example.com`. You most likely don't want such domain and need straight up `app.example.com` for your
production environment. Set a following variable to override the default behaviour:

Expand All @@ -101,6 +101,32 @@ Resource handler returned message: "Invalid request provided: AWS::CloudFront::D
attached to your distribution doesn't cover the alternate domain name (CNAME) that you're trying to add.
```

### [Optional] Configuring CI mode

:::caution
Deploying `<ProjectName />` on a **new AWS account** may result in reaching the AWS CodeBuild concurrent build limit.
This is a common issue with newly created AWS accounts. To mitigate potential issues during CI builds, it is advisable
to configure the CI mode to `simple`. For more information about potential issues with new AWS accounts, see
[Configuring AWS Credentials for New Accounts](./configure-aws-credentials#for-users-with-newly-created-aws-accounts).
:::

Changing the CI mode affects the execution behavior of CI processes:
- `parallel` (the default setting): Enables actions in the AWS CodePipeline stages to execute concurrently.
- `simple`: Ensures actions in the AWS CodePipeline stages are executed sequentially, with only one CodeBuild process
running at a time.

We recommend utilizing the `parallel` mode for optimal performance and efficiency, provided that the concurrent build
limits of AWS CodeBuild have been adjusted accordingly.

```shell
pnpm saas aws set-var SB_CI_MODE <parallel/simple>
```

:::info
Note: If you modify the settings for an already deployed environment, it is necessary to
[redeploy the CI stack](./deploy-infrastructure#deploy-the-infrastructure) to ensure that the changes take effect.
:::

### \[Optional\] Protect the website with basic auth

It's a good idea to prevent unauthorized access to staging environments so we suggest to set a basic auth password
Expand All @@ -121,6 +147,10 @@ pnpm saas aws set-var SB_DEPLOY_BRANCHES master

### \[Optional\] Set tools env variables

The `tools` package during CI deployment is responsible for uploading the information of the version of deployed
application on specific environment. Then, you will be able to check currently deployed state in the
[version matrix](../../../working-with-sb/dev-tools/version-matrix).

To configure `tools` package env variables follow the example below.

```shell
Expand All @@ -131,6 +161,14 @@ pnpm saas aws set-var SB_TOOLS_HOSTED_ZONE_NAME example.com
pnpm saas aws set-var SB_TOOLS_DOMAIN_VERSION_MATRIX status.example.com
```

:::info

If you set `SB_TOOLS_ENABLED` to `true` make sure to deploy **version matrix** component before first CI pipeline run.

Follow the [deployment instructions](../../../working-with-sb/dev-tools/version-matrix#deployment) for more details.

:::

## Env variable validation

You can look up the validator in `packages/internal/cli/src/config/env.ts`, which runs on every `nx` command that
Expand Down
1 change: 1 addition & 0 deletions packages/workers/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ COPY packages/workers/pdm.lock packages/workers/pyproject.toml packages/workers/
RUN pdm sync

WORKDIR $APP_PATH
COPY /patches/ $APP_PATH/patches/
COPY package.json pnpm*.yaml $APP_PATH/
COPY $SRC_CORE_PATH/package.json $DEST_CORE_PATH/
COPY $SRC_WORKERS_PATH/package.json $DEST_WORKERS_PATH/
Expand Down
13 changes: 13 additions & 0 deletions patches/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/src/tasks-runner/run-command.js b/src/tasks-runner/run-command.js
index cd830d3c34639a5d8a52c12b3975e8c309ba8f9b..8300356271db5e2a815d3b51443a5f6682858181 100644
--- a/src/tasks-runner/run-command.js
+++ b/src/tasks-runner/run-command.js
@@ -114,7 +114,7 @@ function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
if (nxArgs.outputStyle == 'stream-without-prefixes') {
process.env.NX_STREAM_OUTPUT = 'true';
}
- if (loadDotEnvFiles) {
+ if (loadDotEnvFiles && !process.env.NX_LOAD_DOT_ENV_FILES) {
process.env.NX_LOAD_DOT_ENV_FILES = 'true';
}
}
Loading

0 comments on commit f2ded1f

Please sign in to comment.