amondnet / amondnet/vercel-action
💡 Discussion: Interest in creating an action that updates vercel.json's rewrites?
- Dominant language
- TypeScript
- Stars
- 765
- Forks
- 116
- PR merge metrics
- No merged PRs in 30d
Description
Hey @amondnet !
I love your action and it has inspired me to create one of my own. If you have the same need that I will explain, I could open source it, it would be a great companion to vercel-action IMO
Here's my use case:
I want to have 3 Vercel sites running:
website.com (www.website.com)
app.website.com
api.website.com
and want to have the following rewrites:
website.com/app => app.website.com
website.com/api => api.website.com
My problem is when I have aliases for CI/CD
For example, for PR#222 I have set up (with `vercel-action`):
pr-222.website.com
pr-222-api.website.com
pr-222-app.website.com
I also have branch build for dev, master and release:
(dev branch / dev env)
dev.website.com
dev-api.website.com
dev-app.website.com
(master branch / staging env)
master.website.com
master-api.website.com
master-app.website.com
(release branch / production env)
website.com
api.website.com
app.website.com
The problem with vercel.json rewrites is that they are static
If you deploy pr-222.website.com, pr-222.website.com/api will still point to the rewrites set in the vercel.json
So what I did was to write a custom vercel action that replace the content of vercel.json with a different one depending on the branch:
```ts
import * as core from '@actions/core';
import * as github from '@actions/github';
import { promises as fsp } from 'fs'; // fix for node v12 https://stackoverflow.com/questions/64725249/fs-promises-api-in-typescript-not-compiling-in-javascript-correctly
import { VercelConfig } from './vercel';
try {
const { context } = github;
core.info(`action : ${context.action}`);
core.info(`ref : ${context.ref}`);
core.info(`eventName : ${context.eventName}`);
core.info(`actor : ${context.actor}`);
core.info(`sha : ${context.sha}`);
core.info(`workflow : ${context.workflow}`);
const workingDir = core.getInput('working-directory'); // ./packages/package-name
core.info(`looking for vercel.json files in: ${workingDir}`);
const filenames = ['vercel.json', 'vercel.dev.json', 'vercel.master.json'];
const vercelJsonFileFilenames = filenames.map((filename) => {
return readVercelConfigFile(`${workingDir}/${filename}`);
});
try {
Promise.all(vercelJsonFileFilenames)
.then((values) => values.filter((value) => !!value) as VercelConfig[])
.then((values) => {
if (values.length !== 3) {
const msg = 'vercel.json, vercel.dev.json and vercel.master.json must be provided';
core.error(msg);
throw new Error(msg);
}
const [vercelProdConfig, vercelDevConfig, vercelMasterConfig] = values;
const vercelConfigPath = `${workingDir}/${filenames[0]}`;
core.info(`current branch is: ${github.context.ref}`);
// @ts-ignore
core.info(`target branch is: ${github.context.head_ref}`);
core.debug(`updating config file and returning both the object and the updated file for verification`);
switch (github.context.ref) {
case 'refs/heads/dev': {
const updatedConfigObject = { ...vercelProdConfig, ...vercelDevConfig };
return updateVercelConfigFile(vercelConfigPath, updatedConfigObject).then((updatedConfigFile) => {
return {
updatedConfig: updatedConfigObject,
updatedConfigFile,
};
});
}
case 'refs/heads/master': {
const updatedConfigObject = { ...vercelProdConfig, ...vercelMasterConfig };
return updateVercelConfigFile(vercelConfigPath, updatedConfigObject).then((updatedConfigFile) => {
return {
updatedConfig: updatedConfigObject,
updatedConfigFile,
};
});
}
default:
case 'refs/heads/release': {
console.info('only replacing vercel.json config on branches master and dev');
return readVercelConfigFile(`${workingDir}/${filenames[0]}`).then((updatedConfigFile) => {
return {
updatedConfig: updatedConfigFile,
updatedConfigFile,
};
});
}
}
})
.then(({ updatedConfig, updatedConfigFile }) => {
if (!updatedConfig) {
const msg = 'no updated vercel config object received, aborting';
core.error(msg);
throw new Error(msg);
}
if (!updatedConfigFile) {
const msg = 'no updated vercel config file received, aborting';
core.error(msg);
throw new Error(msg);
}
if (JSON.stringify(updatedConfig) !== JSON.stringify(updatedConfigFile)) {
const msg = 'updated vercel.json file content does not match the updated config object, aborting!';
core.error(msg);
throw new Error(msg);
}
core.info(`updated vercel.json file successfully ✅`);
})
.catch((error) => {
core.error(`could not find vercel.json files in the specified directory`);
core.error(`error: ${error}`);
});
} catch (error) {
core.error(`could not find vercel.json file at the specified path`);
}
} catch (error) {
core.setFailed(error.message);
}
function readVercelConfigFile(path: string) {
core.info(`reading vercel.json file: ${path}`);
return fsp
.readFile(path, 'utf-8')
.then((result) => {
return JSON.parse(result) as VercelConfig;
})
.catch((error) => {
core.error(`could not read file ${path}`);
return undefined;
});
}
function updateVercelConfigFile(path: string, data: VercelConfig) {
core.info(`replacing vercel.json file content`);
return fsp.writeFile(path, JSON.stringify(data, null, 2)).then(() => {
return readVercelConfigFile(path);
});
}
```
Contributor guide
Assessment
This issue has not been assessed yet.