-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add find and replace for passport variable via cli prompts (#9)
- Loading branch information
1 parent
0c293d0
commit 85b2d25
Showing
4 changed files
with
135 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** | ||
* Find a current passport variable (fn) or (val) and replace it in each node in a flow (live or published | ||
*/ | ||
|
||
const updateNodeFn = (flowData, currentPassportVariable, newPassportVariable) => { | ||
let newFlowData = flowData; | ||
Object.entries(flowData) | ||
.filter(([_nodeId, nodeData]) => nodeData?.["data"]?.["fn"] || nodeData?.["data"]?.["val"]) | ||
.forEach(([nodeId, nodeData]) => { | ||
const passportKey = nodeData["data"]["fn"] ? "fn" : "val" | ||
const currentFn = nodeData["data"][`${passportKey}`] | ||
newFlowData[nodeId]["data"][`${passportKey}`] = currentFn.replaceAll(currentPassportVariable, newPassportVariable) | ||
}) | ||
return newFlowData; | ||
} | ||
|
||
module.exports = { updateNodeFn }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
const ask = require("prompt"); | ||
const chalk = require("chalk"); | ||
const Client = require("../client"); | ||
|
||
const { findAndReplacePrompts } = require("./prompts"); | ||
const { updateNodeFn } = require("./helpers"); | ||
|
||
ask.start(); | ||
|
||
(async function go() { | ||
// greeting | ||
console.log( | ||
chalk.cyan( | ||
`Hello! These prompts will step you through updating a PlanX passport variables.\nType values when prompted or click 'enter' to accept ${chalk.white( | ||
"(default)" | ||
)} values.\n~~~~~~~~~~~~~~ ${chalk.bold("LET'S START")} ~~~~~~~~~~~~~~` | ||
) | ||
); | ||
|
||
// authentication & setup | ||
const { hasuraEnvironment, hasuraSecret, flowSlug, currentPassportVariable, newPassportVariable } = await ask.get( | ||
findAndReplacePrompts | ||
); | ||
const url = { | ||
production: "https://hasura.editor.planx.uk/v1/graphql", | ||
staging: "https://hasura.editor.planx.dev/v1/graphql", | ||
local: "http://localhost:7100/v1/graphql", | ||
}; | ||
|
||
// create graphQL client | ||
const client = new Client({ | ||
hasuraSecret, | ||
targetURL: url[hasuraEnvironment], | ||
}); | ||
|
||
const formattedSlug = flowSlug.toLowerCase().trim().replaceAll(" ", "-"); | ||
|
||
// Fetch flows matching slugs | ||
const flows = await client.getFlowData(formattedSlug); | ||
if (flows?.length > 0) { | ||
console.log(chalk.white(`Fetched ${flows.length} flows`)); | ||
|
||
flows.forEach(async (flow, i) => { | ||
let liveFlowData; | ||
let publishedFlowData; | ||
let response; | ||
|
||
try { | ||
if (flow.publishedFlows.length > 0) { | ||
// Proceed with migration for flows that are published | ||
console.log(chalk.white(`Updating published flow ${i+1}/${flows.length}: ${flow.team.slug}/${flow.slug}`)); | ||
|
||
// Find nodes in live flow data, update them | ||
// This does NOT require a corresponding operation because we are not creating the flow for the first time | ||
liveFlowData = updateNodeFn(flow.data, currentPassportVariable, newPassportVariable); | ||
|
||
// Find nodes in published flow data, update them directly too | ||
publishedFlowData = updateNodeFn(flow.publishedFlows?.[0]?.data, currentPassportVariable, newPassportVariable); | ||
|
||
// Write update in a single mutation block for postgres transaction-like rollback behavior on error | ||
response = await client.updateFlowAndPublishedFlow(flow.id, liveFlowData, flow.publishedFlows?.[0]?.id, publishedFlowData); | ||
if (response?.update_flows_by_pk?.id) { | ||
console.log( | ||
chalk.green(`Successfully updated flow: ${flow.team.slug}/${flow.slug}`) | ||
); | ||
} | ||
if (response?.update_published_flows_by_pk?.id) { | ||
console.log( | ||
chalk.green(`Successfully updated published version of flow: ${flow.team.slug}/${flow.slug}`) | ||
); | ||
} | ||
} else { | ||
// Proceed with migration for flows that are not published | ||
console.log(chalk.white(`Updating unpublished flow ${i+1}/${flows.length}: ${flow.team.slug}/${flow.slug}`)); | ||
|
||
// Find nodes in live flow data, update them | ||
// This does NOT require a corresponding operation because we are not creating the flow for the first time | ||
liveFlowData = updateNodeFn(flow.data, currentPassportVariable, newPassportVariable); | ||
|
||
// Write update | ||
response = await client.updateFlow(flow.id, liveFlowData); | ||
if (response?.update_flows_by_pk?.id) { | ||
console.log( | ||
chalk.green(`Successfully updated flow: ${flow.team.slug}/${flow.slug}`) | ||
); | ||
} | ||
} | ||
} catch (error) { | ||
console.log(chalk.red(error)); | ||
} | ||
}); | ||
} else { | ||
console.log(chalk.red(`Cannot find any flows matching slug: ${formattedSlug}. Exiting migration script`)); | ||
} | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
const { setupPrompts } = require("../prompts"); | ||
|
||
const findAndReplacePrompts= [ | ||
...setupPrompts, | ||
{ | ||
name: "currentPassportVariable", | ||
description: "What is the current passport variable to be replaced?", | ||
default: "outbuildings", | ||
type: "string", | ||
required: true, | ||
}, | ||
{ | ||
name: "newPassportVariable", | ||
description: "What should this passport variable be replaced with?", | ||
default: "outbuilding", | ||
type: "string", | ||
required: true, | ||
}, | ||
|
||
]; | ||
|
||
module.exports = { findAndReplacePrompts }; |