Skip to content

Commit

Permalink
feat(frontend): use hasura action for pipelines (#378)
Browse files Browse the repository at this point in the history
  • Loading branch information
lionelB committed Mar 31, 2021
1 parent 1083a43 commit 2543af4
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 116 deletions.
68 changes: 42 additions & 26 deletions targets/frontend/src/components/button/GitlabButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,70 @@ import {
MdSyncProblem,
MdTimelapse,
} from "react-icons/md";
import { getToken } from "src/lib/auth/token";
import { request } from "src/lib/request";
import useSWR from "swr";
import { useClient } from "urql";

import { ConfirmButton } from "../confirmButton";

function fetchPipelines(url) {
const { jwt_token } = getToken();
return request(url, { headers: { token: jwt_token } });
const pipelineQuery = `
query getPipelines {
pipelines {
preprod
prod
}
}
`;

const pipelineMutation = `
mutation trigger_pipeline($env:String!) {
trigger_pipeline(env: $env) {
message
}
}
`;

export function GitlabButton({ env, children }) {
const [status, setStatus] = useState("disabled");
const token = getToken();
const { error, data, mutate } = useSWR(`/api/pipelines`, fetchPipelines);
const client = useClient();
const { error, data, mutate } = useSWR(pipelineQuery, (query) => {
return client
.query(query)
.toPromise()
.then((result) => {
if (error) {
throw error;
}
return result.data.pipelines;
});
});

async function clickHandler() {
function clickHandler() {
if (isDisabled) {
return;
}
setStatus("pending");
await request("/api/trigger_pipeline", {
body: {
env,
},
headers: {
token: token?.jwt_token,
},
}).catch(() => {
setStatus("disabled");
client.mutation(pipelineMutation, { env }).toPromise((result) => {
if (result.error) {
setStatus("error");
}
if (result.data) {
mutate(pipelineQuery);
}
});
mutate();
}

useEffect(() => {
if (!error && data) {
if (data[env] === false) {
console.log(env, "ready to update", data);
setStatus("ready");
}
if (data[env] === true) {
setStatus("pending");
}
if (data?.[env] === false) {
setStatus("ready");
}
if (data?.[env] === true) {
setStatus("pending");
}
}, [env, data, error]);

const isDisabled =
status === "disabled" || status === "pending" || status === "error";

return (
<ConfirmButton disabled={isDisabled} onClick={clickHandler}>
{status === "pending" && <MdTimelapse />}
Expand Down
6 changes: 5 additions & 1 deletion targets/frontend/src/lib/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ export function request(endpoint, { body, ...customConfig } = {}) {
if (response.ok) {
return data;
} else {
return Promise.reject(data);
return Promise.reject({
data,
status: response.status,
statusText: response.statusText,
});
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { apiError } from "src/lib/apiError";
import { sendActivateAccountEmail } from "src/lib/emails/activateAccount";

export default async function ActivateAccount(req, res) {
if (req.method === "GET") {
res.setHeader("Allow", ["POST"]);
return apiError(Boom.methodNotAllowed("GET method not allowed"));
}

if (
!req.headers["actions-secret"] ||
req.headers["actions-secret"] !== process.env.ACTIONS_SECRET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { apiError } from "src/lib/apiError";
import { sendLostPasswordEmail } from "src/lib/emails/lostPassword";

export default async function AskNewPassword(req, res) {
if (req.method === "GET") {
res.setHeader("Allow", ["POST"]);
return apiError(Boom.methodNotAllowed("GET method not allowed"));
}

if (
!req.headers["actions-secret"] ||
req.headers["actions-secret"] !== process.env.ACTIONS_SECRET
Expand Down
54 changes: 54 additions & 0 deletions targets/frontend/src/pages/api/actions/pipelines.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Boom from "@hapi/boom";
import { apiError } from "src/lib/apiError";
import { getPipelines, getPipelineVariables } from "src/lib/gitlab.api";

export default async function ActivateAccount(req, res) {
if (req.method === "GET") {
res.setHeader("Allow", ["POST"]);
return apiError(Boom.methodNotAllowed("GET method not allowed"));
}

if (
!req.headers["actions-secret"] ||
req.headers["actions-secret"] !== process.env.ACTIONS_SECRET
) {
return apiError(res, Boom.unauthorized("Missing secret or env"));
}

try {
const pipelines = await getPipelines();

const activePipelines = pipelines.filter(
({ status }) => status === "pending" || status === "running"
);

const pipelinesDetails = await Promise.all(
activePipelines.map(({ id }) => getPipelineVariables(id))
);
const runningDeployementPipeline = pipelinesDetails.reduce(
(state, variables) => {
const varsObj = variables.reduce(
(obj, { key, value }) => ({ ...obj, [key]: value }),
{}
);
if (
varsObj.ACTION === "ingest_documents_dev" &&
varsObj.ES_INDEX_PREFIX === "cdtn-preprod"
) {
state.preprod = true;
}
if (varsObj.ACTION === "ingest_documents_prod") {
state.prod = true;
}
return state;
},
{ preprod: false, prod: false }
);
res.json(runningDeployementPipeline);
} catch (error) {
console.error(`[actions] get pipelines failed`, error);
res
.status(error.status)
.json({ code: error.status, message: "[actions]: can't get pipelines" });
}
}
9 changes: 8 additions & 1 deletion targets/frontend/src/pages/api/actions/preview.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Client } from "@elastic/elasticsearch";
import { Boom } from "@hapi/boom";
import { client as gqlClient } from "@shared/graphql-client";
import { SOURCES } from "@socialgouv/cdtn-sources";
import memoizee from "memoizee";
import { apiError } from "src/lib/apiError";
import { markdownTransform } from "src/lib/preview/markdown";

const getGlossary = `
Expand Down Expand Up @@ -31,7 +33,12 @@ const fetchGlossary = memoizee(_fetchGlossary, {
promise: true,
});

export default async function (req, res) {
export default async function updateDocument(req, res) {
if (req.method === "GET") {
res.setHeader("Allow", ["POST"]);
return apiError(Boom.methodNotAllowed("GET method not allowed"));
}

const { cdtnId, document, source } = req.body.input;

if (
Expand Down
21 changes: 21 additions & 0 deletions targets/frontend/src/pages/api/actions/trigger_pipeline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Boom from "@hapi/boom";
import { createErrorFor } from "src/lib/apiError";
import { triggerDeploy } from "src/lib/gitlab.api";

export default async function (req, res) {
const apiError = createErrorFor(res);

if (req.method === "GET") {
res.setHeader("Allow", ["POST"]);
return apiError(Boom.methodNotAllowed("GET method not allowed"));
}
const { env } = req.body.input;

try {
await triggerDeploy(env);
res.status(200).json({ message: "ok" });
} catch (error) {
console.error(`[actions] trigger pipeline failed, error`, error);
apiError(res, Boom.serverUnavailable(`[actions] can't trigger pipeline`));
}
}
47 changes: 0 additions & 47 deletions targets/frontend/src/pages/api/pipelines.js

This file was deleted.

38 changes: 0 additions & 38 deletions targets/frontend/src/pages/api/trigger_pipeline.js

This file was deleted.

2 changes: 1 addition & 1 deletion targets/frontend/src/pages/api/webhooks/publication.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createErrorFor } from "src/lib/apiError";
export default async function (req, res) {
const apiError = createErrorFor(res);

if (req.headers["publication-secret"] !== process.env.PUBLICATION_SECRET) {
if (req.headers["actions-secret"] !== process.env.ACTIONS_SECRET) {
return apiError(Boom.unauthorized("Invalid secret token"));
}

Expand Down
13 changes: 13 additions & 0 deletions targets/hasura/metadata/actions.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ type Mutation {
email_password_request(email: citext!, secret_token: uuid!): Status
}

type Query {
pipelines: RunningPipelines
}

type Mutation {
preview_document(cdtnId: String!, document: jsonb!, source: String!): Status
}

type Mutation {
trigger_pipeline(env: String!): Status
}

input PreviewDocument {
cdtn_id: String
document: jsonb
Expand All @@ -25,3 +33,8 @@ type Status {
message: String!
statusCode: Int!
}

type RunningPipelines {
preprod: Boolean!
prod: Boolean!
}

0 comments on commit 2543af4

Please sign in to comment.