An Interest In:
Web News this Week
- April 2, 2024
- April 1, 2024
- March 31, 2024
- March 30, 2024
- March 29, 2024
- March 28, 2024
- March 27, 2024
One Click to Optimize Images, Create Repo and Making Commit
Continuing from last post, I have completed my feature that produces optimized images, create a remote repository and make a commit with the files. My PR may be updated, but I think the change would not be so big from now.
So the main challenge was how I can make one click to create a repo and make a commit. I tried to use octokit.rest
library. I'm not sure what I did wrong, but it didn't read the parameters that I passed. But GitHub API version works for me. And the post How to push files programatically to a repository using Octokit with Typescript was a huge help for me. My version is not so different from this post except that I use JavaScript
and create multiple blobs in the middle of the process.
First I create a remote repo with createRepo
function below.
const createRepo = async (octokit, username, repoName) => { try { await octokit.rest.repos.createForAuthenticatedUser({ name: repoName ? repoName : generateUniqueName(username), description: 'Your repository generated using my-photohub', private: false, auto_init: true, }); return true; } catch (err) { console.error(err); return false; }};
Then, I produce optimized images with compressor.js
.
const compressImage = (file, option) => { return new Promise((resolve, reject) => { new Compressor(file, { width: option.width, quality: 0.6, success: (result) => { const fileName = file.name.replace(/\.[^/.]+$/, '') + '_' + option.width + '.' + option.mimeType.substring(option.mimeType.indexOf('/') + 1); resolve(new File([result], fileName, { type: option.mimeType })); }, error: (err) => { console.error(err.message); reject(err); }, }); });};export const createOptimizedImages = async (originalImages) => { if (!originalImages) { return; } let compressFilesPromises = []; compressorOptions.forEach((option) => { for (const image of originalImages) { compressFilesPromises.push(compressImage(image, option)); } }); return Promise.all(compressFilesPromises);};
You can change image quality or pass different options. I set customized mimeType
and width
by passing option parameter here. You can find more usages from compressor.js
original documentation.
Then I need to create a blob from each file with the function below.
const createBlobForFile = async (octokit, username, repoName, files) => { let blobDataPromises = []; for (const file of files) { let reader = new FileReader(); await reader.readAsDataURL(file); const promise = new Promise((resolve, reject) => { reader.onload = async () => { const base64Data = reader.result; const blobData = octokit.request(`POST /repos/${username}/${repoName}/git/blobs`, { owner: username, repo: repoName, content: base64Data, }); resolve(blobData); }; reader.onerror = reject; }); blobDataPromises.push(promise); } return Promise.all(blobDataPromises);};
So this function returns an array of blob object in the same order from files.
In the blob, it doesn't have a file name that I can use as a path in next function. So I added getPathNamesFromFile()
.
const getPathNamesFromFile = (convertedFiles) => { let pathNames = []; for (const file of convertedFiles) { pathNames.push(file.name); } return pathNames;};
Next step is that I need to get current existing commit from the repo that I just created so that I can add a new commit as a child. Here's the function.
const createNewCommit = async ( octokit, username, repoName, message, currentTreeSha, currentCommitSha) => ( await octokit.request(`POST /repos/${username}/${repoName}/git/commits`, { owner: username, repo: repoName, message: message, tree: currentTreeSha, parents: [currentCommitSha], }) ).data;
The function is pretty obvious as if I'm making an actual commit. Then, I need to create trees to add. You can find details of git tree object
here. Basically blob
is a file and tree
is a directory in git
. You can check your git
folder with this command.
git cat-file -p main^{tree} ...040000 tree f808c5b1a9eaa36928f49ac82b8b2ed85c53af45 .vscode100644 blob 3ee245e88d83084868e58ba369200acc8354f9df CONTRIBUTING.md...100644 blob 8202e8c8292a2681114b67099e5f47c5aa0e13e4 package.json040000 tree 2ce2a0fdb03a853cc6c855ebc46865cd20d3afaf public040000 tree e3ef837d95be8981e826c7ad683101475f2b6528 src...
And you would have noticed numbers in front of tree
and blob
. This number is an associated mode with the file. 100644
means a normal file. You would have figured 040000
is a directory. 100755
is an executable file and 120000
is a symbolic link.
And the last step is to set the branch to this new commit.
const setBranchToCommit = (octokit, username, repoName, branch = `main`, commitSha) => octokit.request(`PATCH /repos/${username}/${repoName}/git/refs/heads/${branch}`, { owner: username, repo: repoName, ref: `heads/${branch}`, sha: commitSha, });
Conclusion
I spent many days to figure this out. But in the end, I was so happy to see my code working as intended. I was on the issue that my array of promises in createBlobForFile()
returned an empty array for many hours. I could have fixed the problem if I tried to think more rational about the behaviour and root cause. I was adding each promise inside reader.onload
. So the outer function just bypassed the code block and returned an empty array immediately. It was a lot of trials and learning. Moreover, I'm so glad that I set very fundamental of this app.
Original Link: https://dev.to/genne23v/one-click-to-optimize-images-create-repo-and-making-commit-2203
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To