깃허브 데스크탑으로 프로젝트 관리하기 강의 오픈!! (인프런 바로가기)
참고
- RESTful API로 파일의 SHA 구하기
- RESTful API로 파일 읽기
- RESTful API로 파일 쓰기
- 깃허브 RESTful API 한글 깨짐 현상 해결하기
- https://mui.com/material-ui/react-text-field/
- https://mui.com/joy-ui/react-textarea/
리액트로 깃허브의 파일을 불러와서 수정하고 저장해보자.
즉, 파일 형상 관리가 되도록 React에서 GitHub RESTful API를 적용시켜보자.
Simple UI with Mui
Mui로 간단하게 아래의 UI를 구성한다.
repository 입력 / 파일 경로 입력을 하고 불러오기를 하면 Textarea에 파일을 가져오게 된다.
그리고 Textarea에서 파일을 수정하고 저장하면 깃허브에 반영된다.
위에서 관리해야 할 repository와 파일 경로, 그리고 textarea의 내용을 useState로 선언하였다.
import React, { useState } from "react";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import { TextField } from "@mui/material";
import { Textarea } from "@mui/joy";
const App = () => {
const [repo, setRepo] = useState("");
const [path, setPath] = useState("");
const [contents, setContents] = useState("");
return (
<div>
<h1>깃허브 파일 편집기</h1>
<Stack sx={{ m: 5 }} spacing={2} direction="row">
<Button variant="outlined" color="primary">
불러오기
</Button>
<Button variant="outlined" color="secondary">
저장하기
</Button>
</Stack>
<Stack sx={{ m: 5 }} spacing={2} direction="row">
<TextField
id="outlined-required"
label="repository"
value={repo}
onChange={(e) => setRepo(e.target.value)}
/>
<TextField
id="outlined-required"
label="filePath"
value={path}
onChange={(e) => setPath(e.target.value)}
/>
</Stack>
<Stack sx={{ m: 5 }}>
<Textarea
name="Primary"
placeholder="Type in here…"
variant="outlined"
color="primary"
value={contents}
onChange={(e) => setContents(e.target.value)}
/>
</Stack>
</div>
);
};
export default App;
GitHub RESTful API 적용하기
리액트에 octokit을 설치한다.
$ npm install @octokit/rest --legacy-peer-deps
깃허브 RESTful API SHA / GET / PUT 링크를 참고하여 아래와 같이 코드를 수정한다.
리액트에서는 arrow function으로 구현하였고, API에 ${repo}와 ${path}를 적용하였다.
const getSHA = async (octokit) => {
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
}
);
return result.data.sha;
};
const fileWrite = async () => {
const octokit = new Octokit({
auth: myKey,
});
const currentSHA = await getSHA(octokit);
const result = await octokit.request(
`PUT /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
message: "commit message!",
sha: currentSHA,
committer: {
name: "bloodstrawberry",
email: "bloodstrawberry@github.com",
},
content: `${btoa(`${contents}`)}`,
headers: {
"X-GitHub-Api-Version": "2022-11-28",
},
}
);
console.log(result.status);
};
const fileRead = async () => {
const octokit = new Octokit({
auth: myKey,
});
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
}
);
setContents(atob(result.data.content));
};
마지막으로 구현한 함수를 버튼에 추가하자.
<Button variant="outlined" color="primary" onClick={fileRead}>
불러오기
</Button>
<Button variant="outlined" color="secondary" onClick={fileWrite}>
저장하기
</Button>
빌드 후, 실제 테스트를 해서 API가 잘 반영되는지 확인해 보자.
이렇게 깃허브에서 직접 파일을 편집하면 기록이 남는다.
파일의 변경 사항을 기록해야할 때, 이용해보자.
전체 코드는 다음과 같다.
import React, { useState } from "react";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import { TextField } from "@mui/material";
import { Textarea } from "@mui/joy";
import { Octokit } from "@octokit/rest";
let myKey = "...";
const App = () => {
const [repo, setRepo] = useState("");
const [path, setPath] = useState("");
const [contents, setContents] = useState("");
const getSHA = async (octokit) => {
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
}
);
return result.data.sha;
};
const fileWrite = async () => {
const octokit = new Octokit({
auth: myKey,
});
const currentSHA = await getSHA(octokit);
const result = await octokit.request(
`PUT /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
message: "commit message!",
sha: currentSHA,
committer: {
name: "bloodstrawberry",
email: "bloodstrawberry@github.com",
},
content: `${btoa(`${contents}`)}`,
headers: {
"X-GitHub-Api-Version": "2022-11-28",
},
}
);
console.log(result.status);
};
const fileRead = async () => {
const octokit = new Octokit({
auth: myKey,
});
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
}
);
setContents(atob(result.data.content));
};
return (
<div>
<h1>깃허브 파일 편집기</h1>
<Stack sx={{ m: 5 }} spacing={2} direction="row">
<Button variant="outlined" color="primary" onClick={fileRead}>
불러오기
</Button>
<Button variant="outlined" color="secondary" onClick={fileWrite}>
저장하기
</Button>
</Stack>
<Stack sx={{ m: 5 }} spacing={2} direction="row">
<TextField
id="outlined-required"
label="repository"
value={repo}
onChange={(e) => setRepo(e.target.value)}
/>
<TextField
id="outlined-required"
label="filePath"
value={path}
onChange={(e) => setPath(e.target.value)}
/>
</Stack>
<Stack sx={{ m: 5 }}>
<Textarea
name="Primary"
placeholder="Type in here…"
variant="outlined"
color="primary"
value={contents}
onChange={(e) => setContents(e.target.value)}
/>
</Stack>
</div>
);
};
export default App;
댓글