Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ISSUE 461] Fix issue when getting the fork name for the cases where the fork has a different name #462

Merged
merged 7 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kie/build-chain-action",
"version": "3.5.4",
"version": "3.5.5",
"description": "Library to execute commands based on github projects dependencies.",
"main": "dist/index.js",
"author": "",
Expand Down
17 changes: 7 additions & 10 deletions src/service/git/git-api-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,18 @@ export class GitAPIService {
): Promise<string> {
try {
// check whether there is a fork with the same name as repo name
const repoName = await this.checkIfRepositoryExists(targetOwner, repo);
this.logger.info(`Checking if ${targetOwner}/${repo} is forked to ${sourceOwner}/${repo}`);
const repoName = await this.checkIfRepositoryExists(sourceOwner, repo);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jstastny-cz @Ginxo TBH I'm not sure if using checkIfRepositoryExists with sourceOwner instead of targetOwner is the correct way to go, after this change I'm getting many failures in the e2e tests locally and seems that in GH they are running forever and never finish.

To run them locally I used:

$ npm ci
$ ACT_LOG=true npm run test:e2e

Actually taking a look in the existing single-pr.test.ts e2e test, there is test PR from owner2/target:branchA to owner1/target-different-name:branchB which should be testing the case where the fork has a different name from the original repository and the test is passing. Am I missing something?

Copy link
Contributor

@Ginxo Ginxo Oct 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's it, this functionality is already covered and it shouldn't be re-adapted unless we discover specific corner case for it I'm not able to find (can't get trace logs).
I'm afraid we are missing something on the BC configuration rather than BC bug, but it is just a feeling I would like to confirm/discard. Could you please provide logs URL? Many thanks

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really seem correct to you @Ginxo ? We want to check here in the method if there's a fork with the same name as repo name ... but why would we check that the repo in target exists as the first thing and if so then return?

In code we invoke getForkName(currentTarget.group, originalSource.group!, currentTarget.name) in checkout-service.ts:L163, where the currentTarget variable in same file L140 is commented as

 // map the starting project target branch to the corresponding branch defined in the mapping for the current node
 // target branch is guaranteed to exist since base always exist

That really sounds like identity check. And the single-pr.test.ts - I am gonna check, but in this case I have mutliple PRs across 3 repositories, maybe it tests a different thing?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It certainly does not do what the comment just above it says // check whether there is a fork with the same name as repo name

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this reproducer :

test("getForkNameForDifferentName", async () => {
    const moctokit = new Moctokit();
    moctokit.rest.repos
        .get({ owner: "sourceOwner", repo: "repo" })
        .reply({ status: 200, data: {} });
    moctokit.rest.repos
        .get({ owner: "targetOwner", repo: "repo" })
        .reply({ status: 200, data: { name: "repo", owner: { login: "targetOwner" } } });
    moctokit.rest.repos.listForks({ owner: "targetOwner", repo: "repo" }).reply({
        status: 200,
        data: [{ name: "repo-fork", owner: { login: "sourceOwner" } }],
    });
    await expect(git.getForkName("targetOwner", "sourceOwner", "repo")).resolves.toBe(
        "repo-fork"
    );
})

getForkName returns "repo".


if (repoName) {
this.logger.info(`Fork ${sourceOwner}/${repo} found.`);
return repoName;
} else if (targetOwner !== sourceOwner) {
/**
* find repo from fork list. we reach this case only if we are in the edge case where the forked repo's name is different
* from the original one
*/
this.logger.info(`Fork ${sourceOwner}/${repo} does not exist. Trying to find a fork with a different name in ${sourceOwner}`);
const forkName = (
await this.client
.rest(targetOwner, repo)
Expand All @@ -144,17 +147,13 @@ export class GitAPIService {
})
).data;
if (forkName) {
this.logger.info(`Fork ${sourceOwner}/${forkName} found from ${targetOwner}/${repo}`);
return forkName;
}
}
throw new NotFoundError();
} catch (err) {
this.logger.error(
this.getErrorMessage(
err,
`Error getting fork name for ${targetOwner}/${repo} where owner is ${sourceOwner}`
)
);
this.logger.info(`Fork for ${targetOwner}/${repo} not found where owner is ${sourceOwner}`);
throw err;
}
}
Expand Down Expand Up @@ -202,9 +201,7 @@ export class GitAPIService {
});
return repo;
} catch (err) {
this.logger.error(
this.getErrorMessage(err, `Failed to get ${owner}/${repo}.`)
);
this.logger.debug(`Failed to get ${owner}/${repo}, it is not necessarily an error`);
return undefined;
}
}
Expand Down
6 changes: 3 additions & 3 deletions test/e2e-regression/cli/tests.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[
{
"name": "issue-372",
"cmd": "build-chain build cross_pr -f 'https://raw.githubusercontent.com/kiegroup/droolsjbpm-build-bootstrap/${BRANCH:main}/.ci/compilation-config.yaml' -o bc -u https://github.com/kiegroup/drools/pull/4978 --skipExecution",
"cmd": "build-chain build cross_pr -f 'https://raw.githubusercontent.com/kiegroup/droolsjbpm-build-bootstrap/${BRANCH:main}/.ci/compilation-config.yaml' -o bc -u https://github.com/kiegroup/appformer/pull/1394 --skipExecution",
"description": "To test that definition file url placeholders fallback to using default value. Checking whether build succeeded is enough"
},
{
"name": "issue-401",
"cmd": "build-chain build cross_pr -f 'https://raw.githubusercontent.com/kiegroup/kogito-pipelines/%{process.env.GITHUB_BASE_REF.replace(/(\\d*)\\.(.*)\\.(.*)/g, (m, n1, n2, n3) => `${+n1-7}.${n2}.${n3}`)}/.ci/pull-request-config.yaml' -o bc -u https://github.com/kiegroup/optaplanner/pull/2634 -p kiegroup/optaplanner --skipExecution",
"cmd": "build-chain build cross_pr -f 'https://raw.githubusercontent.com/apache/incubator-kie-kogito-pipelines/%{process.env.GITHUB_BASE_REF.replace(/(\\d*)\\.(.*)\\.(.*)/g, (m, n1, n2, n3) => `${+n1-7}.${n2}.${n3}`)}/.ci/pull-request-config.yaml' -o bc -u https://github.com/apache/incubator-kie-optaplanner/pull/2634 -p kiegroup/optaplanner --skipExecution",
"description": "To test that definition file url placeholders as well as expressions work when defined together. Checking whether build succeeded is enough"
},
{
"name": "issue-386",
"cmd": "build-chain build cross_pr -f 'https://raw.githubusercontent.com/kiegroup/kogito-pipelines/1.34.x/.ci/pull-request-config.yaml' -o bc -u https://github.com/kiegroup/kogito-examples/pull/1570 -p kiegroup/kogito-examples --skipExecution",
"cmd": "build-chain build cross_pr -f 'https://raw.githubusercontent.com/apache/incubator-kie-kogito-pipelines/1.34.x/.ci/pull-request-config.yaml' -o bc -u https://github.com/apache/incubator-kie-kogito-examples/pull/1570 -p kiegroup/kogito-examples --skipExecution",
"description": "To test if GITHUB_BASE_REF is set during CLI execution. Checking if 8.34.x is checked out of drools should verify this",
"matchOutput": [
"Project taken from kiegroup/drools:8.34.x",
Expand Down
8 changes: 4 additions & 4 deletions test/e2e-regression/github-action/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
"name": "issue-372",
"definition-file": "https://raw.githubusercontent.com/kiegroup/droolsjbpm-build-bootstrap/${BRANCH:main}/.ci/compilation-config.yaml",
"flow-type": "cross_pr",
"starting-project": "kiegroup/drools",
"starting-project": "kiegroup/appformer",
"skip-execution": "true",
"event": "https://github.com/kiegroup/drools/pull/4978",
"event": "https://github.com/kiegroup/appformer/pull/1394",
"description": "To test that definition file url placeholders fallback to using default value. Checking whether build succeeded is enough"
},
{
"name": "issue-401",
"definition-file": "https://raw.githubusercontent.com/kiegroup/kogito-pipelines/%{process.env.GITHUB_BASE_REF.replace(/(\\d*)\\.(.*)\\.(.*)/g, (m, n1, n2, n3) => `${+n1-7}.${n2}.${n3}`)}/.ci/pull-request-config.yaml",
"definition-file": "https://raw.githubusercontent.com/apache/incubator-kie-kogito-pipelines/%{process.env.GITHUB_BASE_REF.replace(/(\\d*)\\.(.*)\\.(.*)/g, (m, n1, n2, n3) => `${+n1-7}.${n2}.${n3}`)}/.ci/pull-request-config.yaml",
"starting-project": "kiegroup/optaplanner",
"flow-type": "cross_pr",
"skip-execution": "true",
"event": "https://github.com/kiegroup/optaplanner/pull/2634",
"event": "https://github.com/apache/incubator-kie-optaplanner/pull/2634",
"description": "To test that definition file url placeholders as well as expressions work when defined together. Checking whether build succeeded is enough"
},
{
Expand Down
19 changes: 14 additions & 5 deletions test/e2e/cross-pr/cross-pr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,22 @@ test("PR from owner1/target:branchA to owner2/target:branchB while using mapping
mockApi: [
moctokit.rest.repos
.get({
owner: "owner1",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok this seems like it was a hack to get around the issue that we're fixing (to get into the other path of the getForkName method). Seems valid not to fail resolution of the repos.
I would add though a successful resolution of owner1/project4 - that's the one actually receiving a PR. Or do I miss sth?

Copy link
Member Author

@rgdoliveira rgdoliveira Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have a successful resolution of owner2/project4 in the block after this one.

In this cross-pr.test.ts, Owner1 has project1, project2, project3 and project4 while Owner 2 has only project3 and project4, that's why I mocked project1 and 2 to fail state and project 3 and 4 to ok state.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was talking about owner1/project4 , it should not affect how the test runs now, but it might "strengthen" the test context ... anyway, just a minor note really.

Copy link
Member Author

@rgdoliveira rgdoliveira Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jstastny-cz I would go without is for now, as AFAIK we are not doing it for the other tests like full-downstream.test.ts, otherwise I think we would need to apply this everywhere to be consistent (even not affecting the test result)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jstastny-cz if you are ok with the PR state, please approve it

repo: /project(1|2|4)/,
owner: "owner2",
repo: /project(1|2)/,
})
.setResponse({
status: 404,
data: {},
repeat: 3
repeat: 2
}),
moctokit.rest.repos
.get({
owner: "owner2",
repo: "project4"
})
.setResponse({
status: 200,
data: {},
}),
moctokit.rest.repos
.listForks({
Expand All @@ -184,12 +193,12 @@ test("PR from owner1/target:branchA to owner2/target:branchB while using mapping
}),
moctokit.rest.repos
.get({
owner: "owner1",
owner: "owner2",
rgdoliveira marked this conversation as resolved.
Show resolved Hide resolved
repo: "project3",
})
.setResponse({
status: 200,
data: { name: "project3", owner: { login: "owner1" } },
data: { name: "project3", owner: { login: "owner2" } },
}),
moctokit.rest.repos
.listForks({
Expand Down
17 changes: 13 additions & 4 deletions test/e2e/full-downstream/full-downstream.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,22 @@ test("PR from owner1/target:branchA to owner2/target:branchB while using mapping
mockApi: [
moctokit.rest.repos
.get({
owner: "owner1",
repo: /project(1|2|3|4)/,
owner: "owner2",
repo: "project2",
})
.setResponse({
status: 404,
data: {},
repeat: 4
}),
moctokit.rest.repos
.get({
owner: "owner2",
repo: /project(1|3|4)/,
})
.setResponse({
status: 200,
data: {},
repeat: 3
}),
moctokit.rest.repos
.listForks({
Expand Down Expand Up @@ -313,7 +322,7 @@ test("PR from owner1/target:branchA to owner2/target:branchB while using mapping
);
expect(group4.output).toEqual(
expect.stringContaining(
"Merged owner1/project4:branchA into branch 8.x"
"Merged owner2/project4:branchA into branch 8.x"
)
);

Expand Down
6 changes: 3 additions & 3 deletions test/e2e/single-pr/single-pr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,15 @@ test("PR from owner2/target:branchA to owner1/target:branchB", async () => {
mockApi: [
moctokit.rest.repos
.get({
owner: "owner1",
owner: "owner2",
repo: "project3",
})
.setResponse({
status: 200,
data: {
name: "project3",
owner: {
login: "owner1",
login: "owner2",
},
},
}),
Expand Down Expand Up @@ -391,7 +391,7 @@ test("PR from owner2/target:branchA to owner1/target-different-name:branchB", as
mockApi: [
moctokit.rest.repos
.get({
owner: "owner1",
owner: "owner2",
repo: "project1",
})
.setResponse({
Expand Down
37 changes: 25 additions & 12 deletions test/unitary/service/git/git-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,49 +119,62 @@ test.each([
[
"success: same source and target owner",
true,
["target1", "target1", "repoA"],
["target1", "repoA", "target1", "repoA"],
],
[
"failure: same source and target owner",
false,
["target2", "target2", "repoA"],
["target2", "repoA", "target2", "repoA"],
],
[
"success: different source and target owner",
true,
["target3", "source", "repoA"],
["target3", "repoA", "source", "repoA"],
],
[
"failure: different source and target owner",
false,
["target4", "source", "repoA"],
["target4", "repoA", "source", "repoA"],
],
[
"success: different source and target owner / different repo name",
true,
["target5", "repoA", "source", "repoA_fork"],
],
[
"failure: different source and target owner / different repo name",
false,
["target6", "repoA", "source", "no_fork"],
],
])(
"getForkName %p",
async (_title: string, testForSuccess: boolean, args: string[]) => {
const moctokit = new Moctokit();
if (testForSuccess) {
moctokit.rest.repos
.get({ owner: args[1], repo: args[2] })
.get({ owner: args[0], repo: args[1] })
.reply({ status: 200, data: {} });
moctokit.rest.repos
.get({ owner: args[2], repo: args[3] })
.reply({ status: 200, data: {} });
moctokit.rest.repos.listForks({ owner: args[0], repo: args[2] }).reply({
moctokit.rest.repos.listForks({ owner: args[0], repo: args[1] }).reply({
status: 200,
data: [{ name: args[2], owner: { login: args[1] } }],
data: [{ name: args[3], owner: { login: args[2] } }],
});

await expect(git.getForkName(args[0], args[1], args[2])).resolves.toBe(
args[2]
await expect(git.getForkName(args[0], args[2], args[1])).resolves.toBe(
args[3]
);
} else {
moctokit.rest.repos
.get({ owner: args[1], repo: args[2] })
.get({ owner: args[0], repo: args[1] })
.reply({ status: 404, data: {} });
moctokit.rest.repos
.listForks({ owner: args[0], repo: args[2] })
.listForks({ owner: args[2], repo: args[3] })
.reply({ status: 200, data: [] });

await expect(
git.getForkName(args[0], args[1], args[2])
git.getForkName(args[0], args[2], args[1])
).rejects.toThrowError();
}
}
Expand Down