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

Support overriding repos files & providing supplemental ones in PRs #524

Merged
merged 1 commit into from
Feb 13, 2021
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
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,23 @@ For example, if your secret is called `REPO_TOKEN`:
import-token: ${{ secrets.REPO_TOKEN }}
```

### Interdependent pull requests or merge requests

This action allows declaring PR dependencies by providing:
* repos file(s) to override the one(s) defined through the `vcs-repo-file-url` action input
* supplemental repos file(s) to be used along with the rest

For example, this may be useful when your PR depends on PRs/MRs/branches from other repos for it to work or be properly tested.

Include links in your PR's description using the following format:

```
action-ros-ci-repos-override: https://gist.github.com/some-user/some.repos
action-ros-ci-repos-override: https://gist.github.com/some-user/some-other.repos
action-ros-ci-repos-supplemental: https://gist.github.com/some-user/some-supplemental.repos
action-ros-ci-repos-supplemental: file://path/to/some/other/supplemental.repos
```

## License

The scripts and documentation in this project are released under the [Apache 2](LICENSE) license.
Expand Down
53 changes: 53 additions & 0 deletions __tests__/ros-ci.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as core from "@actions/core";
import * as actionRosCi from "../src/action-ros-ci";
import * as dep from "../src/dependencies";
import { execBashCommand } from "../src/action-ros-ci";

jest.setTimeout(20000); // in milliseconds
Expand Down Expand Up @@ -39,3 +40,55 @@ describe("validate distribution test", () => {
expect(actionRosCi.validateDistros("apples", "bananas")).toBe(false);
});
});

describe("PR-specific repos files", () => {
it("should not do anything if not a PR", async () => {
let payload = {};
expect(dep.getReposFilesOverride(payload)).toEqual([]);
expect(dep.getReposFilesSupplemental(payload)).toEqual([]);
payload = { pull_request: {} };
expect(dep.getReposFilesOverride(payload)).toEqual([]);
expect(dep.getReposFilesSupplemental(payload)).toEqual([]);
payload = { pull_request: { body: "" } };
expect(dep.getReposFilesOverride(payload)).toEqual([]);
expect(dep.getReposFilesSupplemental(payload)).toEqual([]);
});

it("should extract repos files from the PR body", () => {
const bodyEmpty = `
Description of the changes.
Blah blah.
`;
let payload = {};
payload = { pull_request: { body: bodyEmpty } };
expect(dep.getReposFilesOverride(payload)).toEqual([]);
expect(dep.getReposFilesSupplemental(payload)).toEqual([]);

const body = `
Description of the changes.
Blah blah.

