Skip to content

Commit

Permalink
Deploy with riff-raff (#1693)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakeii authored Dec 23, 2024
1 parent 1273e6d commit 1d81a68
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 3 deletions.
39 changes: 38 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ jobs:
run: pnpm build

- name: Save build
if: github.ref == 'refs/heads/main'
uses: actions/upload-artifact@v4
with:
name: dist
Expand Down Expand Up @@ -116,3 +115,41 @@ jobs:
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

riff-raff:
name: Upload Riff Raff Artifacts
needs: [build, test, lint, types]
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: write

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Node
uses: ./.github/actions/setup-node-env

- name: Fetch build
uses: actions/download-artifact@v4
with:
name: dist
path: dist

- name: Riff-Raff Upload
uses: guardian/actions-riff-raff@v4
with:
roleArn: ${{ secrets.GU_RIFF_RAFF_ROLE_ARN }}
githubToken: ${{ secrets.GITHUB_TOKEN }}
projectName: dotcom::commercial-bundle
configPath: ./riff-raff.yaml
contentDirectories: |
frontend-static/commercial:
- dist/riff-raff/js/commercial
commercial-bundle-path:
- dist/riff-raff/cloudformation
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ dist
.changeset
README.md
CHANGELOG.md
riff-raff.yaml
.vscode/settings.json
playwright-report/
pnpm-lock.yaml
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,11 @@ In order to do this, first run: `pnpm changeset add`, again, This will create a
**Note**: Once the beta version is released, the label will be removed from the PR, so you will need to add it again if you want to release subsequent new versions.

On a branch on frontend you can update the version of the bundle to the beta version and deploy to CODE to test.

### Deploying to PROD

Ensure your PR has a chageset and has been merged to main. This will trigger a changesets release PR, which will bump the version of the package, once this is merged the package will be published to NPM.

To get your changes live on the site, you will need to update the `@guardian/commercial` version in the [Frontend](https://github.com/guardian/frontend) repository. You can do this by running the [bump_commercial.sh](./scripts/bump_commercial.sh) script.

We're experimenting with direct deployments via riff-raff, when you merge to main a a riff-raff build will be created but you will need to manually deploy it in the riff-raff GUI, these deployments are currently only available behind a server side test that you'll need to opt in to.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
"main": "dist/cjs/core/index.js",
"module": "dist/esm/core/index.js",
"scripts": {
"build": "npm-run-all clean --parallel compile:core:* build:prod build:dev",
"build": "npm-run-all clean --parallel compile:core:* build:prod build:dev build:riff-raff",
"build:dev": "webpack -c webpack.config.dev.mjs",
"build:prod": "webpack -c webpack.config.prod.mjs",
"build:riff-raff": "webpack -c webpack.config.riff-raff.mjs",
"clean": "rm -rf dist",
"compile:core:common": "tsc --project ./tsconfig.core.json --outDir ./dist/cjs --module CommonJS",
"compile:core:esm": "tsc --project ./tsconfig.core.json --outDir ./dist/esm",
Expand Down
21 changes: 21 additions & 0 deletions riff-raff.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
regions: [eu-west-1]
stacks: [frontend]
allowedStages:
- CODE
- PROD
deployments:
frontend-static/commercial:
type: aws-s3
parameters:
bucketSsmKey: /account/services/dotcom-static.bucket
cacheControl: public, max-age=315360000, immutable
prefixStack: false
publicReadAcl: false
commercial-bundle-path:
type: cloud-formation
parameters:
templateStagePaths:
CODE: code.json
PROD: prod.json
dependencies:
- frontend-static/commercial
5 changes: 4 additions & 1 deletion src/commercial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ const decideAssetsPath = () => {
if (process.env.OVERRIDE_BUNDLE_PATH) {
return process.env.OVERRIDE_BUNDLE_PATH;
}

const assetsPath = frontendAssetsFullURL ?? page.assetsPath;
return `${assetsPath}javascripts/commercial/`;
};

__webpack_public_path__ = decideAssetsPath();
if (!process.env.RIFFRAFF_DEPLOY) {
__webpack_public_path__ = decideAssetsPath();
}

/**
* Choose whether to launch Googletag or Opt Out tag (ootag) based on consent state
Expand Down
1 change: 1 addition & 0 deletions webpack.config.prod.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default merge(config, {
new DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.OVERRIDE_BUNDLE_PATH': JSON.stringify(false),
'process.env.RIFFRAFF_DEPLOY': JSON.stringify(false),
...gitCommitSHA(),
}),
],
Expand Down
119 changes: 119 additions & 0 deletions webpack.config.riff-raff.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { execSync } from 'child_process';
import { join } from 'path';
import TerserPlugin from 'terser-webpack-plugin';
import webpack from 'webpack';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import { merge } from 'webpack-merge';
import config from './webpack.config.mjs';

const { DefinePlugin } = webpack;

class GenerateCloudformation {
apply = (compiler) => {
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
const entry = compilation.entrypoints.get('commercial-standalone');

const hashedFilePath = entry?.getFiles()[0];

if (!hashedFilePath) {
throw new Error(
'Could not find hashed file for commercial-standalone',
);
}

const stages = ['code', 'prod'];
stages.forEach((stage) => {
/**
* This small bit of cloudformation will update the SSM parameter that frontend
* reads to get the bundle path.
*/
const cloudformation = {
Resources: {
BundlePath: {
Type: 'AWS::SSM::Parameter',
Properties: {
Name: `/frontend/${stage}/commercial.bundlePath`,
Type: 'String',
Value: hashedFilePath,
},
},
},
};

// If we're in prod, we also want to update the dev bundle path
if (stage === 'prod') {
cloudformation.Resources.DevBundlePath = {
Type: 'AWS::SSM::Parameter',
Properties: {
Name: '/frontend/dev/commercial.bundlePath',
Type: 'String',
Value: hashedFilePath,
},
};
}

const output = JSON.stringify(cloudformation, null, 2);
const outputPath = join(
import.meta.dirname,
'dist',
'riff-raff',
'cloudformation',
`${stage}.json`,
);
compiler.outputFileSystem.mkdirSync(
join(
import.meta.dirname,
'dist',
'riff-raff',
'cloudformation',
),
{ recursive: true },
);
compiler.outputFileSystem.writeFileSync(outputPath, output);
});
});
};
}

const gitCommitSHA = () => {
try {
const commitSHA = execSync('git rev-parse HEAD').toString().trim();
return { 'process.env.COMMIT_SHA': JSON.stringify(commitSHA) };
} catch (_) {
return {};
}
};

const prefix = process.env.BUNDLE_PREFIX ?? '[chunkhash]/';

// eslint-disable-next-line import/no-default-export -- webpack config
export default merge(config, {
mode: 'production',
output: {
filename: `commercial/${prefix}graun.standalone.commercial.js`,
chunkFilename: `commercial/${prefix}graun.[name].commercial.js`,
path: join(import.meta.dirname, 'dist', 'riff-raff', 'js'),
publicPath: 'auto',
clean: true,
},
devtool: 'source-map',
plugins: [
// eslint-disable-next-line @typescript-eslint/no-unsafe-call -- circular-dependency-plugin is not typed
new BundleAnalyzerPlugin({
reportFilename: './commercial-bundle-analyzer-report.html',
analyzerMode: 'static',
openAnalyzer: false,
}),
new DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.OVERRIDE_BUNDLE_PATH': JSON.stringify(false),
'process.env.RIFFRAFF_DEPLOY': JSON.stringify(true),
...gitCommitSHA(),
}),
new GenerateCloudformation(),
],
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
});

0 comments on commit 1d81a68

Please sign in to comment.