fix: gitea/refactor file saving (#492)

This commit is contained in:
Denys Konovalov 2023-02-06 22:30:19 +01:00 committed by GitHub
parent f89d10627a
commit 1abc18b0ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 71 additions and 39 deletions

View File

@ -362,38 +362,50 @@ export default class API {
async persistFiles(dataFiles: DataFile[], mediaFiles: AssetProxy[], options: PersistOptions) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[mediaFiles, dataFiles].forEach(async list => {
list.forEach(async file => {
const item: { raw?: string; sha?: string; toBase64?: () => Promise<string> } = file;
const contentBase64 = await result(
item,
'toBase64',
partial(this.toBase64, item.raw as string),
);
if (options.newEntry) {
await this.request(`${this.repoURL}/contents/${file.path}`, {
method: 'POST',
body: JSON.stringify({
branch: this.branch,
content: contentBase64,
message: options.commitMessage,
signoff: false,
}),
});
} else {
const oldSha = await this.getFileSha(file.path);
await this.request(`${this.repoURL}/contents/${file.path}`, {
method: 'PUT',
body: JSON.stringify({
branch: this.branch,
content: contentBase64,
message: options.commitMessage,
sha: oldSha,
signoff: false,
}),
});
}
});
const files: (DataFile | AssetProxy)[] = mediaFiles.concat(dataFiles as any);
for (const file of files) {
const item: { raw?: string; sha?: string; toBase64?: () => Promise<string> } = file;
const contentBase64 = await result(
item,
'toBase64',
partial(this.toBase64, item.raw as string),
);
try {
const oldSha = await this.getFileSha(file.path);
await this.updateBlob(contentBase64, file, options, oldSha!);
} catch {
await this.createBlob(contentBase64, file, options);
}
}
}
async updateBlob(
contentBase64: string,
file: AssetProxy | DataFile,
options: PersistOptions,
oldSha: string,
) {
await this.request(`${this.repoURL}/contents/${file.path}`, {
method: 'PUT',
body: JSON.stringify({
branch: this.branch,
content: contentBase64,
message: options.commitMessage,
sha: oldSha,
signoff: false,
}),
});
}
async createBlob(contentBase64: string, file: AssetProxy | DataFile, options: PersistOptions) {
await this.request(`${this.repoURL}/contents/${file.path}`, {
method: 'POST',
body: JSON.stringify({
branch: this.branch,
content: contentBase64,
message: options.commitMessage,
signoff: false,
}),
});
}
@ -415,12 +427,12 @@ export default class API {
if (file) {
return file.sha;
} else {
console.error('File not found');
throw new APIError('Not Found', 404, API_NAME);
}
}
async deleteFiles(paths: string[], message: string) {
paths.forEach(async file => {
for (const file of paths) {
const meta: ContentsResponse = await this.request(`${this.repoURL}/contents/${file}`, {
method: 'GET',
});
@ -428,7 +440,7 @@ export default class API {
method: 'DELETE',
body: JSON.stringify({ branch: this.branch, message, sha: meta.sha, signoff: false }),
});
});
}
}
toBase64(str: string) {

View File

@ -101,7 +101,7 @@ describe('gitea API', () => {
});
describe('persistFiles', () => {
it('should create a new file', async () => {
it('should check if file exists and create a new file', async () => {
const api = new API({ branch: 'master', repo: 'owner/repo' });
const responses = {
@ -127,9 +127,13 @@ describe('gitea API', () => {
newEntry: true,
});
expect(api.request).toHaveBeenCalledTimes(1);
expect(api.request).toHaveBeenCalledTimes(2);
expect((api.request as jest.Mock).mock.calls[0]).toEqual([
'/repos/owner/repo/git/trees/master:content%2Fposts',
]);
expect((api.request as jest.Mock).mock.calls[1]).toEqual([
'/repos/owner/repo/contents/content/posts/new-post.md',
{
method: 'POST',
@ -174,11 +178,25 @@ describe('gitea API', () => {
newEntry: false,
});
expect(api.request).toHaveBeenCalledTimes(1);
expect(api.request).toHaveBeenCalledTimes(2);
expect((api.request as jest.Mock).mock.calls[0]).toEqual([
'/repos/owner/repo/git/trees/master:content%2Fposts',
]);
expect((api.request as jest.Mock).mock.calls[1]).toEqual([
'/repos/owner/repo/contents/content/posts/update-post.md',
{
method: 'PUT',
body: JSON.stringify({
branch: 'master',
content: Base64.encode(entry.dataFiles[0].raw),
message: 'commitMessage',
sha: 'old-sha',
signoff: false,
}),
},
]);
});
});

View File

@ -9,13 +9,15 @@ beta: true
For repositories stored on Gitea, the `gitea` backend allows CMS users to log in directly with their Gitea account. Note that all users must have push access to your content repository for this to work.
<Alert severity="warning">Because of the [lack](https://github.com/go-gitea/gitea/issues/14619) of a Gitea API endpoint for multifile commits, when using this backend, separate commits are created for every changed file. Please make sure this is handled correctly by your CI.</Alert>
## Authentication
Because Gitea requires a server for authentication and Netlify doesn't support Gitea, a custom OAuth provider needs to be used for basic Gitea authentication.
To enable basic Gitea authentication:
1. Setup an own OAuth provider, for example with [scm-oauth](https://github.com/denyskon/scm-oauth-provider).
1. Setup an own OAuth provider, for example with [Teabag](https://github.com/denyskon/teabag).
2. Add the following lines to your Static CMS `config` file:
<CodeTabs>