summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vedant K <gamemaker0042@gmail.com> 2021-09-26 10:27:40 +0530
committerGravatar GitHub <noreply@github.com> 2021-09-26 11:57:40 +0700
commitfdd2e33dbc61675685eaa914f869c955a305764c (patch)
tree4602bddc1bd523e8bb8cc41d61a9e9e45964eef8
parent37fa4677f1ecf26d7176c8d9d43f8a4db6d5d902 (diff)
downloadrefined-github-fdd2e33dbc61675685eaa914f869c955a305764c.tar.gz
refined-github-fdd2e33dbc61675685eaa914f869c955a305764c.tar.zst
refined-github-fdd2e33dbc61675685eaa914f869c955a305764c.zip
Use safer saving mechanism in `restore-file` (#4803)
Co-authored-by: Federico Brigante <me@fregante.com>
-rw-r--r--source/features/restore-file.tsx58
-rw-r--r--source/github-helpers/api.ts2
2 files changed, 38 insertions, 22 deletions
diff --git a/source/features/restore-file.tsx b/source/features/restore-file.tsx
index 04a84595..95df3862 100644
--- a/source/features/restore-file.tsx
+++ b/source/features/restore-file.tsx
@@ -1,13 +1,11 @@
import React from 'dom-chef';
import select from 'select-dom';
import onetime from 'onetime';
-import pushForm from 'push-form';
import delegate from 'delegate-it';
import * as pageDetect from 'github-url-detection';
import features from '.';
import * as api from '../github-helpers/api';
-import fetchDom from '../helpers/fetch-dom';
import showToast from '../github-helpers/toast';
import {getConversationNumber} from '../github-helpers';
@@ -25,6 +23,17 @@ const getBaseReference = onetime(async (): Promise<string> => {
`);
return repository.pullRequest.baseRefOid;
});
+const getHeadReference = async (): Promise<string> => {
+ // Get the sha of the latest commit to the PR, required to create a new commit
+ const {repository} = await api.v4(`
+ repository() { # Cache buster ${Math.random()}
+ pullRequest(number: ${getConversationNumber()!}) {
+ headRefOid
+ }
+ }
+ `);
+ return repository.pullRequest.headRefOid;
+};
async function getFile(filePath: string): Promise<{isTruncated: boolean; text: string} | undefined> {
const {repository} = await api.v4(`
@@ -53,27 +62,34 @@ async function restoreFile(progress: (message: string) => void, menuItem: Elemen
throw new Error('Restore failed: File too big');
}
- let {pathname} = menuItem.previousElementSibling as HTMLAnchorElement;
- // Check if file was deleted by PR
- if (menuItem.closest('[data-file-deleted="true"]')) {
- progress('Undeleting…');
- const [nameWithOwner, headBranch] = select('.head-ref')!.title.split(':');
- pathname = `/${nameWithOwner}/new/${headBranch}?filename=${filePath}`;
- } else {
- progress('Committing…');
- }
+ const [nameWithOwner, prBranch] = select('.head-ref')!.title.split(':');
+ progress(menuItem.closest('[data-file-deleted="true"]') ? 'Undeleting…' : 'Committing…');
const content = file.text;
- // This is either an `edit` or `create` form
- const form = (await fetchDom(pathname, 'form.js-blob-form'))!;
- form.elements.value.value = content; // Restore content (`value` is the name of the file content field)
- form.elements.message.value = (form.elements.message as HTMLInputElement).placeholder
- .replace(/^Create|^Update/, 'Restore');
-
- const response = await pushForm(form);
- if (!response.ok) {
- throw new Error(response.statusText);
- }
+ await api.v4(`mutation {
+ createCommitOnBranch(input: {
+ branch: {
+ repositoryNameWithOwner: "${nameWithOwner}",
+ branchName: "${prBranch}"
+ },
+ expectedHeadOid: "${await getHeadReference()}",
+ fileChanges: {
+ additions: [
+ {
+ path: "${filePath}",
+ contents: "${btoa(content)}"
+ }
+ ]
+ },
+ message: {
+ headline: "Restore ${filePath}"
+ }
+ }) {
+ commit {
+ oid
+ }
+ }
+ }`);
}
const filesRestored = new WeakSet<HTMLButtonElement>();
diff --git a/source/github-helpers/api.ts b/source/github-helpers/api.ts
index 17937968..e9ca80af 100644
--- a/source/github-helpers/api.ts
+++ b/source/github-helpers/api.ts
@@ -186,7 +186,7 @@ export const v4 = mem(async (
Authorization: `bearer ${personalToken}`,
},
method: 'POST',
- body: JSON.stringify({query: `{${query}}`}),
+ body: JSON.stringify({query: query.trimStart().startsWith('mutation') ? query : `{${query}}`}),
});
const apiResponse: GraphQLResponse = await response.json();