action-ros-ci-repos-override:
action-ros-ci-repos-override: https://raw.githubusercontent.com/ros2/ros2/master/ros2.repos
action-ros-ci-repos-override : https://some.website.repos
action-ros-ci-repos-override: https://gist.github.com/some-user/some-gist.repos
action-ros-ci-repos-supplemental:https://gist.github.com/some-user/some-other-gist.repos
action-ros-ci-repos-supplemental: file://path/to/some/file.txt
`;
payload = { pull_request: { body: body } };
const expectedOverride = [
"https://raw.githubusercontent.com/ros2/ros2/master/ros2.repos",
"https://gist.github.com/some-user/some-gist.repos",
];
const expectedSupplemental = [
"https://gist.github.com/some-user/some-other-gist.repos",
"file://path/to/some/file.txt",
];
expect(dep.getReposFilesOverride(payload)).toEqual(
expect.arrayContaining(expectedOverride)
);
expect(dep.getReposFilesSupplemental(payload)).toEqual(
expect.arrayContaining(expectedSupplemental)
);
});
});
102 changes: 101 additions & 1 deletion dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10840,6 +10840,7 @@ const os = __importStar(__nccwpck_require__(2087));
const path = __importStar(__nccwpck_require__(5622));
const fs_1 = __importDefault(__nccwpck_require__(5747));
const async_retry_1 = __importDefault(__nccwpck_require__(3415));
const dep = __importStar(__nccwpck_require__(7760));
// All command line flags passed to curl when invoked as a command.
const curlFlagsArray = [
// (HTTP) Fail silently (no output at all) on server errors. This is mostly done to better enable
Expand Down Expand Up @@ -11007,7 +11008,28 @@ function run() {
const targetRos1Distro = core.getInput(targetROS1DistroInput);
const targetRos2Distro = core.getInput(targetROS2DistroInput);
const vcsRepoFileUrlListAsString = core.getInput("vcs-repo-file-url") || "";
const vcsRepoFileUrlList = vcsRepoFileUrlListAsString.split(RegExp("\\s"));
let vcsRepoFileUrlList = vcsRepoFileUrlListAsString.split(RegExp("\\s"));
// Check if PR overrides/adds supplemental repos files
const vcsReposOverride = dep.getReposFilesOverride(github.context.payload);
const vcsReposSupplemental = dep.getReposFilesSupplemental(github.context.payload);
yield core.group("Repos files: override" +
(vcsReposOverride.length === 0 ? " - none" : ""), () => {
for (const vcsRepos of vcsReposOverride) {
core.info("\t" + vcsRepos);
}
return Promise.resolve();
});
if (vcsReposOverride.length > 0) {
vcsRepoFileUrlList = vcsReposOverride;
}
yield core.group("Repos files: supplemental" +
(vcsReposSupplemental.length === 0 ? " - none" : ""), () => {
for (const vcsRepos of vcsReposSupplemental) {
core.info("\t" + vcsRepos);
}
return Promise.resolve();
});
vcsRepoFileUrlList = vcsRepoFileUrlList.concat(vcsReposSupplemental);
const vcsRepoFileUrlListNonEmpty = vcsRepoFileUrlList.filter((x) => x != "");
const vcsRepoFileUrlListResolved = vcsRepoFileUrlListNonEmpty.map((x) => resolveVcsRepoFileUrl(x));
const coverageIgnorePattern = core.getInput("coverage-ignore-pattern");
Expand Down Expand Up @@ -11173,6 +11195,84 @@ function run() {
run();


/***/ }),

/***/ 7760:
/***/ ((__unused_webpack_module, exports) => {

"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getReposFilesSupplemental = exports.getReposFilesOverride = void 0;
// Expecting something like:
// action-ros-ci-repos-override: https://raw.githubusercontent.com/ros2/ros2/master/ros2.repos
const REGEX_REPOS_FILES_OVERRIDE = /action-ros-ci-repos-override:[ ]*([\S]+)/g;
const REGEX_REPOS_FILES_SUPPLEMENTAL = /action-ros-ci-repos-supplemental:[ ]*([\S]+)/g;
/**
* Extract captures of all matches.
*
* The first dimension contains all the matches and the second
* dimension contains the captures for the given match.
*
* @param content the string in which to search
* @param regex the regex to apply
* @returns the array of all captures for all matches
*/
function extractCaptures(content, regex) {
const captures = [];
let matches;
while ((matches = regex.exec(content)) !== null) {
const capture = matches.slice(1);
if (capture.length > 0) {
captures.push(capture);
}
}
return captures;
}
/**
* Try to extract PR body from context payload.
*/
function extractPrBody(contextPayload) {
const prPayload = contextPayload.pull_request;
if (!prPayload) {
return undefined;
}
return prPayload.body;
}
/**
* Get list of repos override files.
*
* @param contextPayload the github context payload object
* @returns an array with all declared repos override files
*/
function getReposFilesOverride(contextPayload) {
const prBody = extractPrBody(contextPayload);
if (!prBody) {
return [];
}
return extractCaptures(prBody, REGEX_REPOS_FILES_OVERRIDE).map((capture) => {
return capture[0];
});
}
exports.getReposFilesOverride = getReposFilesOverride;
/**
* Get list of override repos files.
*
* @param contextPayload the github context payload object
* @returns an array with all declared override repos files
*/
function getReposFilesSupplemental(contextPayload) {
const prBody = extractPrBody(contextPayload);
if (!prBody) {
return [];
}
return extractCaptures(prBody, REGEX_REPOS_FILES_SUPPLEMENTAL).map((capture) => {
return capture[0];
});
}
exports.getReposFilesSupplemental = getReposFilesSupplemental;


/***/ }),

/***/ 2877:
Expand Down
34 changes: 33 additions & 1 deletion src/action-ros-ci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as os from "os";
import * as path from "path";
import fs from "fs";
import retry from "async-retry";
import * as dep from "./dependencies";

// All command line flags passed to curl when invoked as a command.
const curlFlagsArray = [
Expand Down Expand Up @@ -209,7 +210,38 @@ async function run() {
const targetRos1Distro = core.getInput(targetROS1DistroInput);
const targetRos2Distro = core.getInput(targetROS2DistroInput);
const vcsRepoFileUrlListAsString = core.getInput("vcs-repo-file-url") || "";
const vcsRepoFileUrlList = vcsRepoFileUrlListAsString.split(RegExp("\\s"));
let vcsRepoFileUrlList = vcsRepoFileUrlListAsString.split(RegExp("\\s"));

// Check if PR overrides/adds supplemental repos files
const vcsReposOverride = dep.getReposFilesOverride(github.context.payload);
const vcsReposSupplemental = dep.getReposFilesSupplemental(
github.context.payload
);
await core.group(
"Repos files: override" +
(vcsReposOverride.length === 0 ? " - none" : ""),
() => {
for (const vcsRepos of vcsReposOverride) {
core.info("\t" + vcsRepos);
}
return Promise.resolve();
}
);
if (vcsReposOverride.length > 0) {
vcsRepoFileUrlList = vcsReposOverride;
}
await core.group(
"Repos files: supplemental" +
(vcsReposSupplemental.length === 0 ? " - none" : ""),
() => {
for (const vcsRepos of vcsReposSupplemental) {
core.info("\t" + vcsRepos);
}
return Promise.resolve();
}
);
vcsRepoFileUrlList = vcsRepoFileUrlList.concat(vcsReposSupplemental);

const vcsRepoFileUrlListNonEmpty = vcsRepoFileUrlList.filter(
(x) => x != ""
);
Expand Down
79 changes: 79 additions & 0 deletions src/dependencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { WebhookPayload } from "@actions/github/lib/interfaces";

// Expecting something like:
// action-ros-ci-repos-override: https://raw.githubusercontent.com/ros2/ros2/master/ros2.repos
const REGEX_REPOS_FILES_OVERRIDE = /action-ros-ci-repos-override:[ ]*([\S]+)/g;
const REGEX_REPOS_FILES_SUPPLEMENTAL = /action-ros-ci-repos-supplemental:[ ]*([\S]+)/g;

/**
* Extract captures of all matches.
*
* The first dimension contains all the matches and the second
* dimension contains the captures for the given match.
*
* @param content the string in which to search
* @param regex the regex to apply
* @returns the array of all captures for all matches
*/
function extractCaptures(content: string, regex: RegExp): string[][] {
const captures: string[][] = [];
let matches;
while ((matches = regex.exec(content)) !== null) {
const capture = matches.slice(1);
if (capture.length > 0) {
captures.push(capture);
}
}
return captures;
}

/**
* Try to extract PR body from context payload.
*/
function extractPrBody(contextPayload: WebhookPayload): string | undefined {
const prPayload = contextPayload.pull_request;
if (!prPayload) {
return undefined;
}
return prPayload.body;
}

/**
* Get list of repos override files.
*
* @param contextPayload the github context payload object
* @returns an array with all declared repos override files
*/
export function getReposFilesOverride(
contextPayload: WebhookPayload
): string[] {
const prBody = extractPrBody(contextPayload);
if (!prBody) {
return [];
}

return extractCaptures(prBody, REGEX_REPOS_FILES_OVERRIDE).map((capture) => {
return capture[0];
});
}

/**
* Get list of override repos files.
*
* @param contextPayload the github context payload object
* @returns an array with all declared override repos files
*/
export function getReposFilesSupplemental(
contextPayload: WebhookPayload
): string[] {
const prBody = extractPrBody(contextPayload);
if (!prBody) {
return [];
}

return extractCaptures(prBody, REGEX_REPOS_FILES_SUPPLEMENTAL).map(
(capture) => {
return capture[0];
}
);
}