Made gitlab:repo:push action idempotent.
Signed-off-by: Bogdan Nechyporenko <bnechyporenko@bol.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
|
||||
---
|
||||
|
||||
Made gitlab:repo:push action idempotent.
|
||||
@@ -154,30 +154,36 @@ export function createGithubRepoCreateAction(options: {
|
||||
username: owner,
|
||||
});
|
||||
|
||||
await ctx.checkpoint('repo.creation', async () => {
|
||||
const repoCreationPromise =
|
||||
user.data.type === 'Organization'
|
||||
? client.rest.repos.createInOrg({
|
||||
name: repo,
|
||||
org: owner,
|
||||
})
|
||||
: client.rest.repos.createForAuthenticatedUser({
|
||||
name: repo,
|
||||
});
|
||||
const { repoUrl } = await repoCreationPromise;
|
||||
return { repoUrl };
|
||||
await ctx.checkpoint({
|
||||
key: 'repo.creation.v1',
|
||||
fn: async () => {
|
||||
const repoCreationPromise =
|
||||
user.data.type === 'Organization'
|
||||
? client.rest.repos.createInOrg({
|
||||
name: repo,
|
||||
org: owner,
|
||||
})
|
||||
: client.rest.repos.createForAuthenticatedUser({
|
||||
name: repo,
|
||||
});
|
||||
const { repoUrl } = await repoCreationPromise;
|
||||
return { repoUrl };
|
||||
},
|
||||
});
|
||||
|
||||
if (secrets) {
|
||||
await ctx.checkpoint('repo.create.variables', async () => {
|
||||
for (const [key, value] of Object.entries(repoVariables ?? {})) {
|
||||
await client.rest.actions.createRepoVariable({
|
||||
owner,
|
||||
repo,
|
||||
name: key,
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
await ctx.checkpoint({
|
||||
key: 'repo.create.variables',
|
||||
fn: async () => {
|
||||
for (const [key, value] of Object.entries(repoVariables ?? {})) {
|
||||
await client.rest.actions.createRepoVariable({
|
||||
owner,
|
||||
repo,
|
||||
name: key,
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -202,9 +208,12 @@ Checkpoints will allow action authors to create actions where code paths are ign
|
||||
This will be provided on a context object and action of author provide a key and a callback.
|
||||
|
||||
```typescript
|
||||
await ctx.checkpoint('repo.creation', async () => {
|
||||
const { repoUrl } = await client.rest.Repository.create({});
|
||||
return { repoUrl };
|
||||
await ctx.checkpoint({
|
||||
key: 'repo.creation',
|
||||
fn: async () => {
|
||||
const { repoUrl } = await client.rest.Repository.create({});
|
||||
return { repoUrl };
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -259,6 +268,12 @@ Task state will be stored in the extra column `state` in the table `tasks` with
|
||||
}
|
||||
```
|
||||
|
||||
Whenever you change the return type of the checkpoint, we encourage you to change the ID.
|
||||
For example, you can embed the versioning or another indicator for that.
|
||||
If you'll preserve the same key, and you'll try to restart the affected task, it will fail on this checkpoint.
|
||||
The cached result will not match with the expected updated return type.
|
||||
By changing the key, you'll invalidate the cache of the checkpoint.
|
||||
|
||||
#### Workspace Persistence
|
||||
|
||||
The workspace will be serialized and stored in the database by default. This serialization should occur at the end of a step, and after each checkpoint. It will be possible to provide additional modules to extend the workspace serialization to other providers, such as GCS or S3 instead of the database.
|
||||
|
||||
@@ -151,19 +151,24 @@ export const createGitlabRepoPushAction = (options: {
|
||||
execute_filemode: file.executable,
|
||||
}));
|
||||
|
||||
let branchExists = false;
|
||||
try {
|
||||
await api.Branches.show(repoID, branchName);
|
||||
branchExists = true;
|
||||
} catch (e: any) {
|
||||
if (e.cause?.response?.status !== 404) {
|
||||
throw new InputError(
|
||||
`Failed to check status of branch '${branchName}'. Please make sure that branch already exists or Backstage has permissions to create one. ${getErrorMessage(
|
||||
e,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const branchExists = await ctx.checkpoint({
|
||||
key: `branch.exists.${repoID}.${branchName}`,
|
||||
fn: async () => {
|
||||
try {
|
||||
await api.Branches.show(repoID, branchName);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
if (e.cause?.response?.status !== 404) {
|
||||
throw new InputError(
|
||||
`Failed to check status of branch '${branchName}'. Please make sure that branch already exists or Backstage has permissions to create one. ${getErrorMessage(
|
||||
e,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
if (!branchExists) {
|
||||
// create a branch using the default branch as ref
|
||||
@@ -181,15 +186,22 @@ export const createGitlabRepoPushAction = (options: {
|
||||
}
|
||||
|
||||
try {
|
||||
const commit = await api.Commits.create(
|
||||
repoID,
|
||||
branchName,
|
||||
ctx.input.commitMessage,
|
||||
actions,
|
||||
);
|
||||
const commitId = await ctx.checkpoint({
|
||||
key: `commit.create.${repoID}.${branchName}`,
|
||||
fn: async () => {
|
||||
const commit = await api.Commits.create(
|
||||
repoID,
|
||||
branchName,
|
||||
ctx.input.commitMessage,
|
||||
actions,
|
||||
);
|
||||
return commit.id;
|
||||
},
|
||||
});
|
||||
|
||||
ctx.output('projectid', repoID);
|
||||
ctx.output('projectPath', repoID);
|
||||
ctx.output('commitHash', commit.id);
|
||||
ctx.output('commitHash', commitId);
|
||||
} catch (e) {
|
||||
throw new InputError(
|
||||
`Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${getErrorMessage(
|
||||
|
||||
Reference in New Issue
Block a user