From 875dfcc49015e06d544d40c5c3fdbfcb55f21040 Mon Sep 17 00:00:00 2001 From: Emerson Knapp <537409+emersonknapp@users.noreply.github.com> Date: Thu, 13 Aug 2020 14:56:52 -0700 Subject: [PATCH] Fix failure to touch /opt/ros/$DISTRO/setup.sh due to insufficient permissions (#303) * Add a test that should fail due to insufficient permissions to touch /opt/ros/foxy * Don't source ros setup.sh if it doesn't exist, rather than creating it to blindly source Signed-off-by: Emerson Knapp --- ...po_file_for_test_cpp_with_dependency.repos | 6 ++ .github/workflows/test.yml | 17 +++++- dist/index.js | 56 +++++++++-------- src/action-ros-ci.ts | 60 ++++++++++--------- 4 files changed, 85 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/repo_file_for_test_cpp_with_dependency.repos diff --git a/.github/workflows/repo_file_for_test_cpp_with_dependency.repos b/.github/workflows/repo_file_for_test_cpp_with_dependency.repos new file mode 100644 index 000000000..ec40729b2 --- /dev/null +++ b/.github/workflows/repo_file_for_test_cpp_with_dependency.repos @@ -0,0 +1,6 @@ + +repositories: + rmw: + type: git + url: https://github.com/ros2/rmw.git + version: foxy diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c109c0d81..5b4557e3a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -91,6 +91,21 @@ jobs: # TODO(tmoulard): re-enable this test once it passes on Windows if: matrix.os != 'windows-latest' + test_ros2_foxy_package_with_dependencies: + name: "Test ROS2 foxy package with ROS dependencies" + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: ros-tooling/setup-ros@0.0.25 + with: + required-ros-distributions: foxy + - uses: ./ + with: + package-name: rmw + target-ros2-distro: foxy + vcs-repo-file-url: "${{ github.workspace }}/.github/workflows/repo_file_for_test_cpp_with_dependency.repos" + + test_ros2_docker: name: "Test ROS 2 package" runs-on: ubuntu-latest @@ -390,7 +405,7 @@ jobs: # serves two purposes: # - Don't skip this job if dependent jobs have failed. # - On a fork, we don't have the secrets to authenticate to AWS. - if: ${{ ! github.event.repository.fork && ! github.event.pull_request.head.repo.fork }} + if: ${{ !github.event.repository.fork && !github.event.pull_request.head.repo.fork }} steps: - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 diff --git a/dist/index.js b/dist/index.js index 501346742..1663be8a6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3337,20 +3337,10 @@ function run() { if (!validateDistros(targetRos1Distro, targetRos2Distro)) { return; } - // Source any installed ROS binary distribution, safely creating an empty setup file if it is not present - let commandPrefix = ""; - if (isLinux) { - if (targetRos1Distro) { - commandPrefix += `mkdir -p /opt/ros/${targetRos1Distro} && touch /opt/ros/${targetRos1Distro}/setup.sh && source /opt/ros/${targetRos1Distro}/setup.sh && `; - } - if (targetRos2Distro) { - commandPrefix += `mkdir -p /opt/ros/${targetRos2Distro} && touch /opt/ros/${targetRos2Distro}/setup.sh && source /opt/ros/${targetRos2Distro}/setup.sh && `; - } - } - // rosdep on Windows does not reliably work on Windows, see + // rosdep does not reliably work on Windows, see // ros-infrastructure/rosdep#610 for instance. So, we do not run it. if (!isWindows) { - yield execBashCommand("rosdep update", commandPrefix); + yield execBashCommand("rosdep update"); } // Reset colcon configuration. yield io.rmRF(path.join(os.homedir(), ".colcon")); @@ -3364,7 +3354,7 @@ function run() { }; const curlFlags = curlFlagsArray.join(" "); for (let vcsRepoFileUrl of vcsRepoFileUrlListResolved) { - yield execBashCommand(`curl ${curlFlags} '${vcsRepoFileUrl}' | vcs import --force --recursive src/`, commandPrefix, options); + yield execBashCommand(`curl ${curlFlags} '${vcsRepoFileUrl}' | vcs import --force --recursive src/`, undefined, options); } // If the package under tests is part of ros.repos, remove it first. // We do not want to allow the "default" head state of the package to @@ -3373,7 +3363,7 @@ function run() { const posixRosWorkspaceDir = isWindows ? rosWorkspaceDir.replace(/\\/g, "/") : rosWorkspaceDir; - yield execBashCommand(`find "${posixRosWorkspaceDir}" -type d -and -name "${repo["repo"]}" | xargs rm -rf`, commandPrefix); + yield execBashCommand(`find "${posixRosWorkspaceDir}" -type d -and -name "${repo["repo"]}" | xargs rm -rf`); // The repo file for the repository needs to be generated on-the-fly to // incorporate the custom repository URL and branch name, when a PR is // being built. @@ -3394,20 +3384,20 @@ function run() { url: 'https://${tokenAuth}github.com/${repoFullName}.git' version: '${commitRef}'`; fs_1.default.writeFileSync(repoFilePath, repoFileContent); - yield execBashCommand("vcs import --force --recursive src/ < package.repo", commandPrefix, options); + yield execBashCommand("vcs import --force --recursive src/ < package.repo", undefined, options); // Remove all repositories the package under test does not depend on, to // avoid having rosdep installing unrequired dependencies. - yield execBashCommand(`diff --new-line-format="" --unchanged-line-format="" <(colcon list -p) <(colcon list --packages-up-to ${packageNameList.join(" ")} -p) | xargs rm -rf`, commandPrefix, options); + yield execBashCommand(`diff --new-line-format="" --unchanged-line-format="" <(colcon list -p) <(colcon list --packages-up-to ${packageNameList.join(" ")} -p) | xargs rm -rf`, undefined, options); // Install ROS dependencies for each distribution being sourced if (targetRos1Distro) { - yield execBashCommand(`DEBIAN_FRONTEND=noninteractive RTI_NC_LICENSE_ACCEPTED=yes rosdep install -r --from-paths src --ignore-src --rosdistro ${targetRos1Distro} -y || true`, commandPrefix, options); + yield execBashCommand(`DEBIAN_FRONTEND=noninteractive RTI_NC_LICENSE_ACCEPTED=yes rosdep install -r --from-paths src --ignore-src --rosdistro ${targetRos1Distro} -y || true`, undefined, options); } if (targetRos2Distro) { - yield execBashCommand(`DEBIAN_FRONTEND=noninteractive RTI_NC_LICENSE_ACCEPTED=yes rosdep install -r --from-paths src --ignore-src --rosdistro ${targetRos2Distro} -y || true`, commandPrefix, options); + yield execBashCommand(`DEBIAN_FRONTEND=noninteractive RTI_NC_LICENSE_ACCEPTED=yes rosdep install -r --from-paths src --ignore-src --rosdistro ${targetRos2Distro} -y || true`, undefined, options); } if (colconMixinName !== "" && colconMixinRepo !== "") { - yield execBashCommand(`colcon mixin add default '${colconMixinRepo}'`, commandPrefix); - yield execBashCommand("colcon mixin update default", commandPrefix); + yield execBashCommand(`colcon mixin add default '${colconMixinRepo}'`); + yield execBashCommand("colcon mixin update default"); } let extra_options = []; if (colconMixinName !== "") { @@ -3430,6 +3420,22 @@ function run() { // ament_cmake should handle this automatically, but we are seeing cases // where this does not happen. See issue #26 for relevant CI logs. core.addPath(path.join(rosWorkspaceDir, "install", "bin")); + // Source any installed ROS distributions if they are present + let colconCommandPrefix = ""; + if (isLinux) { + if (targetRos1Distro) { + const ros1SetupPath = `/opt/ros/${targetRos1Distro}/setup.sh`; + if (fs_1.default.existsSync(ros1SetupPath)) { + colconCommandPrefix += `source ${ros1SetupPath} && `; + } + } + if (targetRos2Distro) { + const ros2SetupPath = `/opt/ros/${targetRos2Distro}/setup.sh`; + if (fs_1.default.existsSync(ros2SetupPath)) { + colconCommandPrefix += `source ${ros2SetupPath} && `; + } + } + } let colconBuildCmd = `colcon build --event-handlers console_cohesion+ \ --packages-up-to ${packageNameList.join(" ")} \ ${extra_options.join(" ")} \ @@ -3437,11 +3443,11 @@ function run() { if (!isWindows) { colconBuildCmd = colconBuildCmd.concat(" --symlink-install"); } - yield execBashCommand(colconBuildCmd, commandPrefix, options); + yield execBashCommand(colconBuildCmd, colconCommandPrefix, options); // ignoreReturnCode is set to true to avoid having a lack of coverage // data fail the build. const colconLcovInitialCmd = "colcon lcov-result --initial"; - yield execBashCommand(colconLcovInitialCmd, commandPrefix, { + yield execBashCommand(colconLcovInitialCmd, colconCommandPrefix, { cwd: rosWorkspaceDir, ignoreReturnCode: true, }); @@ -3449,18 +3455,18 @@ function run() { --pytest-with-coverage --return-code-on-test-failure \ --packages-select ${packageNameList.join(" ")} \ ${extra_options.join(" ")}`; - yield execBashCommand(colconTestCmd, commandPrefix, options); + yield execBashCommand(colconTestCmd, colconCommandPrefix, options); // ignoreReturnCode, check comment above in --initial const colconLcovResultCmd = `colcon lcov-result \ --filter ${coverageIgnorePattern} \ --packages-select ${packageNameList.join(" ")}`; - yield execBashCommand(colconLcovResultCmd, commandPrefix, { + yield execBashCommand(colconLcovResultCmd, colconCommandPrefix, { cwd: rosWorkspaceDir, ignoreReturnCode: true, }); const colconCoveragepyResultCmd = `colcon coveragepy-result \ --packages-select ${packageNameList.join(" ")}`; - yield execBashCommand(colconCoveragepyResultCmd, commandPrefix, options); + yield execBashCommand(colconCoveragepyResultCmd, colconCommandPrefix, options); core.setOutput("ros-workspace-directory-name", rosWorkspaceName); } catch (error) { diff --git a/src/action-ros-ci.ts b/src/action-ros-ci.ts index ed96fb2e0..89944f91a 100644 --- a/src/action-ros-ci.ts +++ b/src/action-ros-ci.ts @@ -166,21 +166,10 @@ async function run() { return; } - // Source any installed ROS binary distribution, safely creating an empty setup file if it is not present - let commandPrefix = ""; - if (isLinux) { - if (targetRos1Distro) { - commandPrefix += `mkdir -p /opt/ros/${targetRos1Distro} && touch /opt/ros/${targetRos1Distro}/setup.sh && source /opt/ros/${targetRos1Distro}/setup.sh && `; - } - if (targetRos2Distro) { - commandPrefix += `mkdir -p /opt/ros/${targetRos2Distro} && touch /opt/ros/${targetRos2Distro}/setup.sh && source /opt/ros/${targetRos2Distro}/setup.sh && `; - } - } - - // rosdep on Windows does not reliably work on Windows, see + // rosdep does not reliably work on Windows, see // ros-infrastructure/rosdep#610 for instance. So, we do not run it. if (!isWindows) { - await execBashCommand("rosdep update", commandPrefix); + await execBashCommand("rosdep update"); } // Reset colcon configuration. @@ -201,7 +190,7 @@ async function run() { for (let vcsRepoFileUrl of vcsRepoFileUrlListResolved) { await execBashCommand( `curl ${curlFlags} '${vcsRepoFileUrl}' | vcs import --force --recursive src/`, - commandPrefix, + undefined, options ); } @@ -215,8 +204,7 @@ async function run() { ? rosWorkspaceDir.replace(/\\/g, "/") : rosWorkspaceDir; await execBashCommand( - `find "${posixRosWorkspaceDir}" -type d -and -name "${repo["repo"]}" | xargs rm -rf`, - commandPrefix + `find "${posixRosWorkspaceDir}" -type d -and -name "${repo["repo"]}" | xargs rm -rf` ); // The repo file for the repository needs to be generated on-the-fly to @@ -241,7 +229,7 @@ async function run() { fs.writeFileSync(repoFilePath, repoFileContent); await execBashCommand( "vcs import --force --recursive src/ < package.repo", - commandPrefix, + undefined, options ); @@ -251,7 +239,7 @@ async function run() { `diff --new-line-format="" --unchanged-line-format="" <(colcon list -p) <(colcon list --packages-up-to ${packageNameList.join( " " )} -p) | xargs rm -rf`, - commandPrefix, + undefined, options ); @@ -259,24 +247,23 @@ async function run() { if (targetRos1Distro) { await execBashCommand( `DEBIAN_FRONTEND=noninteractive RTI_NC_LICENSE_ACCEPTED=yes rosdep install -r --from-paths src --ignore-src --rosdistro ${targetRos1Distro} -y || true`, - commandPrefix, + undefined, options ); } if (targetRos2Distro) { await execBashCommand( `DEBIAN_FRONTEND=noninteractive RTI_NC_LICENSE_ACCEPTED=yes rosdep install -r --from-paths src --ignore-src --rosdistro ${targetRos2Distro} -y || true`, - commandPrefix, + undefined, options ); } if (colconMixinName !== "" && colconMixinRepo !== "") { await execBashCommand( - `colcon mixin add default '${colconMixinRepo}'`, - commandPrefix + `colcon mixin add default '${colconMixinRepo}'` ); - await execBashCommand("colcon mixin update default", commandPrefix); + await execBashCommand("colcon mixin update default"); } let extra_options: string[] = []; @@ -302,6 +289,23 @@ async function run() { // where this does not happen. See issue #26 for relevant CI logs. core.addPath(path.join(rosWorkspaceDir, "install", "bin")); + // Source any installed ROS distributions if they are present + let colconCommandPrefix = ""; + if (isLinux) { + if (targetRos1Distro) { + const ros1SetupPath = `/opt/ros/${targetRos1Distro}/setup.sh`; + if (fs.existsSync(ros1SetupPath)) { + colconCommandPrefix += `source ${ros1SetupPath} && `; + } + } + if (targetRos2Distro) { + const ros2SetupPath = `/opt/ros/${targetRos2Distro}/setup.sh`; + if (fs.existsSync(ros2SetupPath)) { + colconCommandPrefix += `source ${ros2SetupPath} && `; + } + } + } + let colconBuildCmd = `colcon build --event-handlers console_cohesion+ \ --packages-up-to ${packageNameList.join(" ")} \ ${extra_options.join(" ")} \ @@ -309,12 +313,12 @@ async function run() { if (!isWindows) { colconBuildCmd = colconBuildCmd.concat(" --symlink-install"); } - await execBashCommand(colconBuildCmd, commandPrefix, options); + await execBashCommand(colconBuildCmd, colconCommandPrefix, options); // ignoreReturnCode is set to true to avoid having a lack of coverage // data fail the build. const colconLcovInitialCmd = "colcon lcov-result --initial"; - await execBashCommand(colconLcovInitialCmd, commandPrefix, { + await execBashCommand(colconLcovInitialCmd, colconCommandPrefix, { cwd: rosWorkspaceDir, ignoreReturnCode: true, }); @@ -323,20 +327,20 @@ async function run() { --pytest-with-coverage --return-code-on-test-failure \ --packages-select ${packageNameList.join(" ")} \ ${extra_options.join(" ")}`; - await execBashCommand(colconTestCmd, commandPrefix, options); + await execBashCommand(colconTestCmd, colconCommandPrefix, options); // ignoreReturnCode, check comment above in --initial const colconLcovResultCmd = `colcon lcov-result \ --filter ${coverageIgnorePattern} \ --packages-select ${packageNameList.join(" ")}`; - await execBashCommand(colconLcovResultCmd, commandPrefix, { + await execBashCommand(colconLcovResultCmd, colconCommandPrefix, { cwd: rosWorkspaceDir, ignoreReturnCode: true, }); const colconCoveragepyResultCmd = `colcon coveragepy-result \ --packages-select ${packageNameList.join(" ")}`; - await execBashCommand(colconCoveragepyResultCmd, commandPrefix, options); + await execBashCommand(colconCoveragepyResultCmd, colconCommandPrefix, options); core.setOutput("ros-workspace-directory-name", rosWorkspaceName); } catch (error) {