diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..a82962f --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,11 @@ +^.dockerignore$ +^.github/ +^.lintr$ +^Dockerfile$ +^LICENSE\.md$ +^docker-compose.yml$ +^input_dir/ +^output_dir/ +^portfolios/ +^run-pacta.sh$ +^workflow.pacta.Rproj$ diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..70fe075 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +**/.git +**/.github +**/.gitignore +**/Dockerfile +**/*.md +**/*.Rproj +output_dir/**/* +output_dir +pacta-data/**/* +pacta-data +docker-compose.yml diff --git a/.github/workflows/R.yml b/.github/workflows/R.yml new file mode 100644 index 0000000..1023ad1 --- /dev/null +++ b/.github/workflows/R.yml @@ -0,0 +1,22 @@ +--- +# This example file will enable R language checks on push or PR to the main +# branch. +# It will also run the checks every weeknight at midnight UTC +# +# Note the @main in `uses:` on the last line. This will call the latest version +# of the workflow from the `main` brnach in the RMI-PACTA/actions repo. You can +# also specify a tag from that repo, or a commit SHA to pin action versions. +on: + pull_request: + push: + branches: [main] + schedule: + - cron: '0 0 * * 1,2,3,4,5' + workflow_dispatch: + +name: R + +jobs: + R-package: + name: R Package Checks + uses: RMI-PACTA/actions/.github/workflows/R.yml@main diff --git a/.github/workflows/build-Docker-image-nightly.yml b/.github/workflows/build-Docker-image-nightly.yml deleted file mode 100644 index 546b98b..0000000 --- a/.github/workflows/build-Docker-image-nightly.yml +++ /dev/null @@ -1,12 +0,0 @@ -on: - schedule: - - cron: '0 0 * * 1,2,3,4,5' - -jobs: - build_docker_image: - name: "Call build and push action" - uses: ./.github/workflows/build-and-push-Docker-image.yml - secrets: inherit - with: - image-name: workflow.pacta.report - image-tag: nightly diff --git a/.github/workflows/build-Docker-image-on-push-to-main.yml b/.github/workflows/build-Docker-image-on-push-to-main.yml deleted file mode 100644 index a442b85..0000000 --- a/.github/workflows/build-Docker-image-on-push-to-main.yml +++ /dev/null @@ -1,12 +0,0 @@ -on: - push: - branches: [main] - -jobs: - build_docker_image: - name: "Call build and push action" - uses: ./.github/workflows/build-and-push-Docker-image.yml - secrets: inherit - with: - image-name: workflow.pacta.report - image-tag: main diff --git a/.github/workflows/build-Docker-image-on-push-to-pr.yml b/.github/workflows/build-Docker-image-on-push-to-pr.yml deleted file mode 100644 index cf4b0f9..0000000 --- a/.github/workflows/build-Docker-image-on-push-to-pr.yml +++ /dev/null @@ -1,37 +0,0 @@ -on: - pull_request: - -jobs: - build_docker_image: - name: "Call build and push action" - uses: ./.github/workflows/build-and-push-Docker-image.yml - secrets: inherit - with: - image-name: workflow.pacta.report - image-tag: pr${{ github.event.pull_request.number }} - - add_comment: - needs: build_docker_image - runs-on: ubuntu-latest - steps: - - name: Find Comment - # https://github.com/peter-evans/find-comment - uses: peter-evans/find-comment@v2 - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: 'github-actions[bot]' - body-includes: Docker image from this PR - - - name: Create or update comment - # https://github.com/peter-evans/create-or-update-comment - uses: peter-evans/create-or-update-comment@v3 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: | - Docker image from this PR (${{ github.event.pull_request.head.sha }}) created - ``` - docker pull ${{ needs.build_docker_image.outputs.full-image-name }} - ``` - edit-mode: replace diff --git a/.github/workflows/build-and-push-Docker-image.yml b/.github/workflows/build-and-push-Docker-image.yml deleted file mode 100644 index b6d8e1e..0000000 --- a/.github/workflows/build-and-push-Docker-image.yml +++ /dev/null @@ -1,67 +0,0 @@ ---- -name: Build and push docker image - -on: - workflow_call: - inputs: - image-name: - required: true - type: string - image-tag: - required: true - type: string - outputs: - full-image-name: - description: "Full pushed image name including host/registry, name, and tag" - value: ${{ jobs.docker.outputs.full-image-name }} - -jobs: - docker: - runs-on: ubuntu-latest - permissions: - packages: write - contents: read - timeout-minutes: 25 - outputs: - full-image-name: ${{ steps.image-name.outputs.full-image-name }} - - steps: - - - name: Define image name - id: image-name - run: | - full_image_name="ghcr.io/${{ github.repository_owner }}/${{ inputs.image-name }}:${{ inputs.image-tag }}" - full_image_name=$(echo $full_image_name | tr '[A-Z]' '[a-z]') - echo "full-image-name=$full_image_name" >> "$GITHUB_OUTPUT" - echo "$full_image_name" > full-image-name - - - uses: actions/upload-artifact@v3 - with: - name: full-image-name - path: . - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v5 - with: - push: true - tags: ${{ steps.image-name.outputs.full-image-name }} - cache-from: type=gha - cache-to: type=gha,mode=min - no-cache-filters: install-pacta - - check-system-dependencies: - name: "Check System Dependencies" - needs: docker - uses: ./.github/workflows/check-R-sysdeps.yml - with: - image: ${{ needs.docker.outputs.full-image-name }} \ No newline at end of file diff --git a/.github/workflows/check-R-sysdeps.yml b/.github/workflows/check-R-sysdeps.yml deleted file mode 100644 index 3a1c08b..0000000 --- a/.github/workflows/check-R-sysdeps.yml +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: Check R system dependencies - -on: - workflow_call: - inputs: - image: - required: true - type: string - -jobs: - - check-system-dependencies: - runs-on: ubuntu-latest - steps: - - name: 'Pull image' - run: | - echo ${{ inputs.image }} - docker pull ${{ inputs.image }} - - name: 'Run pak::sysreqs_check_installed()' - run: | - - docker run \ - --rm \ - --entrypoint "/bin/sh" \ - ${{ inputs.image }} \ - -c "Rscript -e ' - x <- pak::sysreqs_check_installed() - print(x) - is_installed <- as.data.frame(x)[[\"installed\"]] - stopifnot(all(is_installed)) - '" diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..9274fd8 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,39 @@ +--- +on: + pull_request: + push: + branches: [main] + schedule: + - cron: '0 0 * * 1,2,3,4,5' + workflow_dispatch: + +name: docker + +jobs: + docker: + name: Docker actions + uses: RMI-PACTA/actions/.github/workflows/docker.yml@main + + test: + name: Test + uses: ./.github/workflows/test.yml + needs: [docker] + secrets: inherit + strategy: + fail-fast: false + matrix: + config-name: + - default_2022Q4 + - default_2023Q4 + # - full_params_2023Q4 + with: + full-image-name: ${{ needs.docker.outputs.full-image-name }} + config-name: ${{ matrix.config-name }} + + add-comment: + if: ${{ github.event_name == 'pull_request' }} + uses: RMI-PACTA/actions/.github/workflows/add-comment-table.yml@main + needs: [test] + with: + header: "Report Links" + artifact-prefix: report-comment-json diff --git a/.github/workflows/run-hadolint.yml b/.github/workflows/run-hadolint.yml deleted file mode 100644 index 0f07812..0000000 --- a/.github/workflows/run-hadolint.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -on: [push, pull_request] - -jobs: - hadolint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: hadolint/hadolint-action@v3.1.0 - with: - dockerfile: Dockerfile diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..6490b27 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,205 @@ +--- +name: Test docker image + +on: + workflow_call: + inputs: + full-image-name: + required: true + type: string + config-name: + required: true + type: string + results-url: + description: azure blob store path for results + required: false + default: "https://pactadatadev.blob.core.windows.net/ghactions-workflow-pacta-report-results" + type: string + +jobs: + test: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + + - name: Checkout workflow.pacta + uses: actions/checkout@v4 + + - name: Prepare environment + id: prepare + env: + CONFIG_NAME: ${{ inputs.config-name }} + run: | + config_file="tests/config/$CONFIG_NAME.json" + echo "config_file: $config_file" + + HOLDINGS_DATE="$(jq -rc '.holdingsDate' $config_file)" + echo "holdings-date=$HOLDINGS_DATE" + echo "holdings-date=$HOLDINGS_DATE" >> "$GITHUB_OUTPUT" + + PACTA_DATA_URL="$(jq -rc '.pactaDataURL' $config_file)" + echo "pacta-data-url=$PACTA_DATA_URL" + echo "pacta-data-url=$PACTA_DATA_URL" >> "$GITHUB_OUTPUT" + + BENCHMARKS_URL="$(jq -rc '.benchmarksURL' $config_file)" + echo "benchmarks-url=$BENCHMARKS_URL" + echo "benchmarks-url=$BENCHMARKS_URL" >> "$GITHUB_OUTPUT" + + RESULTS_URL="$(jq -rc '.resultsURL' $config_file)" + echo "results-url=$RESULTS_URL" + echo "results-url=$RESULTS_URL" >> "$GITHUB_OUTPUT" + + # includes handling for null/missing keys + PARAMETERS="$(jq -rc '.parameters | select( . != null )' $config_file)" + echo "parameters=$PARAMETERS" + echo "parameters=$PARAMETERS" >> "$GITHUB_OUTPUT" + + # https://github.com/Azure/login?tab=readme-ov-file#login-with-openid-connect-oidc-recommended + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + # https://github.com/marketplace/actions/azure-cli-action#workflow-to-execute-an-azure-cli-script-of-a-specific-cli-version + - name: Download outputs from workflow.pacta + uses: azure/CLI@v2 + env: + RESULTS_URL: ${{ steps.prepare.outputs.results-url }} + with: + # azcliversion: 2.30.0 + inlineScript: | + az storage copy \ + --source "$RESULTS_URL/*" \ + --destination "analysis_output_dir/" \ + --recursive \ + --exclude-pattern "*.sqlite" + + # https://github.com/marketplace/actions/azure-cli-action#workflow-to-execute-an-azure-cli-script-of-a-specific-cli-version + - name: Download Benchmark Results + uses: azure/CLI@v2 + env: + BENCHMARKS_URL: ${{ steps.prepare.outputs.benchmarks-url }} + with: + # azcliversion: 2.30.0 + inlineScript: | + az storage copy \ + --source "$BENCHMARKS_URL/*" \ + --destination "benchmarks_dir/" \ + --recursive \ + --exclude-pattern "*.sqlite" + + - name: Run Docker Image + env: + FULL_IMAGE_NAME: ${{ inputs.full-image-name }} + ANALYSIS_OUTPUT_DIR: analysis_output_dir + BENCHMARKS_DIR: benchmarks_dir + REPORT_OUTPUT_DIR: report_output_dir + SUMMARY_OUTPUT_DIR: summary_output_dir + WORKSPACE: ${{ github.workspace }} + PARAMETERS: ${{ steps.prepare.outputs.parameters }} + REAL_ESTATE_DIR: real_estate_dir + SURVEY_DIR: survey_dir + run: | + mkdir -p "$REPORT_OUTPUT_DIR" + chmod -R 777 "$REPORT_OUTPUT_DIR" + mkdir -p "$SUMMARY_OUTPUT_DIR" + chmod -R 777 "$SUMMARY_OUTPUT_DIR" + mkdir -p "$REAL_ESTATE_DIR" + chmod -R 777 "$REAL_ESTATE_DIR" + mkdir -p "$SURVEY_DIR" + chmod -R 777 "$SURVEY_DIR" + + docker run \ + --network none \ + --env LOG_LEVEL=TRACE \ + --env ANALYSIS_OUTPUT_DIR="/mnt/analysis_output_dir" \ + --env BENCHMARKS_DIR="/mnt/benchmarks_dir" \ + --env REPORT_OUTPUT_DIR="/mnt/report_output_dir" \ + --env SUMMARY_OUTPUT_DIR="/mnt/summary_output_dir" \ + --mount type=bind,readonly,source=${WORKSPACE}/${BENCHMARKS_DIR},target=/mnt/benchmarks_dir \ + --mount type=bind,readonly,source=${WORKSPACE}/${ANALYSIS_OUTPUT_DIR},target=/mnt/analysis_output_dir \ + --mount type=bind,source=${WORKSPACE}/${REPORT_OUTPUT_DIR},target=/mnt/report_output_dir \ + --mount type=bind,source=${WORKSPACE}/${SUMMARY_OUTPUT_DIR},target=/mnt/summary_output_dir \ + $FULL_IMAGE_NAME \ + $PARAMETERS + + - name: List outputs + run: | + ls -lR report_output_dir + ls -lR summary_output_dir + + # https://github.com/marketplace/actions/azure-cli-action#workflow-to-execute-an-azure-cli-script-of-a-specific-cli-version + - name: Upload results to blob store + id: upload + uses: azure/CLI@v2 + env: + CONFIG_NAME: ${{ inputs.config-name }} + GITHUB_REF_NAME: ${{ github.ref_name}} + GITHUB_RUN_ATTEMPT: ${{ github.run_attempt }} + GITHUB_RUN_NUMBER: ${{ github.run_number }} + REPORT_OUTPUT_DIR: report_output_dir + SUMMARY_OUTPUT_DIR: summary_output_dir + RESULTS_URL: ${{ inputs.results-url }} + with: + inlineScript: | + unique_directory="$RESULTS_URL/$GITHUB_REF_NAME/$GITHUB_RUN_NUMBER/$GITHUB_RUN_ATTEMPT/$CONFIG_NAME" + az storage copy \ + --source "$REPORT_OUTPUT_DIR"/* \ + --destination "$unique_directory" \ + --recursive + echo "report-url=${unique_directory}/report/index.html" >> "$GITHUB_OUTPUT" + + az storage copy \ + --source "$SUMMARY_OUTPUT_DIR"/* \ + --destination "$unique_directory" \ + --recursive + summary_files="$(ls $SUMMARY_OUTPUT_DIR/executive_summary/*.pdf)" + echo "summary-url=${unique_directory}/executive_summary/$summary_files" >> "$GITHUB_OUTPUT" + + - name: Prepare comment artifact + id: prepare-artifact + env: + commit_time: ${{ github.event.pull_request.updated_at }} + config_name: ${{ inputs.config-name }} + full_image_name: ${{ inputs.full-image-name }} + git_sha: ${{ github.event.pull_request.head.sha }} + report_url: ${{ steps.upload.outputs.report-url }} + summary_url: ${{ steps.upload.outputs.summary-url }} + run: | + mkdir -p /tmp/comment-json + json_filename="$( \ + echo "report-comment-json-merge-$full_image_name-$config_name" | \ + tr '/:._' '-' \ + ).json" + echo "json-filename=$json_filename" >> "$GITHUB_OUTPUT" + json_file="/tmp/comment-json/$json_filename" + jq \ + -n \ + --arg commit_time "$commit_time" \ + --arg config_name "$config_name" \ + --arg git_sha "$git_sha" \ + --arg report_url "$report_url" \ + --arg summary_url "$summary_url" \ + --arg full_image_name "$full_image_name" \ + '{ + "commit_time": $commit_time, + "git_sha": $git_sha, + "config": $config_name, + "report": ("[Report](" + $report_url + ")"), + "summary": (if (("" + $summary_url) == "") then null else "[Summary](" + $summary_url + ")" end), + "image": ("`" + $full_image_name + "`") + }' \ + >> $json_file + cat "$json_file" + + - name: Upload comment JSON + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.prepare-artifact.outputs.json-filename }} + path: /tmp/comment-json/* + if-no-files-found: error + retention-days: 1 diff --git a/.lintr b/.lintr new file mode 100644 index 0000000..b9931e6 --- /dev/null +++ b/.lintr @@ -0,0 +1,7 @@ +linters: linters_with_defaults( + commented_code_linter = NULL, + cyclocomp_linter = NULL, + object_length_linter(35), + line_length_linter(120) + ) + diff --git a/DESCRIPTION b/DESCRIPTION index f108a0e..89824c6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,11 +1,36 @@ -Type: PACTA -Description: Run PACTA. -Depends: - dplyr, - fs, - jsonlite, - logger, - pacta.executive.summary, - pacta.portfolio.report, - pacta.portfolio.utils, - readr +Package: workflow.pacta.report +Title: Reporting functionality for PACTA +Version: 0.0.0.9001 +Authors@R: + c(person(given = "Alex", + family = "Axthelm", + role = c("aut", "cre", "ctr"), + email = "aaxthelm@rmi.org", + comment = c(ORCID = "0000-0001-8579-8565")), + person(given = "Jackson", + family = "Hoffart", + email = "jackson.hoffart@gmail.com", + role = c("aut", "ctr"), + comment = c(ORCID = "0000-0002-8600-5042")), + person(given = "RMI", + role = c("cph", "fnd"), + email = "PACTA4investors@rmi.org")) +Description: Create Interactive Reports and Executive Summaries for PACTA. +License: MIT + file LICENSE +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.1 +Imports: + dplyr, + jsonlite, + logger, + pacta.executive.summary, + pacta.portfolio.report, + pacta.portfolio.utils, + pacta.workflow.utils, + readr +Remotes: + RMI-PACTA/pacta.executive.summary, + RMI-PACTA/pacta.portfolio.report, + RMI-PACTA/pacta.portfolio.utils, + RMI-PACTA/pacta.workflow.utils diff --git a/Dockerfile b/Dockerfile index 062a4a5..8fc65d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,76 +1,77 @@ -# using rocker r-vers as a base with R 4.3.1 -# https://hub.docker.com/r/rocker/r-ver -# https://rocker-project.org/images/versioned/r-ver.html -# -# sets CRAN repo to use Posit Package Manager to freeze R package versions to -# those available on 2023-10-30 -# https://packagemanager.posit.co/client/#/repos/2/overview -# https://packagemanager.posit.co/cran/__linux__/jammy/2023-10-30 - -# set proper base image -ARG R_VERS="4.3.1" -FROM ghcr.io/rmi-pacta/workflow.pacta:main AS base +FROM docker.io/rocker/r-ver:4.3.1 AS base # set Docker image labels LABEL org.opencontainers.image.source=https://github.com/RMI-PACTA/workflow.pacta.report -LABEL org.opencontainers.image.description="Docker image to run PACTA" +LABEL org.opencontainers.image.description="Docker image to create PACTA reports and executive summaries" LABEL org.opencontainers.image.licenses=MIT -LABEL org.opencontainers.image.title="" -LABEL org.opencontainers.image.revision="" -LABEL org.opencontainers.image.version="" -LABEL org.opencontainers.image.vendor="" -LABEL org.opencontainers.image.base.name="" -LABEL org.opencontainers.image.ref.name="" -LABEL org.opencontainers.image.authors="" - -# set apt-get to noninteractive mode -ARG DEBIAN_FRONTEND="noninteractive" -ARG DEBCONF_NOWARNINGS="yes" +LABEL org.opencontainers.image.title="workflow.pacta.report" +LABEL org.opencontainers.image.vendor="RMI" +LABEL org.opencontainers.image.base.name="docker.io/rocker/r-ver:4.3.1" +LABEL org.opencontainers.image.authors="Alex Axthelm" # install system dependencies +USER root RUN apt-get update \ - && apt-get install -y --no-install-recommends \ + && DEBIAN_FRONTEND="noninteractive" \ + apt-get install -y --no-install-recommends \ + git=1:2.34.* \ + libcurl4-openssl-dev=7.81.* \ + libgit2-dev=1.1.* \ + libicu-dev=70.* \ libpng-dev=1.6.* \ + libssl-dev=3.0.* \ libxt6=1:1.2.* \ pandoc=2.9.* \ && chmod -R a+rwX /root \ && rm -rf /var/lib/apt/lists/* -# set frozen CRAN repo -ARG CRAN_REPO="https://packagemanager.posit.co/cran/__linux__/jammy/2024-03-05" -RUN echo "options(repos = c(CRAN = '$CRAN_REPO'), pkg.sysreqs = FALSE)" >> "${R_HOME}/etc/Rprofile.site" \ - # install packages for dependency resolution and installation - && Rscript -e "install.packages('pak'); pak::pkg_install('renv')" +# set frozen CRAN repo and RProfile.site +# This block makes use of the builtin ARG $TARGETPLATFORM (See: +# https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/ +# ) to pick the correct CRAN-like repo, which will let us target binaries for +# supported platforms +ARG TARGETPLATFORM +RUN PACKAGE_PIN_DATE="2024-04-05" && \ + echo "TARGETPLATFORM: $TARGETPLATFORM" && \ + if [ "$TARGETPLATFORM" = "linux/amd64" ] && grep -q -e "Jammy Jellyfish" "/etc/os-release" ; then \ + CRAN_LIKE_URL="https://packagemanager.posit.co/cran/__linux__/jammy/$PACKAGE_PIN_DATE"; \ + else \ + CRAN_LIKE_URL="https://packagemanager.posit.co/cran/$PACKAGE_PIN_DATE"; \ + fi && \ + echo "CRAN_LIKE_URL: $CRAN_LIKE_URL" && \ + printf "options(\n \ + repos = c(CRAN = '%s'),\n \ + pak.no_extra_messages = TRUE,\n \ + pkg.sysreqs = FALSE,\n \ + pkg.sysreqs_db_update = FALSE,\n \ + pkg.sysreqs_update = FALSE\n \ + )\n" \ + "$CRAN_LIKE_URL" \ + > "${R_HOME}/etc/Rprofile.site" \ + && Rscript -e "install.packages('pak', repos = sprintf('https://r-lib.github.io/p/pak/stable/%s/%s/%s', .Platform[['pkgType']], R.Version()[['os']], R.Version()[['arch']]))" -FROM base AS install-pacta +# Create and use non-root user +# -m creates a home directory, +# -G adds user to staff group allowing R package installation. +RUN useradd \ + -m \ + -G staff \ + workflow-pacta-report +USER workflow-pacta-report +WORKDIR /home/workflow-pacta-report # copy in everything from this repo -COPY DESCRIPTION /DESCRIPTION +COPY DESCRIPTION /workflow.pacta.report/DESCRIPTION -# PACTA R package tags -ARG report_tag="/tree/main" -ARG summary_tag="/tree/main" -ARG utils_tag="/tree/main" +# Rprofile, including CRAN-like repos are inhertied from base image +# install pak, find dependencises from DESCRIPTION, and install them. +RUN Rscript -e "pak::local_install_deps(root = '/workflow.pacta.report')" -ARG report_url="https://github.com/rmi-pacta/pacta.portfolio.report" -ARG summary_url="https://github.com/rmi-pacta/pacta.executive.summary" -ARG utils_url="https://github.com/rmi-pacta/pacta.portfolio.utils" +FROM base AS install-pacta -# install R package dependencies -RUN Rscript -e "\ - gh_pkgs <- \ - c( \ - paste0('$report_url', '$report_tag'), \ - paste0('$summary_url', '$summary_tag'), \ - paste0('$utils_url', '$utils_tag') \ - ); \ - workflow_pkgs <- renv::dependencies('DESCRIPTION')[['Package']]; \ - workflow_pkgs <- grep('^pacta[.]', workflow_pkgs, value = TRUE, invert = TRUE); \ - pak::pak(c(gh_pkgs, workflow_pkgs)); \ - " +COPY . /workflow.pacta.report/ -COPY . / +RUN Rscript -e "pak::local_install(root = '/workflow.pacta.report')" # set default run behavior -ENTRYPOINT ["/run-pacta.sh"] -CMD ["input_dir/default_config.json"] +ENTRYPOINT ["Rscript", "--vanilla", "/workflow.pacta.report/inst/extdata/scripts/run_pacta_report.R"] diff --git a/LICENSE b/LICENSE index 844b42c..7ec6c95 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,2 @@ -MIT License - -Copyright (c) 2023 RMI - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +YEAR: 2024 +COPYRIGHT HOLDER: RMI diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c3f0481 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2024 RMI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..0a6e867 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,8 @@ +# Generated by roxygen2: do not edit by hand + +importFrom(logger,log_debug) +importFrom(logger,log_error) +importFrom(logger,log_fatal) +importFrom(logger,log_info) +importFrom(logger,log_trace) +importFrom(logger,log_warn) diff --git a/R/prepare_executive_summary.R b/R/prepare_executive_summary.R new file mode 100644 index 0000000..9ab596a --- /dev/null +++ b/R/prepare_executive_summary.R @@ -0,0 +1,111 @@ +prepare_executive_summary <- function( + summary_output_dir, + survey_dir, + real_estate_dir, + score_card_dir, + project_code, + language_select, + peer_group, + investor_name, + portfolio_name, + start_year, + currency_exchange_value, + total_portfolio, + equity_results_portfolio, + bonds_results_portfolio, + indices_equity_results_portfolio, + indices_bonds_results_portfolio, + audit_file, + emissions, + peers_bonds_results_portfolio, + peers_bonds_results_user, + peers_equity_results_portfolio, + peers_equity_results_user +) { + log_debug("Preparing to create executive summary.") + + es_dir <- file.path(summary_output_dir, "executive_summary") + if (!dir.exists(es_dir)) { + dir.create(es_dir, showWarnings = FALSE, recursive = TRUE) + } + + log_trace("Defining executive summary template paths.") + exec_summary_template_name <- paste0(project_code, "_", tolower(language_select), "_exec_summary") + exec_summary_builtin_template_path <- system.file( + "extdata", exec_summary_template_name, + package = "pacta.executive.summary" + ) + invisible(file.copy(exec_summary_builtin_template_path, summary_output_dir, recursive = TRUE, copy.mode = FALSE)) + exec_summary_template_path <- file.path(summary_output_dir, exec_summary_template_name) + + if ( + dir.exists(exec_summary_template_path) && ( + peer_group %in% c("assetmanager", "bank", "insurance", "pensionfund") + ) + ) { + log_debug("Preparing data for executive summary.") + data_aggregated_filtered <- + pacta.executive.summary::prep_data_executive_summary( + investor_name = investor_name, + portfolio_name = portfolio_name, + peer_group = peer_group, + start_year = start_year, + scenario_source = "GECO2021", + scenario_selected = "1.5C-Unif", + scenario_geography = "Global", + equity_market = "GlobalMarket", + portfolio_allocation_method_equity = "portfolio_weight", + portfolio_allocation_method_bonds = "portfolio_weight", + green_techs = c( + "RenewablesCap", + "HydroCap", + "NuclearCap", + "Hybrid", + "Electric", + "FuelCell", + "Hybrid_HDV", + "Electric_HDV", + "FuelCell_HDV", + "Electric Arc Furnace" + ), + equity_results_portfolio = equity_results_portfolio, + bonds_results_portfolio = bonds_results_portfolio, + peers_equity_results_aggregated = peers_equity_results_portfolio, + peers_bonds_results_aggregated = peers_bonds_results_portfolio, + peers_equity_results_individual = peers_equity_results_user, + peers_bonds_results_individual = peers_bonds_results_user, + indices_equity_results_portfolio = indices_equity_results_portfolio, + indices_bonds_results_portfolio = indices_bonds_results_portfolio, + audit_file = audit_file, + emissions_portfolio = emissions, + score_card_dir = score_card_dir + ) + + log_trace("Checking for real estate data.") + real_estate_flag <- (length(list.files(real_estate_dir)) > 0) + + log_info("Creating executive summary.") + pacta.executive.summary::render_executive_summary( + data = data_aggregated_filtered, + language = language_select, + output_dir = es_dir, + exec_summary_dir = exec_summary_template_path, + survey_dir = survey_dir, + real_estate_dir = real_estate_dir, + real_estate_flag = real_estate_flag, + score_card_dir = score_card_dir, + file_name = "template.Rmd", + investor_name = investor_name, + portfolio_name = portfolio_name, + peer_group = peer_group, + total_portfolio = total_portfolio, + scenario_selected = "1.5C-Unif", + currency_exchange_value = currency_exchange_value, + log_dir = summary_output_dir + ) + } else { + # this is required for the online tool to know that the process has been completed. + log_debug("No executive summary created.") + invisible(file.copy(pacta.executive.summary::blank_pdf(), es_dir)) + } +} diff --git a/R/prepare_interactive_report.R b/R/prepare_interactive_report.R new file mode 100644 index 0000000..f35cbbe --- /dev/null +++ b/R/prepare_interactive_report.R @@ -0,0 +1,117 @@ +prepare_interactive_report <- function( + report_output_dir, + project_report_name, + survey_dir, + real_estate_dir, + language_select, + peer_group, + investor_name, + portfolio_name, + start_year, + currency_exchange_value, + select_scenario, + scenario_other, + portfolio_allocation_method, + scenario_geography, + sector_list, + green_techs, + tech_roadmap_sectors, + pacta_sectors_not_analysed, + display_currency, + audit_file, + emissions, + portfolio_overview, + equity_results_portfolio, + bonds_results_portfolio, + equity_results_company, + bonds_results_company, + equity_results_map, + bonds_results_map, + indices_bonds_results_portfolio, + indices_equity_results_portfolio, + peers_bonds_results_portfolio, + peers_bonds_results_user, + peers_equity_results_portfolio, + peers_equity_results_user, + analysis_output_manifest +) { + log_debug("Preparing to create interactive report.") + + log_debug("Loading data frame label translations.") + dataframe_translations <- readr::read_csv( + system.file("extdata/translation/dataframe_labels.csv", package = "pacta.portfolio.report"), + col_types = readr::cols() + ) + + log_debug("Loading data frame header translations.") + header_dictionary <- readr::read_csv( + system.file("extdata/translation/dataframe_headers.csv", package = "pacta.portfolio.report"), + col_types = readr::cols() + ) + + log_debug("Loading JavaScript label translations.") + js_translations <- jsonlite::fromJSON( + txt = system.file("extdata/translation/js_labels.json", package = "pacta.portfolio.report") + ) + + log_debug("Loading sector order.") + sector_order <- readr::read_csv( + system.file("extdata/sector_order/sector_order.csv", package = "pacta.portfolio.report"), + col_types = readr::cols() + ) + + # combine config files to send to create_interactive_report() + log_trace("Defining configs and manifest.") + + configs <- list( + analysis_output_manifest = analysis_output_manifest + ) + + log_trace("Defining interactive report template paths.") + template_path <- system.file("templates", package = "pacta.portfolio.report") + template_dir_name <- paste(tolower(project_report_name), tolower(language_select), "template", sep = "_") + template_dir <- file.path(template_path, template_dir_name) + + log_info("Creating interactive report.") + pacta.portfolio.report::create_interactive_report( + template_dir = template_dir, + output_dir = report_output_dir, + survey_dir = survey_dir, + real_estate_dir = real_estate_dir, + language_select = language_select, + investor_name = investor_name, + portfolio_name = portfolio_name, + peer_group = peer_group, + start_year = start_year, + select_scenario = select_scenario, + select_scenario_other = scenario_other, + portfolio_allocation_method = portfolio_allocation_method, + scenario_geography = scenario_geography, + pacta_sectors = sector_list, + green_techs = green_techs, + tech_roadmap_sectors = tech_roadmap_sectors, + pacta_sectors_not_analysed = pacta_sectors_not_analysed, + audit_file = audit_file, + emissions = emissions, + portfolio_overview = portfolio_overview, + equity_results_portfolio = equity_results_portfolio, + bonds_results_portfolio = bonds_results_portfolio, + equity_results_company = equity_results_company, + bonds_results_company = bonds_results_company, + equity_results_map = equity_results_map, + bonds_results_map = bonds_results_map, + indices_equity_results_portfolio = indices_equity_results_portfolio, + indices_bonds_results_portfolio = indices_bonds_results_portfolio, + peers_equity_results_portfolio = peers_equity_results_portfolio, + peers_bonds_results_portfolio = peers_bonds_results_portfolio, + peers_equity_results_user = peers_equity_results_user, + peers_bonds_results_user = peers_bonds_results_user, + dataframe_translations = dataframe_translations, + js_translations = js_translations, + display_currency = display_currency, + currency_exchange_value = currency_exchange_value, + header_dictionary = header_dictionary, + sector_order = sector_order, + configs = configs + ) +} diff --git a/R/run_pacta_reporting_process.R b/R/run_pacta_reporting_process.R new file mode 100644 index 0000000..a599b45 --- /dev/null +++ b/R/run_pacta_reporting_process.R @@ -0,0 +1,317 @@ +run_pacta_reporting_process <- function( + raw_params = commandArgs(trailingOnly = TRUE), + analysis_output_dir = Sys.getenv("ANALYSIS_OUTPUT_DIR"), + benchmarks_dir = Sys.getenv("BENCHMARKS_DIR"), + report_output_dir = Sys.getenv("REPORT_OUTPUT_DIR"), + summary_output_dir = Sys.getenv("SUMMARY_OUTPUT_DIR"), + real_estate_dir = Sys.getenv("REAL_ESTATE_DIR"), + survey_dir = Sys.getenv("SURVEY_DIR"), + score_card_dir = Sys.getenv("SCORE_CARD_DIR") +) { + log_debug("Checking configuration.") + if (is.null(analysis_output_dir) || analysis_output_dir == "") { + log_error("ANALYSIS_OUTPUTS_DIR not set.") + stop("ANALYSIS_OUTPUTS_DIR not set.") + } + if (is.null(benchmarks_dir) || benchmarks_dir == "") { + log_error("BENCHMARKS_DIR not set.") + stop("BENCHMARKS_DIR not set.") + } + if (is.null(report_output_dir) || report_output_dir == "") { + log_error("REPORT_OUTPUT_DIR not set.") + stop("REPORT_OUTPUT_DIR not set.") + } + if (is.null(summary_output_dir) || summary_output_dir == "") { + log_error("SUMMARY_OUTPUT_DIR not set.") + stop("SUMMARY_OUTPUT_DIR not set.") + } + + # defaulting to WARN to maintain current (silent) behavior. + logger::log_threshold(Sys.getenv("LOG_LEVEL", "INFO")) + logger::log_formatter(logger::formatter_glue) + + # ------------------------------------------------------------------------- + + log_info("Starting portfolio report process") + + # Read Params + log_trace("Processing input parameters.") + if (length(raw_params) == 0L || all(raw_params == "")) { + log_error("No parameters specified.") + } + + # log_trace("Validating raw input parameters.") + # raw_input_validation_results <- jsonvalidate::json_validate( + # json = raw_params, + # schema = system.file( + # "extdata", "schema", "rawParameters.json", + # package = "workflow.pacta.report" + # ), + # verbose = TRUE, + # greedy = FALSE, + # engine = "ajv" + # ) + # if (raw_input_validation_results) { + # log_trace("Raw input parameters are valid.") + # } else { + # log_error( + # "Invalid raw input parameters. ", + # "Must include \"inherit\" key, or match full schema." + # ) + # stop("Invalid raw input parameters.") + # } + + params <- pacta.workflow.utils:::parse_params( + json = raw_params, + inheritence_search_paths = system.file( + "extdata", "parameters", + package = "workflow.pacta.report" + ) , + schema_file = NULL + # schema_file = system.file( + # "extdata", "schema", "portfolioParameters_0-0-1.json", + # package = "workflow.pacta.report" + # ) + ) + + # quit if there's no relevant PACTA assets ------------------------------------- + + log_debug("Checking for PACTA relevant data in portfolio results.") + total_portfolio_path <- file.path(analysis_output_dir, "total_portfolio.rds") + if (file.exists(total_portfolio_path)) { + total_portfolio <- readRDS(total_portfolio_path) + log_trace("Checking for PACTA relevant data in file: \"{total_portfolio_path}\".") + pacta.portfolio.utils::quit_if_no_pacta_relevant_data(total_portfolio) + } else { + log_warn("file \"{total_portfolio_path}\" does not exist.") + warning("Cannot find total_portfolio.rds file. Exiting.") + } + + + # fix parameters --------------------------------------------------------------- + + if ( + params[["project_code"]] == "GENERAL" && + params[["language_select"]] != "EN" + ) { + log_warn("Overriding language selection to \"EN\" for \"GENERAL\".") + params[["language_select"]] <- "EN" + } else { + log_trace("Using language selection: \"{params[['language_select']]}\".") + } + + + # load PACTA results ----------------------------------------------------------- + + log_info("Loading PACTA results.") + + log_debug("Loading audit file.") + audit_file <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "audit_file.rds"), + alt_return = pacta.portfolio.utils::empty_audit_file() + ) + audit_file <- add_inv_and_port_names_if_needed( + data = audit_file, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading portfolio overview.") + portfolio_overview <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "overview_portfolio.rds"), + alt_return = pacta.portfolio.utils::empty_portfolio_overview() + ) + portfolio_overview <- add_inv_and_port_names_if_needed( + data = portfolio_overview, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading emissions.") + emissions <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "emissions.rds"), + alt_return = pacta.portfolio.utils::empty_emissions_results() + ) + emissions <- add_inv_and_port_names_if_needed( + data = emissions, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading total portfolio results.") + total_portfolio <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "total_portfolio.rds"), + alt_return = pacta.portfolio.utils::empty_portfolio_results() + ) + total_portfolio <- add_inv_and_port_names_if_needed( + data = total_portfolio, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading portfolio equity results.") + equity_results_portfolio <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "Equity_results_portfolio.rds"), + alt_return = pacta.portfolio.utils::empty_portfolio_results() + ) + equity_results_portfolio <- add_inv_and_port_names_if_needed( + data = equity_results_portfolio, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading portfolio bonds results.") + bonds_results_portfolio <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "Bonds_results_portfolio.rds"), + alt_return = pacta.portfolio.utils::empty_portfolio_results() + ) + bonds_results_portfolio <- add_inv_and_port_names_if_needed( + data = bonds_results_portfolio, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading company equity results.") + equity_results_company <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "Equity_results_company.rds"), + alt_return = pacta.portfolio.utils::empty_company_results() + ) + equity_results_company <- add_inv_and_port_names_if_needed( + data = equity_results_company, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading company bonds results.") + bonds_results_company <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "Bonds_results_company.rds"), + alt_return = pacta.portfolio.utils::empty_company_results() + ) + bonds_results_company <- add_inv_and_port_names_if_needed( + data = bonds_results_company, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading equity map results.") + equity_results_map <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "Equity_results_map.rds"), + alt_return = pacta.portfolio.utils::empty_map_results() + ) + equity_results_map <- add_inv_and_port_names_if_needed( + data = equity_results_map, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + log_debug("Loading bonds map results.") + bonds_results_map <- read_rds_or_return_alt_data( + filepath = file.path(analysis_output_dir, "Bonds_results_map.rds"), + alt_return = pacta.portfolio.utils::empty_map_results() + ) + bonds_results_map <- add_inv_and_port_names_if_needed( + data = bonds_results_map, + portfolio_name = params[["portfolio_name"]], + investor_name = params[["investor_name"]] + ) + + analysis_output_manifest <- jsonlite::read_json(file.path(analysis_output_dir, "manifest.json")) + + log_debug("Loading portfolio equity peer results.") + peers_equity_results_portfolio <- read_rds_or_return_alt_data( + filepath = file.path(benchmarks_dir, paste0(params[["project_code"]], "_peers_equity_results_portfolio.rds")), + alt_return = pacta.portfolio.utils::empty_portfolio_results() + ) + + log_debug("Loading portfolio bonds peer results.") + peers_bonds_results_portfolio <- read_rds_or_return_alt_data( + filepath = file.path(benchmarks_dir, paste0(params[["project_code"]], "_peers_bonds_results_portfolio.rds")), + alt_return = pacta.portfolio.utils::empty_portfolio_results() + ) + + log_debug("Loading index equity peer results.") + peers_equity_results_user <- read_rds_or_return_alt_data( + filepath = file.path(benchmarks_dir, paste0(params[["project_code"]], "_peers_equity_results_portfolio_ind.rds")), + alt_return = pacta.portfolio.utils::empty_portfolio_results() + ) + + log_debug("Loading index bonds peer results.") + peers_bonds_results_user <- read_rds_or_return_alt_data( + filepath = file.path(benchmarks_dir, paste0(params[["project_code"]], "_peers_bonds_results_portfolio_ind.rds")), + alt_return = pacta.portfolio.utils::empty_portfolio_results() + ) + + log_debug("Loading index equity portfolio results.") + indices_equity_results_portfolio <- readRDS(file.path(benchmarks_dir, "Indices_equity_results_portfolio.rds")) + + log_debug("Loading index bonds portfolio results.") + indices_bonds_results_portfolio <- readRDS(file.path(benchmarks_dir, "Indices_bonds_results_portfolio.rds")) + + # create interactive report ---------------------------------------------------- + + prepare_interactive_report( + report_output_dir = report_output_dir, + project_report_name = params[["project_report_name"]], + survey_dir = survey_dir, + real_estate_dir = real_estate_dir, + language_select = params[["language_select"]], + peer_group = params[["peer_group"]], + investor_name = params[["investor_name"]], + portfolio_name = params[["portfolio_name"]], + start_year = params[["start_year"]], + currency_exchange_value = params[["currency_exchange_value"]], + select_scenario = params[["select_scenario"]], + scenario_other = params[["scenario_other"]], + portfolio_allocation_method = params[["portfolio_allocation_method"]], + scenario_geography = params[["scenario_geography"]], + sector_list = params[["sector_list"]], + green_techs = params[["green_techs"]], + tech_roadmap_sectors = params[["tech_roadmap_sectors"]], + pacta_sectors_not_analysed = params[["pacta_sectors_not_analysed"]], + display_currency = params[["display_currency"]], + audit_file = audit_file, + emissions = emissions, + portfolio_overview = portfolio_overview, + equity_results_portfolio = equity_results_portfolio, + bonds_results_portfolio = bonds_results_portfolio, + equity_results_company = equity_results_company, + bonds_results_company = bonds_results_company, + equity_results_map = equity_results_map, + bonds_results_map = bonds_results_map, + indices_bonds_results_portfolio = indices_bonds_results_portfolio, + indices_equity_results_portfolio = indices_equity_results_portfolio, + peers_bonds_results_portfolio = peers_bonds_results_portfolio, + peers_bonds_results_user = peers_bonds_results_user, + peers_equity_results_portfolio = peers_equity_results_portfolio, + peers_equity_results_user = peers_equity_results_user, + analysis_output_manifest = analysis_output_manifest + ) + + # create executive summary ----------------------------------------------------- + prepare_executive_summary( + summary_output_dir = summary_output_dir, + survey_dir = survey_dir, + real_estate_dir = real_estate_dir, + score_card_dir = score_card_dir, + project_code = params[["project_code"]], + language_select = params[["language_select"]], + peer_group = params[["peer_group"]], + investor_name = params[["investor_name"]], + portfolio_name = params[["portfolio_name"]], + start_year = params[["start_year"]], + currency_exchange_value = params[["currency_exchange_value"]], + total_portfolio = total_portfolio, + equity_results_portfolio = equity_results_portfolio, + bonds_results_portfolio = bonds_results_portfolio, + indices_equity_results_portfolio = indices_equity_results_portfolio, + indices_bonds_results_portfolio = indices_bonds_results_portfolio, + audit_file = audit_file, + emissions = emissions, + peers_bonds_results_portfolio = peers_bonds_results_portfolio, + peers_bonds_results_user = peers_bonds_results_user, + peers_equity_results_portfolio = peers_equity_results_portfolio, + peers_equity_results_user = peers_equity_results_user + ) + + log_info("Portfolio report finished.") +} diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..a602a3a --- /dev/null +++ b/R/utils.R @@ -0,0 +1,29 @@ +read_rds_or_return_alt_data <- function(filepath, alt_return = NULL) { + log_trace("Reading RDS file: \"filepath\"") + if (file.exists(filepath)) { + log_trace("File found. Reading data.") + data <- readRDS(filepath) + } else { + log_warn("File not found. Returning alternative data.") + data <- alt_return + } + return(data) +} + +add_inv_and_port_names_if_needed <- function(data, portfolio_name, investor_name) { + if (!inherits(data, "data.frame")) { + return(data) + } + + if (!"portfolio_name" %in% names(data)) { + log_trace("Adding portfolio_name column to data.") + data <- dplyr::mutate(data, portfolio_name = portfolio_name, .before = dplyr::everything()) + } + + if (!"investor_name" %in% names(data)) { + log_trace("Adding investor_name column to data.") + data <- dplyr::mutate(data, investor_name = investor_name, .before = dplyr::everything()) + } + + data +} diff --git a/R/workflow.pacta.report-package.R b/R/workflow.pacta.report-package.R new file mode 100644 index 0000000..98a01ae --- /dev/null +++ b/R/workflow.pacta.report-package.R @@ -0,0 +1,12 @@ +#' @keywords internal +"_PACKAGE" + +## usethis namespace: start +#' @importFrom logger log_debug +#' @importFrom logger log_error +#' @importFrom logger log_fatal +#' @importFrom logger log_info +#' @importFrom logger log_trace +#' @importFrom logger log_warn +## usethis namespace: end +NULL diff --git a/README.md b/README.md index 82bca40..cfb35aa 100644 --- a/README.md +++ b/README.md @@ -11,42 +11,4 @@ packages that it depends on. Running PACTA also requires pacta-data, which needs to be mounted into the container at run-time. -# Using Docker images pushed to GHCR automatically by GH Actions - -``` {.bash} - -tag_name=main -image_name=ghcr.io/rmi-pacta/workflow.pacta.report:$tag_name -data_dir=~/Downloads/2022Q4_transition_monitor_inputs_2023-07-11/ -input_dir=./input_dir -output_dir=./output_dir - -# Build -docker build . -t $image_name - -# Run -docker run --rm \ - --network none \ - --platform linux/amd64 \ - --env LOG_LEVEL=DEBUG \ - --mount type=bind,readonly,source=${data_dir},target=/pacta-data \ - --mount type=bind,source=${output_dir},target=/output_dir \ - --mount type=bind,source=${input_dir},target=/input_dir \ - $image_name - -``` - -```sh - -# Run R in container -docker run -it --rm \ - --network none \ - --platform linux/amd64 \ - --env LOG_LEVEL=TRACE \ - --mount type=bind,readonly,source=${data_dir},target=/pacta-data \ - --mount type=bind,source=${output_dir},target=/output_dir \ - --mount type=bind,source=${input_dir},target=/input_dir \ - --entrypoint R - $image_name - -``` +See workflow.pacta for examples of a similar docker container and invocation diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5325c70 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,41 @@ +--- +services: + workflow.pacta.report: + build: . + # stdin_open: true + # tty: true + # entrypoint: ["R", "--args"] + command: '{\"portfolio_files\": \"default_portfolio.csv\", \"inherit\": \"GENERAL_2023Q4\"}' + environment: + LOG_LEVEL: TRACE + ANALYSIS_OUTPUT_DIR: "/mnt/analysis_output_dir" + BENCHMARKS_DIR: "/mnt/benchmarks_dir" + REPORT_OUTPUT_DIR: "/mnt/report_output_dir" + SUMMARY_OUTPUT_DIR: "/mnt/summary_output_dir" + REAL_ESTATE_DIR: "/mnt/real_estate_dir" + SURVEY_DIR: "/mnt/survey_dir" + volumes: + - type: bind + source: ${benchmarks_dir:-./benchmarks_dir} + target: /mnt/benchmarks_dir/ + read_only: true + - type: bind + source: ${analysis_output_dir:-./analysis_output_dir} + target: /mnt/analysis_output_dir + read_only: true + - type: bind + source: ${real_estate_dir:-./real_estate_dir} + target: /mnt/real_estate_dir + read_only: true + - type: bind + source: ${survey_dir:-./survey_dir} + target: /mnt/survey_dir + read_only: true + - type: bind + source: ${report_output_dir:-./report_output_dir} + target: /mnt/report_output_dir + read_only: false + - type: bind + source: ${summary_output_dir:-./summary_output_dir} + target: /mnt/summary_output_dir + read_only: false diff --git a/input_dir/default_config.json b/input_dir/default_config.json deleted file mode 100644 index 1112fd7..0000000 --- a/input_dir/default_config.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "data_dir": "../pacta-data/2022Q4", - "portfolio_path": "input_dir/default_portfolio.csv", - "output_dir": "output_dir", - "start_year": 2022, - "equity_market_list": [ - "GlobalMarket", - "DevelopedMarket", - "EmergingMarket" - ], - "scenario_sources_list": [ - "GECO2022", - "IPR2021", - "ISF2021", - "WEO2022" - ], - "scenario_geographies_list": [ - "Global", - "GlobalAggregate", - "NonOECD", - "OECD" - ], - "sector_list": [ - "Power", - "Automotive", - "Oil&Gas", - "Coal", - "Steel", - "Aviation", - "Cement" - ], - "has_map": false, - "project_code": "GENERAL", - "portfolio_name": "Default Portfolio", - "investor_name": "Default Investor", - "peer_group": "bank", - "language_select": "EN", - "user_id": "4", - "project_report_name": "general", - "display_currency": "USD", - "currency_exchange_value": 1, - "select_scenario": "WEO2022_NZE_2050", - "scenario_other": "GECO2022_1.5C", - "portfolio_allocation_method": "portfolio_weight", - "scenario_geography": "Global", - "tech_roadmap_sectors": [ - "Power", - "Automotive", - "Oil&Gas", - "Coal" - ], - "pacta_sectors_not_analysed": [ - "Steel", - "Aviation", - "Cement" - ], - "green_techs": [ - "RenewablesCap", - "HydroCap", - "NuclearCap", - "Hybrid", - "Electric", - "FuelCell", - "Electric Arc Furnace" - ], - "user_results_path": "input_dir/user_results", - "real_estate_dir": "input_dir/real_estate", - "survey_dir": "input_dir/survey" -} diff --git a/inst/extdata/parameters/GENERAL.json b/inst/extdata/parameters/GENERAL.json new file mode 100644 index 0000000..8012eb5 --- /dev/null +++ b/inst/extdata/parameters/GENERAL.json @@ -0,0 +1,5 @@ +{ + "project_code": "GENERAL", + "project_report_name": "general", + "inherit": "default" +} diff --git a/inst/extdata/parameters/GENERAL_2022Q4.json b/inst/extdata/parameters/GENERAL_2022Q4.json new file mode 100644 index 0000000..cb859b0 --- /dev/null +++ b/inst/extdata/parameters/GENERAL_2022Q4.json @@ -0,0 +1,7 @@ +{ + "select_scenario": "WEO2022_NZE_2050", + "scenario_other": "GECO2022_1.5C", + "start_year": 2022, + "inherit": "GENERAL" +} + diff --git a/inst/extdata/parameters/GENERAL_2023Q4.json b/inst/extdata/parameters/GENERAL_2023Q4.json new file mode 100644 index 0000000..9afadd7 --- /dev/null +++ b/inst/extdata/parameters/GENERAL_2023Q4.json @@ -0,0 +1,7 @@ +{ + "select_scenario": "WEO2022_NZE_2050", + "scenario_other": "GECO2022_1.5C", + "start_year": 2023, + "inherit": "GENERAL" +} + diff --git a/inst/extdata/parameters/default.json b/inst/extdata/parameters/default.json new file mode 100644 index 0000000..2ccad1b --- /dev/null +++ b/inst/extdata/parameters/default.json @@ -0,0 +1,39 @@ +{ + "scenario_geography": "Global", + "sector_list": [ + "Power", + "Automotive", + "Oil&Gas", + "Coal", + "Steel", + "Aviation", + "Cement" + ], + "portfolio_name": "Default Portfolio", + "investor_name": "Default Investor", + "peer_group": "bank", + "language_select": "EN", + "display_currency": "USD", + "currency_exchange_value": 1, + "portfolio_allocation_method": "portfolio_weight", + "tech_roadmap_sectors": [ + "Power", + "Automotive", + "Oil&Gas", + "Coal" + ], + "pacta_sectors_not_analysed": [ + "Steel", + "Aviation", + "Cement" + ], + "green_techs": [ + "RenewablesCap", + "HydroCap", + "NuclearCap", + "Hybrid", + "Electric", + "FuelCell", + "Electric Arc Furnace" + ] +} diff --git a/inst/extdata/scripts/run_pacta_report.R b/inst/extdata/scripts/run_pacta_report.R new file mode 100644 index 0000000..62335dc --- /dev/null +++ b/inst/extdata/scripts/run_pacta_report.R @@ -0,0 +1,2 @@ +logger::log_threshold(Sys.getenv("LOG_LEVEL", "WARN")) +workflow.pacta.report:::run_pacta_reporting_process(commandArgs(trailingOnly = TRUE)) diff --git a/man/workflow.pacta.report-package.Rd b/man/workflow.pacta.report-package.Rd new file mode 100644 index 0000000..c57a881 --- /dev/null +++ b/man/workflow.pacta.report-package.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/workflow.pacta.report-package.R +\docType{package} +\name{workflow.pacta.report-package} +\alias{workflow.pacta.report} +\alias{workflow.pacta.report-package} +\title{workflow.pacta.report: Reporting functionality for PACTA} +\description{ +Create Interactive Reports and Executive Summaries for PACTA. +} +\author{ +\strong{Maintainer}: Alex Axthelm \email{aaxthelm@rmi.org} (\href{https://orcid.org/0000-0001-8579-8565}{ORCID}) [contractor] + +Authors: +\itemize{ + \item Jackson Hoffart \email{jackson.hoffart@gmail.com} (\href{https://orcid.org/0000-0002-8600-5042}{ORCID}) [contractor] +} + +Other contributors: +\itemize{ + \item RMI \email{PACTA4investors@rmi.org} [copyright holder, funder] +} + +} +\keyword{internal} diff --git a/pacta_03.R b/pacta_03.R deleted file mode 100644 index 14a9c59..0000000 --- a/pacta_03.R +++ /dev/null @@ -1,362 +0,0 @@ -suppressPackageStartupMessages({ - library(pacta.portfolio.utils) - library(pacta.portfolio.report) - library(pacta.executive.summary) - library(dplyr) - library(readr) - library(jsonlite) - library(fs) -}) - -# defaulting to WARN to maintain current (silent) behavior. -logger::log_threshold(Sys.getenv("LOG_LEVEL", "WARN")) -logger::log_formatter(logger::formatter_glue) - -# ------------------------------------------------------------------------- - -logger::log_info("Starting portfolio report process") - -logger::log_trace("Determining configuration file path") -cfg_path <- commandArgs(trailingOnly = TRUE) -if (length(cfg_path) == 0 || cfg_path == "") { - logger::log_warn("No configuration file specified, using default") - cfg_path <- "input_dir/default_config.json" -} -logger::log_debug("Loading configuration from file: \"{cfg_path}\".") -cfg <- fromJSON(cfg_path) - -# quit if there's no relevant PACTA assets ------------------------------------- - -logger::log_debug("Checking for PACTA relevant data in portfolio results.") -total_portfolio_path <- file.path(cfg$output_dir, "total_portfolio.rds") -if (file.exists(total_portfolio_path)) { - total_portfolio <- readRDS(total_portfolio_path) - logger::log_trace("Checking for PACTA relevant data in file: \"{total_portfolio_path}\".") - quit_if_no_pacta_relevant_data(total_portfolio) -} else { - logger::log_warn("file \"{total_portfolio_path}\" does not exist.") - warning("This is weird... the `total_portfolio.rds` file does not exist in the `30_Processed_inputs` directory.") -} - - -# fix parameters --------------------------------------------------------------- - -if (cfg$project_code == "GENERAL") { - logger::log_warn("Overriding language selection to \"EN\" for \"GENERAL\".") - cfg$language_select <- "EN" -} else { - logger::log_trace("Using language selection: \"{cfg$language_select}\".") -} - - -# load PACTA results ----------------------------------------------------------- - -logger::log_info("Loading PACTA results.") - -readRDS_or_return_alt_data <- function(filepath, alt_return = NULL) { - if (file.exists(filepath)) { - return(readRDS(filepath)) - } - alt_return -} - -add_inv_and_port_names_if_needed <- function(data) { - if (!inherits(data, "data.frame")) { - return(data) - } - - if (!"portfolio_name" %in% names(data)) { - data <- mutate(data, portfolio_name = cfg$portfolio_name, .before = everything()) - } - - if (!"investor_name" %in% names(data)) { - data <- mutate(data, investor_name = cfg$investor_name, .before = everything()) - } - - data -} - -logger::log_debug("Loading audit file.") -audit_file <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "audit_file.rds"), - alt_return = empty_audit_file() -) -audit_file <- add_inv_and_port_names_if_needed(audit_file) - -logger::log_debug("Loading portfolio overview.") -portfolio_overview <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "overview_portfolio.rds"), - alt_return = empty_portfolio_overview() -) -portfolio_overview <- add_inv_and_port_names_if_needed(portfolio_overview) - -logger::log_debug("Loading emissions.") -emissions <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "emissions.rds"), - alt_return = empty_emissions_results() -) -emissions <- add_inv_and_port_names_if_needed(emissions) - -logger::log_debug("Loading total portfolio results.") -total_portfolio <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "total_portfolio.rds"), - alt_return = empty_portfolio_results() -) -total_portfolio <- add_inv_and_port_names_if_needed(total_portfolio) - -logger::log_debug("Loading portfolio equity results.") -equity_results_portfolio <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "Equity_results_portfolio.rds"), - alt_return = empty_portfolio_results() -) -equity_results_portfolio <- add_inv_and_port_names_if_needed(equity_results_portfolio) - -logger::log_debug("Loading portfolio bonds results.") -bonds_results_portfolio <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "Bonds_results_portfolio.rds"), - alt_return = empty_portfolio_results() -) -bonds_results_portfolio <- add_inv_and_port_names_if_needed(bonds_results_portfolio) - -logger::log_debug("Loading company equity results.") -equity_results_company <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "Equity_results_company.rds"), - alt_return = empty_company_results() -) -equity_results_company <- add_inv_and_port_names_if_needed(equity_results_company) - -logger::log_debug("Loading company bonds results.") -bonds_results_company <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "Bonds_results_company.rds"), - alt_return = empty_company_results() -) -bonds_results_company <- add_inv_and_port_names_if_needed(bonds_results_company) - -logger::log_debug("Loading equity map results.") -equity_results_map <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "Equity_results_map.rds"), - alt_return = empty_map_results() -) -equity_results_map <- add_inv_and_port_names_if_needed(equity_results_map) - -logger::log_debug("Loading bonds map results.") -bonds_results_map <- readRDS_or_return_alt_data( - filepath = file.path(cfg$output_dir, "Bonds_results_map.rds"), - alt_return = empty_map_results() -) -bonds_results_map <- add_inv_and_port_names_if_needed(bonds_results_map) - -logger::log_debug("Loading portfolio equity peer results.") -peers_equity_results_portfolio <- readRDS_or_return_alt_data( - filepath = file.path(cfg$data_dir, paste0(cfg$project_code, "_peers_equity_results_portfolio.rds")), - alt_return = empty_portfolio_results() -) - -logger::log_debug("Loading portfolio bonds peer results.") -peers_bonds_results_portfolio <- readRDS_or_return_alt_data( - filepath = file.path(cfg$data_dir, paste0(cfg$project_code, "_peers_bonds_results_portfolio.rds")), - alt_return = empty_portfolio_results() -) - -logger::log_debug("Loading index equity peer results.") -peers_equity_results_user <- readRDS_or_return_alt_data( - filepath = file.path(cfg$data_dir, paste0(cfg$project_code, "_peers_equity_results_portfolio_ind.rds")), - alt_return = empty_portfolio_results() -) - -logger::log_debug("Loading index bonds peer results.") -peers_bonds_results_user <- readRDS_or_return_alt_data( - filepath = file.path(cfg$data_dir, paste0(cfg$project_code, "_peers_bonds_results_portfolio_ind.rds")), - alt_return = empty_portfolio_results() -) - -logger::log_debug("Loading index equity portfolio results.") -indices_equity_results_portfolio <- readRDS(file.path(cfg$data_dir, "Indices_equity_results_portfolio.rds")) - -logger::log_debug("Loading index bonds portfolio results.") -indices_bonds_results_portfolio <- readRDS(file.path(cfg$data_dir, "Indices_bonds_results_portfolio.rds")) - - -# create interactive report ---------------------------------------------------- - -logger::log_debug("Preparing to create interactive report.") - -survey_dir <- file.path(cfg$user_results_path, cfg$project_code, "survey") -real_estate_dir <- file.path(cfg$user_results_path, cfg$project_code, "real_estate") -output_dir <- file.path(cfg$output_dir) - -logger::log_debug("Loading data frame label translations.") -dataframe_translations <- readr::read_csv( - system.file("extdata/translation/dataframe_labels.csv", package = "pacta.portfolio.report"), - col_types = cols() -) - -logger::log_debug("Loading data frame header translations.") -header_dictionary <- readr::read_csv( - system.file("extdata/translation/dataframe_headers.csv", package = "pacta.portfolio.report"), - col_types = cols() -) - -logger::log_debug("Loading JavaScript label translations.") -js_translations <- jsonlite::fromJSON( - txt = system.file("extdata/translation/js_labels.json", package = "pacta.portfolio.report") -) - -logger::log_debug("Loading sector order.") -sector_order <- readr::read_csv( - system.file("extdata/sector_order/sector_order.csv", package = "pacta.portfolio.report"), - col_types = cols() -) - -# combine config files to send to create_interactive_report() -logger::log_trace("Defining configs and manifest.") -pacta_data_public_manifest <- - list( - creation_time_date = jsonlite::read_json(file.path(cfg$data_dir, "manifest.json"))$creation_time_date, - outputs_manifest = jsonlite::read_json(file.path(cfg$data_dir, "manifest.json"))$outputs_manifest - ) - -configs <- - list( - portfolio_config = cfg, - pacta_data_public_manifest = pacta_data_public_manifest - ) - -# workaround a bug in {config} v0.3.2 that only adds "config" class to objects it creates -class(configs$portfolio_config) <- c(class(configs$portfolio_config), "list") - -logger::log_trace("Defining interactive report template paths.") -template_path <- system.file("templates", package = "pacta.portfolio.report") #TODO: generalize this to accept non-builtin templates -template_dir_name <- paste(tolower(cfg$project_report_name), tolower(cfg$language_select), "template", sep = "_") -template_dir <- file.path(template_path, template_dir_name) - -logger::log_info("Creating interactive report.") -create_interactive_report( - template_dir = template_dir, - output_dir = file.path(cfg$output_dir, "report"), - survey_dir = cfg$survey_dir, - real_estate_dir = cfg$real_estate_dir, - language_select = cfg$language_select, - investor_name = cfg$investor_name, - portfolio_name = cfg$portfolio_name, - peer_group = cfg$peer_group, - start_year = cfg$start_year, - select_scenario = cfg$select_scenario, - select_scenario_other = cfg$scenario_other, - portfolio_allocation_method = cfg$portfolio_allocation_method, - scenario_geography = cfg$scenario_geography, - pacta_sectors = cfg$sector_list, - green_techs = cfg$green_techs, - tech_roadmap_sectors = cfg$tech_roadmap_sectors, - pacta_sectors_not_analysed = cfg$pacta_sectors_not_analysed, - audit_file = audit_file, - emissions = emissions, - portfolio_overview = portfolio_overview, - equity_results_portfolio = equity_results_portfolio, - bonds_results_portfolio = bonds_results_portfolio, - equity_results_company = equity_results_company, - bonds_results_company = bonds_results_company, - equity_results_map = equity_results_map, - bonds_results_map = bonds_results_map, - indices_equity_results_portfolio = indices_equity_results_portfolio, - indices_bonds_results_portfolio = indices_bonds_results_portfolio, - peers_equity_results_portfolio = peers_equity_results_portfolio, - peers_bonds_results_portfolio = peers_bonds_results_portfolio, - peers_equity_results_user = peers_equity_results_user, - peers_bonds_results_user = peers_bonds_results_user, - dataframe_translations = dataframe_translations, - js_translations = js_translations, - display_currency = cfg$display_currency, - currency_exchange_value = cfg$currency_exchange_value, - header_dictionary = header_dictionary, - sector_order = sector_order, - configs = configs -) - - -# create executive summary ----------------------------------------------------- -logger::log_debug("Preparing to create executive summary.") - -survey_dir <- fs::path_abs(file.path(cfg$user_results_path, cfg$project_code, "survey")) -real_estate_dir <- fs::path_abs(file.path(cfg$user_results_path, cfg$project_code, "real_estate")) -score_card_dir <- fs::path_abs(file.path(cfg$user_results_path, cfg$project_code, "score_card")) -output_dir <- file.path(cfg$output_dir) -es_dir <- file.path(cfg$output_dir, "executive_summary") -if (!dir.exists(es_dir)) { - dir.create(es_dir, showWarnings = FALSE, recursive = TRUE) -} - -logger::log_trace("Defining executive summary template paths.") -exec_summary_template_name <- paste0(cfg$project_code, "_", tolower(cfg$language_select), "_exec_summary") -exec_summary_builtin_template_path <- system.file("extdata", exec_summary_template_name, package = "pacta.executive.summary") -invisible(file.copy(exec_summary_builtin_template_path, cfg$output_dir, recursive = TRUE, copy.mode = FALSE)) -exec_summary_template_path <- file.path(cfg$output_dir, exec_summary_template_name) - -if (dir.exists(exec_summary_template_path) && (cfg$peer_group %in% c("assetmanager", "bank", "insurance", "pensionfund"))) { - logger::log_debug("Preparing data for executive summary.") - data_aggregated_filtered <- - prep_data_executive_summary( - investor_name = cfg$investor_name, - portfolio_name = cfg$portfolio_name, - peer_group = cfg$peer_group, - start_year = cfg$start_year, - scenario_source = "GECO2021", - scenario_selected = "1.5C-Unif", - scenario_geography = "Global", - equity_market = "GlobalMarket", - portfolio_allocation_method_equity = "portfolio_weight", - portfolio_allocation_method_bonds = "portfolio_weight", - green_techs = c( - "RenewablesCap", - "HydroCap", - "NuclearCap", - "Hybrid", - "Electric", - "FuelCell", - "Hybrid_HDV", - "Electric_HDV", - "FuelCell_HDV", - "Electric Arc Furnace" - ), - equity_results_portfolio = equity_results_portfolio, - bonds_results_portfolio = bonds_results_portfolio, - peers_equity_results_aggregated = peers_equity_results_portfolio, - peers_bonds_results_aggregated = peers_bonds_results_portfolio, - peers_equity_results_individual = peers_equity_results_user, - peers_bonds_results_individual = peers_bonds_results_user, - indices_equity_results_portfolio = indices_equity_results_portfolio, - indices_bonds_results_portfolio = indices_bonds_results_portfolio, - audit_file = audit_file, - emissions_portfolio = emissions, - score_card_dir = score_card_dir - ) - - logger::log_trace("Checking for real estate data.") - real_estate_flag <- (length(list.files(real_estate_dir)) > 0) - - logger::log_info("Creating executive summary.") - render_executive_summary( - data = data_aggregated_filtered, - language = cfg$language_select, - output_dir = es_dir, - exec_summary_dir = exec_summary_template_path, - survey_dir = survey_dir, - real_estate_dir = real_estate_dir, - real_estate_flag = real_estate_flag, - score_card_dir = score_card_dir, - file_name = "template.Rmd", - investor_name = cfg$investor_name, - portfolio_name = cfg$portfolio_name, - peer_group = cfg$peer_group, - total_portfolio = total_portfolio, - scenario_selected = "1.5C-Unif", - currency_exchange_value = cfg$currency_exchange_value, - log_dir = cfg$output_dir - ) -} else { - # this is required for the online tool to know that the process has been completed. - logger::log_debug("No executive summary created.") - invisible(file.copy(blank_pdf(), es_dir)) -} - -logger::log_info("Portfolio report finished.") diff --git a/run-pacta.sh b/run-pacta.sh deleted file mode 100755 index d24b05a..0000000 --- a/run-pacta.sh +++ /dev/null @@ -1,6 +0,0 @@ -#! /bin/bash - -# Set permissions so that new files can be deleted/overwritten outside docker -umask 000 - -Rscript --vanilla pacta_03.R "${1}" \ diff --git a/tests/config/default_2022Q4.json b/tests/config/default_2022Q4.json new file mode 100644 index 0000000..d52e8ec --- /dev/null +++ b/tests/config/default_2022Q4.json @@ -0,0 +1,10 @@ +{ + "holdingsDate": "2022Q4", + "pactaDataURL": "https://pactadatadev.file.core.windows.net/workflow-data-preparation-outputs/2022Q4_20240426T113151Z", + "resultsURL": "https://pactadatadev.blob.core.windows.net/ghactions-workflow-pacta-results/73/merge/latest/default_2022Q4/output_dir", + "benchmarksURL": "https://pactadatadev.file.core.windows.net/workflow-prepare-pacta-indices-outputs/2022Q4_20240529T002407Z", + "parameters": { + "portfolio_files": "default_portfolio.csv", + "inherit": "GENERAL_2022Q4" + } +} diff --git a/tests/config/default_2023Q4.json b/tests/config/default_2023Q4.json new file mode 100644 index 0000000..2a6ec42 --- /dev/null +++ b/tests/config/default_2023Q4.json @@ -0,0 +1,10 @@ +{ + "holdingsDate": "2023Q4", + "pactaDataURL": "https://pactadatadev.file.core.windows.net/workflow-data-preparation-outputs/2023Q4_20240424T120055Z", + "resultsURL": "https://pactadatadev.blob.core.windows.net/ghactions-workflow-pacta-results/73/merge/latest/default_2023Q4/output_dir", + "benchmarksURL": "https://pactadatadev.file.core.windows.net/workflow-prepare-pacta-indices-outputs/2023Q4_20240529T002355Z", + "parameters": { + "portfolio_files": "default_portfolio.csv", + "inherit": "GENERAL_2023Q4" + } +} diff --git a/tests/config/full_params_2023Q4.json b/tests/config/full_params_2023Q4.json new file mode 100644 index 0000000..3463007 --- /dev/null +++ b/tests/config/full_params_2023Q4.json @@ -0,0 +1,17 @@ +{ + "holdingsDate": "2023Q4", + "pactaDataURL": "https://pactadatadev.file.core.windows.net/workflow-data-preparation-outputs/2023Q4_20240424T120055Z", + "resultsURL": "https://pactadatadev.blob.core.windows.net/ghactions-workflow-pacta-results/73/merge/latest/full_params_2023Q4/output_dir", + "benchmarksURL": "https://pactadatadev.file.core.windows.net/workflow-prepare-pacta-indices-outputs/2023Q4_20240529T002355Z", + "parameters": { + "equity_market_list": ["GlobalMarket", "DevelopedMarket", "EmergingMarket"], + "scenario_geographies_list": ["Global", "GlobalAggregate", "NonOECD", "OECD"], + "sector_list": ["Power", "Automotive", "Oil&Gas", "Coal", "Steel", "Aviation", "Cement"], + "time_horizon": 5, + "start_year": 2023, + "holdingsDate": "2023-12-31", + "scenario_sources_list": ["GECO2023", "ISF2023", "WEO2023"], + "project_code": "GENERAL", + "portfolio_files": "default_portfolio.csv" + } +}