From cc608d20eff7d2a6e246a52c6da341f50aec1b61 Mon Sep 17 00:00:00 2001 From: Mariana Vertenstein Date: Wed, 26 Apr 2023 11:03:44 +0200 Subject: [PATCH 01/38] added blom --- CIME/data/config/cesm/config_files.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CIME/data/config/cesm/config_files.xml b/CIME/data/config/cesm/config_files.xml index b1dc9e587f5..61ad861e13d 100644 --- a/CIME/data/config/cesm/config_files.xml +++ b/CIME/data/config/cesm/config_files.xml @@ -160,6 +160,7 @@ $SRCROOT/components/pop/ $SRCROOT/components/mom/ $SRCROOT/components/nemo/ + $SRCROOT/components/blom/ $SRCROOT/components/cpl7/components/data_comps_$COMP_INTERFACE/docn $SRCROOT/components/cdeps/docn $SRCROOT/components/cpl7/components/stub_comps_$COMP_INTERFACE/socn @@ -313,6 +314,7 @@ $COMP_ROOT_DIR_OCN/cime_config/config_compsets.xml $COMP_ROOT_DIR_OCN/cime_config/config_compsets.xml $COMP_ROOT_DIR_OCN/cime_config/config_compsets.xml + $COMP_ROOT_DIR_OCN/cime_config/config_compsets.xml case_last env_case.xml @@ -336,6 +338,7 @@ $COMP_ROOT_DIR_OCN/cime_config/config_pes.xml $COMP_ROOT_DIR_OCN/cime_config/config_pes.xml $COMP_ROOT_DIR_OCN/cime_config/config_pes.xml + $COMP_ROOT_DIR_OCN/cime_config/config_pes.xml case_last env_case.xml @@ -365,6 +368,7 @@ $COMP_ROOT_DIR_OCN/cime_config/config_archive.xml $COMP_ROOT_DIR_OCN/cime_config/config_archive.xml $COMP_ROOT_DIR_OCN/cime_config/config_archive.xml + $COMP_ROOT_DIR_OCN/cime_config/config_archive.xml $COMP_ROOT_DIR_ROF/cime_config/config_archive.xml $COMP_ROOT_DIR_ROF/cime_config/config_archive.xml $COMP_ROOT_DIR_ROF/cime_config/config_archive.xml @@ -386,6 +390,7 @@ $COMP_ROOT_DIR_OCN/cime_config/SystemTests $COMP_ROOT_DIR_OCN/cime_config/SystemTests $COMP_ROOT_DIR_OCN/cime_config/SystemTests + $COMP_ROOT_DIR_OCN/cime_config/SystemTests $COMP_ROOT_DIR_ICE/cime_config/SystemTests $COMP_ROOT_DIR_ICE/cime_config/SystemTests $COMP_ROOT_DIR_GLC/cime_config/SystemTests @@ -413,6 +418,7 @@ $COMP_ROOT_DIR_OCN/cime_config/testdefs/testlist_pop.xml $COMP_ROOT_DIR_OCN/cime_config/testdefs/testlist_mom.xml $COMP_ROOT_DIR_OCN/cime_config/testdefs/testlist_nemo.xml + $COMP_ROOT_DIR_OCN/cime_config/testdefs/testlist_blom.xml $COMP_ROOT_DIR_ROF/cime_config/testdefs/testlist_rtm.xml $COMP_ROOT_DIR_ROF/cime_config/testdefs/testlist_mosart.xml $COMP_ROOT_DIR_ROF/cime_config/testdefs/testlist_mizuRoute.xml @@ -448,6 +454,7 @@ $COMP_ROOT_DIR_OCN/cime_config/testdefs/testmods_dirs $COMP_ROOT_DIR_OCN/cime_config/testdefs/testmods_dirs $COMP_ROOT_DIR_OCN/cime_config/testdefs/testmods_dirs + $COMP_ROOT_DIR_OCN/cime_config/testdefs/testmods_dirs $SRCROOT/components/cdeps/datm/cime_config/testdefs/testmods_dirs $SRCROOT/components/cdeps/dice/cime_config/testdefs/testmods_dirs $SRCROOT/components/cdeps/dlnd/cime_config/testdefs/testmods_dirs @@ -478,6 +485,7 @@ $COMP_ROOT_DIR_OCN/cime_config/usermods_dirs $COMP_ROOT_DIR_OCN/cime_config/usermods_dirs $COMP_ROOT_DIR_OCN/cime_config/usermods_dirs + $COMP_ROOT_DIR_OCN/cime_config/usermods_dirs case_last env_case.xml @@ -507,6 +515,7 @@ $COMP_ROOT_DIR_OCN/bld/namelist_files/namelist_definition_pop.xml $COMP_ROOT_DIR_OCN/bld/namelist_files/namelist_definition_mom.xml $COMP_ROOT_DIR_OCN/bld/namelist_files/namelist_definition_nemo.xml + $COMP_ROOT_DIR_OCN/bld/namelist_files/namelist_definition_blom.xml --> $COMP_ROOT_DIR_LND/bld/namelist_files/namelist_definition_slim.xml From f0812b254f4e9cb7116cd54a686aed6b74185439 Mon Sep 17 00:00:00 2001 From: Mariana Vertenstein Date: Thu, 25 May 2023 11:31:37 +0200 Subject: [PATCH 02/38] removed reference to config_grids_mct.xml --- CIME/data/config/cesm/config_files.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/CIME/data/config/cesm/config_files.xml b/CIME/data/config/cesm/config_files.xml index 61ad861e13d..e5e38b42b62 100644 --- a/CIME/data/config/cesm/config_files.xml +++ b/CIME/data/config/cesm/config_files.xml @@ -29,7 +29,6 @@ $SRCROOT/ccs_config/config_grids.xml $SRCROOT/ccs_config/config_grids_nuopc.xml - $SRCROOT/ccs_config/config_grids_mct.xml case_last env_case.xml From 5a6a47bd88edfbffc12203f426843ddff43b787b Mon Sep 17 00:00:00 2001 From: Mariana Vertenstein Date: Mon, 17 Jul 2023 13:09:49 +0200 Subject: [PATCH 03/38] udpate for having WW3 define compsets for testing --- CIME/data/config/cesm/config_files.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/CIME/data/config/cesm/config_files.xml b/CIME/data/config/cesm/config_files.xml index e5e38b42b62..47266bf5605 100644 --- a/CIME/data/config/cesm/config_files.xml +++ b/CIME/data/config/cesm/config_files.xml @@ -314,6 +314,7 @@ $COMP_ROOT_DIR_OCN/cime_config/config_compsets.xml $COMP_ROOT_DIR_OCN/cime_config/config_compsets.xml $COMP_ROOT_DIR_OCN/cime_config/config_compsets.xml + $COMP_ROOT_DIR_WAV/cime_config/config_compsets.xml case_last env_case.xml From 0008b643cac581102137617fe1462701e9b4c14e Mon Sep 17 00:00:00 2001 From: Mariana Vertenstein Date: Wed, 26 Jul 2023 13:52:53 +0200 Subject: [PATCH 04/38] added ww3dev config_pes.xml search --- CIME/data/config/cesm/config_files.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/CIME/data/config/cesm/config_files.xml b/CIME/data/config/cesm/config_files.xml index 47266bf5605..a83773d2335 100644 --- a/CIME/data/config/cesm/config_files.xml +++ b/CIME/data/config/cesm/config_files.xml @@ -339,6 +339,7 @@ $COMP_ROOT_DIR_OCN/cime_config/config_pes.xml $COMP_ROOT_DIR_OCN/cime_config/config_pes.xml $COMP_ROOT_DIR_OCN/cime_config/config_pes.xml + $COMP_ROOT_DIR_WAV/cime_config/config_pes.xml case_last env_case.xml From ded4546e43a140d5c6d1066d41defbd51d92566c Mon Sep 17 00:00:00 2001 From: Wuyin Lin Date: Thu, 9 Nov 2023 17:46:05 -0800 Subject: [PATCH 05/38] Update e3smv3 pgn and tsc tests with L80 ICs for atm and lnd --- CIME/SystemTests/pgn.py | 6 +++--- CIME/SystemTests/tsc.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CIME/SystemTests/pgn.py b/CIME/SystemTests/pgn.py index a597cc71f97..afbdd236e8e 100644 --- a/CIME/SystemTests/pgn.py +++ b/CIME/SystemTests/pgn.py @@ -45,7 +45,7 @@ ] ) FCLD_NC = "cam.h0.cloud.nc" -INIT_COND_FILE_TEMPLATE = "20210915.v2.ne4_oQU240.F2010.{}.{}.0002-{:02d}-01-00000.nc" +INIT_COND_FILE_TEMPLATE = "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" INSTANCE_FILE_TEMPLATE = "{}{}_{:04d}.h0.0001-01-01-00000{}.nc" @@ -95,8 +95,8 @@ def build_phase(self, sharedlib_only=False, model_only=False): logger.debug("PGN_INFO: Updating user_nl_* files") csmdata_root = self._case.get_value("DIN_LOC_ROOT") - csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4_v2_init") - csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4_oQU240_v2_init") + csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4_v3_init") + csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4_oQU240_v3_init") iinst = 1 for icond in range(1, NUMBER_INITIAL_CONDITIONS + 1): diff --git a/CIME/SystemTests/tsc.py b/CIME/SystemTests/tsc.py index 3ecaefe75d0..3a122af893d 100644 --- a/CIME/SystemTests/tsc.py +++ b/CIME/SystemTests/tsc.py @@ -32,7 +32,7 @@ SIM_LENGTH = 600 # seconds OUT_FREQ = 10 # seconds INSPECT_AT = [300, 450, 600] # seconds -INIT_COND_FILE_TEMPLATE = "20210915.v2.ne4_oQU240.F2010.{}.{}.0002-{:02d}-01-00000.nc" +INIT_COND_FILE_TEMPLATE = "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" VAR_LIST = [ "T", "Q", @@ -100,8 +100,8 @@ def _run_with_specified_dtime(self, dtime=2): self._case.set_value("STOP_OPTION", "nsteps") csmdata_root = self._case.get_value("DIN_LOC_ROOT") - csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4_v2_init") - csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4_oQU240_v2_init") + csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4_v3_init") + csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4_oQU240_v3_init") nstep_output = OUT_FREQ // dtime for iinst in range(1, NINST + 1): From 34c2b12b3913b96a5f17f7e0b48c7fde0dc1e9b7 Mon Sep 17 00:00:00 2001 From: Robert Jacob Date: Fri, 16 Feb 2024 16:03:31 -0600 Subject: [PATCH 06/38] black formatting for pgn.py tsc.py --- CIME/SystemTests/pgn.py | 4 +++- CIME/SystemTests/tsc.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CIME/SystemTests/pgn.py b/CIME/SystemTests/pgn.py index afbdd236e8e..ac68773aeb4 100644 --- a/CIME/SystemTests/pgn.py +++ b/CIME/SystemTests/pgn.py @@ -45,7 +45,9 @@ ] ) FCLD_NC = "cam.h0.cloud.nc" -INIT_COND_FILE_TEMPLATE = "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" +INIT_COND_FILE_TEMPLATE = ( + "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" +) INSTANCE_FILE_TEMPLATE = "{}{}_{:04d}.h0.0001-01-01-00000{}.nc" diff --git a/CIME/SystemTests/tsc.py b/CIME/SystemTests/tsc.py index 3a122af893d..1a37ecaac5d 100644 --- a/CIME/SystemTests/tsc.py +++ b/CIME/SystemTests/tsc.py @@ -32,7 +32,9 @@ SIM_LENGTH = 600 # seconds OUT_FREQ = 10 # seconds INSPECT_AT = [300, 450, 600] # seconds -INIT_COND_FILE_TEMPLATE = "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" +INIT_COND_FILE_TEMPLATE = ( + "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" +) VAR_LIST = [ "T", "Q", From 8424c3de852d0e11446f5d92fa6044bd0fab667c Mon Sep 17 00:00:00 2001 From: James Foucar Date: Tue, 20 Feb 2024 14:54:29 -0700 Subject: [PATCH 07/38] case.submit: Always try to download input data We don't want test cases downloading data while on a compute node if it can be avoided. It's harmless to call check_all_input_data twice, so let's have the case.submit call handle the 99% of cases where the main case will download all the inputs needed for the case/test. --- CIME/case/case_submit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CIME/case/case_submit.py b/CIME/case/case_submit.py index 7893d2d3aae..e3f30654814 100644 --- a/CIME/case/case_submit.py +++ b/CIME/case/case_submit.py @@ -290,9 +290,9 @@ def check_case(self, skip_pnl=False, chksum=False): self.check_lockedfiles() if not skip_pnl: self.create_namelists() # Must be called before check_all_input_data + logger.info("Checking that inputdata is available as part of case submission") - if not self.get_value("TEST"): - self.check_all_input_data(chksum=chksum) + self.check_all_input_data(chksum=chksum) if self.get_value("COMP_WAV") == "ww": # the ww3 buildnml has dependencies on inputdata so we must run it again From 8bdb5a276098ec6d2af9176106a804a930523c04 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 21 Feb 2024 08:23:33 -0800 Subject: [PATCH 08/38] Fixes workflow for forked repo pr --- .github/workflows/testing.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 530c00db89e..e3740cc2952 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -34,6 +34,7 @@ permissions: jobs: build-containers: runs-on: ubuntu-latest + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} permissions: packages: write steps: @@ -91,7 +92,7 @@ jobs: if: ${{ github.event_name == 'pull_request' && always() && ! cancelled() }} needs: build-containers container: - image: ghcr.io/esmci/cime:sha-${{ github.sha }} + image: ghcr.io/esmci/cime:${{ github.event.pull_request.head.repo.full_name == github.repository && "sha-{{ github.sha }}" || 'latest' }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -127,7 +128,7 @@ jobs: if: ${{ github.event_name == 'pull_request' && always() && ! cancelled() }} needs: build-containers container: - image: ghcr.io/esmci/cime:sha-${{ github.sha }} + image: ghcr.io/esmci/cime:${{ github.event.pull_request.head.repo.full_name == github.repository && "sha-{{ github.sha }}" || 'latest' }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} From 5dd16f4bfb19fbf26beb71aa9e944d74553f8ded Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 21 Feb 2024 08:26:24 -0800 Subject: [PATCH 09/38] Trigger testing/building workflow --- CIME/TRIGGER | 1 + 1 file changed, 1 insertion(+) create mode 100644 CIME/TRIGGER diff --git a/CIME/TRIGGER b/CIME/TRIGGER new file mode 100644 index 00000000000..f755cd95fdf --- /dev/null +++ b/CIME/TRIGGER @@ -0,0 +1 @@ +Wed Feb 21 08:26:04 AM PST 2024 From 54abbf0c1065d5464dc6b577e9d65f869c0d4bf3 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 21 Feb 2024 08:32:33 -0800 Subject: [PATCH 10/38] Fixes ternary condition for testing jobs --- .github/workflows/testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index e3740cc2952..994a2dd1b4a 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -92,7 +92,7 @@ jobs: if: ${{ github.event_name == 'pull_request' && always() && ! cancelled() }} needs: build-containers container: - image: ghcr.io/esmci/cime:${{ github.event.pull_request.head.repo.full_name == github.repository && "sha-{{ github.sha }}" || 'latest' }} + image: ghcr.io/esmci/cime:${{ github.event.pull_request.head.repo.full_name == github.repository && format('sha-{0}', github.sha) || 'latest' }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} @@ -128,7 +128,7 @@ jobs: if: ${{ github.event_name == 'pull_request' && always() && ! cancelled() }} needs: build-containers container: - image: ghcr.io/esmci/cime:${{ github.event.pull_request.head.repo.full_name == github.repository && "sha-{{ github.sha }}" || 'latest' }} + image: ghcr.io/esmci/cime:${{ github.event.pull_request.head.repo.full_name == github.repository && format('sha-{0}', github.sha) || 'latest' }} credentials: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} From 0a2a1d7af610d232e5bd220d9a1e1b10082936e8 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 21 Feb 2024 12:18:32 -0700 Subject: [PATCH 11/38] Remove unneeded test --- CIME/tests/test_unit_case.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CIME/tests/test_unit_case.py b/CIME/tests/test_unit_case.py index e7f8c9a2ead..10ef1b372da 100755 --- a/CIME/tests/test_unit_case.py +++ b/CIME/tests/test_unit_case.py @@ -28,14 +28,6 @@ def test_check_case(self): case.check_all_input_data.assert_called_with(chksum=True) - def test_check_case_test(self): - case = mock.MagicMock() - # get_value arguments TEST, COMP_WAV, COMP_INTERFACE, BUILD_COMPLETE - case.get_value.side_effect = [True, "", "", True] - case_submit.check_case(case, chksum=True) - - case.check_all_input_data.assert_not_called() - @mock.patch("CIME.case.case_submit.lock_file") @mock.patch("CIME.case.case_submit.unlock_file") @mock.patch("os.path.basename") From c54b59b970a8768e2d8bcdc2eadd55f82ff18305 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 21 Feb 2024 12:25:09 -0700 Subject: [PATCH 12/38] Fix test --- CIME/tests/test_unit_case.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/tests/test_unit_case.py b/CIME/tests/test_unit_case.py index 10ef1b372da..b14458a8dea 100755 --- a/CIME/tests/test_unit_case.py +++ b/CIME/tests/test_unit_case.py @@ -23,7 +23,7 @@ class TestCaseSubmit(unittest.TestCase): def test_check_case(self): case = mock.MagicMock() # get_value arguments TEST, COMP_WAV, COMP_INTERFACE, BUILD_COMPLETE - case.get_value.side_effect = [False, "", "", True] + case.get_value.side_effect = ["", "", True] case_submit.check_case(case, chksum=True) case.check_all_input_data.assert_called_with(chksum=True) From 9d7f46032e1208bfa02ef356718220d0488c7271 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 21 Feb 2024 16:15:11 -0800 Subject: [PATCH 13/38] Fixes finding termination message in logs --- CIME/case/case_run.py | 10 ++----- CIME/tests/test_unit_case_run.py | 49 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 CIME/tests/test_unit_case_run.py diff --git a/CIME/case/case_run.py b/CIME/case/case_run.py index 2e86e594a5d..9dd92ec4876 100644 --- a/CIME/case/case_run.py +++ b/CIME/case/case_run.py @@ -10,6 +10,8 @@ import shutil, time, sys, os, glob +TERMINATION_TEXT = ("HAS ENDED", "END OF MODEL RUN", "SUCCESSFUL TERMINATION") + logger = logging.getLogger(__name__) ############################################################################### @@ -331,13 +333,7 @@ def _post_run_check(case, lid): break with open(cpl_logfile, "r") as fd: logfile = fd.read() - if ( - comp_standalone - and "HAS ENDED" in logfile - or "END OF MODEL RUN" in logfile - ): - count_ok += 1 - elif not comp_standalone and "SUCCESSFUL TERMINATION" in logfile: + if any([x in logfile for x in TERMINATION_TEXT]): count_ok += 1 if count_ok < cpl_ninst: expect(False, "Model did not complete - see {} \n ".format(cpl_logfile)) diff --git a/CIME/tests/test_unit_case_run.py b/CIME/tests/test_unit_case_run.py new file mode 100644 index 00000000000..878face2795 --- /dev/null +++ b/CIME/tests/test_unit_case_run.py @@ -0,0 +1,49 @@ +import unittest +from unittest import mock + +from CIME.utils import CIMEError +from CIME.case.case_run import TERMINATION_TEXT +from CIME.case.case_run import _post_run_check + +def _case_post_run_check(): + case = mock.MagicMock() + + # RUNDIR, COMP_INTERFACE, COMP_CPL, COMP_ATM, COMP_OCN, MULTI_DRIVER + case.get_value.side_effect = ( + "/tmp/run", "mct", + "cpl", "satm", "socn", + False + ) + + # COMP_CLASSES + case.get_values.return_value = ("CPL", "ATM", "OCN") + + return case + +class TestCaseSubmit(unittest.TestCase): + @mock.patch("os.stat") + @mock.patch("os.path.isfile") + def test_post_run_check(self, isfile, stat): + isfile.return_value = True + + stat.return_value.st_size = 1024 + + # no exceptions means success + for x in TERMINATION_TEXT: + case = _case_post_run_check() + + with mock.patch("builtins.open", mock.mock_open(read_data=x)) as mock_file: + _post_run_check(case, "1234") + + @mock.patch("os.stat") + @mock.patch("os.path.isfile") + def test_post_run_check_no_termination(self, isfile, stat): + isfile.return_value = True + + stat.return_value.st_size = 1024 + + case = _case_post_run_check() + + with self.assertRaises(CIMEError): + with mock.patch("builtins.open", mock.mock_open(read_data="I DONT HAVE A TERMINATION MESSAGE")) as mock_file: + _post_run_check(case, "1234") From 90fa2272143c63d65da99b1da8e6489df3a9b38a Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 21 Feb 2024 17:16:00 -0800 Subject: [PATCH 14/38] Fixes black formatting --- CIME/tests/test_unit_case_run.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CIME/tests/test_unit_case_run.py b/CIME/tests/test_unit_case_run.py index 878face2795..8f188925d57 100644 --- a/CIME/tests/test_unit_case_run.py +++ b/CIME/tests/test_unit_case_run.py @@ -5,21 +5,19 @@ from CIME.case.case_run import TERMINATION_TEXT from CIME.case.case_run import _post_run_check + def _case_post_run_check(): case = mock.MagicMock() # RUNDIR, COMP_INTERFACE, COMP_CPL, COMP_ATM, COMP_OCN, MULTI_DRIVER - case.get_value.side_effect = ( - "/tmp/run", "mct", - "cpl", "satm", "socn", - False - ) + case.get_value.side_effect = ("/tmp/run", "mct", "cpl", "satm", "socn", False) # COMP_CLASSES case.get_values.return_value = ("CPL", "ATM", "OCN") return case + class TestCaseSubmit(unittest.TestCase): @mock.patch("os.stat") @mock.patch("os.path.isfile") @@ -45,5 +43,8 @@ def test_post_run_check_no_termination(self, isfile, stat): case = _case_post_run_check() with self.assertRaises(CIMEError): - with mock.patch("builtins.open", mock.mock_open(read_data="I DONT HAVE A TERMINATION MESSAGE")) as mock_file: + with mock.patch( + "builtins.open", + mock.mock_open(read_data="I DONT HAVE A TERMINATION MESSAGE"), + ) as mock_file: _post_run_check(case, "1234") From d0093ee4a5c06ed45215cc24e9451468f2084605 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Thu, 22 Feb 2024 12:53:32 -0700 Subject: [PATCH 15/38] Add option to ignore diffs across the system Useful for performance testing. --- CIME/Tools/jenkins_generic_job | 9 +++++++ CIME/Tools/wait_for_tests | 9 +++++++ CIME/bless_test_results.py | 49 +++++++++++++++++++++------------- CIME/jenkins_generic_job.py | 2 ++ CIME/scripts/create_test.py | 11 ++++++++ CIME/test_scheduler.py | 2 ++ CIME/test_status.py | 11 ++++++++ CIME/wait_for_tests.py | 6 +++++ 8 files changed, 81 insertions(+), 18 deletions(-) diff --git a/CIME/Tools/jenkins_generic_job b/CIME/Tools/jenkins_generic_job index ec93bfca238..b02a5b69199 100755 --- a/CIME/Tools/jenkins_generic_job +++ b/CIME/Tools/jenkins_generic_job @@ -186,6 +186,12 @@ OR help="Do not fail if there are namelist diffs", ) + parser.add_argument( + "--ignore-diffs", + action="store_true", + help="Do not fail if there are history diffs", + ) + parser.add_argument( "--save-timing", action="store_true", @@ -272,6 +278,7 @@ OR args.check_memory, args.ignore_memleak, args.ignore_namelists, + args.ignore_diffs, args.save_timing, args.pes_file, args.jenkins_id, @@ -304,6 +311,7 @@ def _main_func(description): check_memory, ignore_memleak, ignore_namelists, + ignore_diffs, save_timing, pes_file, jenkins_id, @@ -334,6 +342,7 @@ def _main_func(description): check_memory, ignore_memleak, ignore_namelists, + ignore_diffs, save_timing, pes_file, jenkins_id, diff --git a/CIME/Tools/wait_for_tests b/CIME/Tools/wait_for_tests index ffe29f2727d..c166061c99b 100755 --- a/CIME/Tools/wait_for_tests +++ b/CIME/Tools/wait_for_tests @@ -74,6 +74,12 @@ OR help="Do not fail a test if the only problem is diffing namelists", ) + parser.add_argument( + "--ignore-diffs", + action="store_true", + help="Do not fail a test if the only problem is diffing history files", + ) + parser.add_argument( "--ignore-memleak", action="store_true", @@ -122,6 +128,7 @@ OR args.check_throughput, args.check_memory, args.ignore_namelist_diffs, + args.ignore_diffs, args.ignore_memleak, args.cdash_build_name, args.cdash_project, @@ -142,6 +149,7 @@ def _main_func(description): check_throughput, check_memory, ignore_namelist_diffs, + ignore_diffs, ignore_memleak, cdash_build_name, cdash_project, @@ -160,6 +168,7 @@ def _main_func(description): check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelist_diffs, + ignore_diffs=ignore_diffs, ignore_memleak=ignore_memleak, cdash_build_name=cdash_build_name, cdash_project=cdash_project, diff --git a/CIME/bless_test_results.py b/CIME/bless_test_results.py index 0502c541d3a..2d7ca4f72ee 100644 --- a/CIME/bless_test_results.py +++ b/CIME/bless_test_results.py @@ -216,7 +216,21 @@ def bless_test_results( bless_perf=False, **_, # Capture all for extra ): - bless_all = not (namelists_only | hist_only | bless_tput | bless_mem | bless_perf) + if bless_perf: + bless_mem = True + bless_tput = True + + bless_all_non_perf = not (namelists_only | hist_only | bless_tput | bless_mem) + perf_bless = bless_mem or bless_tput + + expect( + not (perf_bless and hist_only), + "Do not mix performance and non-performance blesses", + ) + expect( + not (perf_bless and namelists_only), + "Do not mix performance and non-performance blesses", + ) test_status_files = get_test_status_files(test_root, compiler, test_id=test_id) @@ -284,12 +298,13 @@ def bless_test_results( overall_result, phase = ts.get_overall_test_status( ignore_namelists=True, ignore_memleak=True, - check_throughput=False, - check_memory=False, + ignore_diffs=perf_bless, + check_throughput=bless_tput, + check_memory=bless_mem, ) # See if we need to bless namelist - if namelists_only or bless_all: + if namelists_only or bless_all_non_perf: if no_skip_pass: nl_bless = True else: @@ -305,21 +320,19 @@ def bless_test_results( test_name, ts, broken_blesses, overall_result, no_skip_pass, phase ) - # See if we need to bless baselines - if hist_only or bless_all: - hist_bless = bless_needed - - if bless_tput or bless_perf: - tput_bless = bless_needed - - if not tput_bless: - tput_bless = ts.get_status(THROUGHPUT_PHASE) != TEST_PASS_STATUS - - if bless_mem or bless_perf: - mem_bless = bless_needed + if bless_needed: + hist_bless = hist_only or bless_all_non_perf + tput_bless = ( + bless_tput and ts.get_status(THROUGHPUT_PHASE) != TEST_PASS_STATUS + ) + mem_bless = ( + bless_mem and ts.get_status(MEMCOMP_PHASE) != TEST_PASS_STATUS + ) - if not mem_bless: - mem_bless = ts.get_status(MEMCOMP_PHASE) != TEST_PASS_STATUS + expect( + not ((nl_bless or hist_bless) and (tput_bless or mem_bless)), + "Do not mix performance and non-performance blessing", + ) # Now, do the bless if not nl_bless and not hist_bless and not tput_bless and not mem_bless: diff --git a/CIME/jenkins_generic_job.py b/CIME/jenkins_generic_job.py index d68bc2b007c..8d99e5c5874 100644 --- a/CIME/jenkins_generic_job.py +++ b/CIME/jenkins_generic_job.py @@ -280,6 +280,7 @@ def jenkins_generic_job( check_memory, ignore_memleak, ignore_namelists, + ignore_diffs, save_timing, pes_file, jenkins_id, @@ -423,6 +424,7 @@ def jenkins_generic_job( check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelists, + ignore_diffs=ignore_diffs, ignore_memleak=ignore_memleak, cdash_build_name=cdash_build_name, cdash_project=cdash_project, diff --git a/CIME/scripts/create_test.py b/CIME/scripts/create_test.py index 65fcc03b359..07a10689b3c 100755 --- a/CIME/scripts/create_test.py +++ b/CIME/scripts/create_test.py @@ -392,6 +392,12 @@ def parse_command_line(args, description): help="Do not fail if there namelist diffs", ) + parser.add_argument( + "--ignore-diffs", + action="store_true", + help="Do not fail if there history file diffs", + ) + parser.add_argument( "--ignore-memleak", action="store_true", help="Do not fail if there's a memleak" ) @@ -761,6 +767,7 @@ def parse_command_line(args, description): args.check_throughput, args.check_memory, args.ignore_namelists, + args.ignore_diffs, args.ignore_memleak, args.allow_pnl, args.non_local, @@ -921,6 +928,7 @@ def create_test( check_throughput, check_memory, ignore_namelists, + ignore_diffs, ignore_memleak, allow_pnl, non_local, @@ -976,6 +984,7 @@ def create_test( check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelists, + ignore_diffs=ignore_diffs, ignore_memleak=ignore_memleak, ) @@ -1064,6 +1073,7 @@ def _main_func(description=None): check_throughput, check_memory, ignore_namelists, + ignore_diffs, ignore_memleak, allow_pnl, non_local, @@ -1116,6 +1126,7 @@ def _main_func(description=None): check_throughput, check_memory, ignore_namelists, + ignore_diffs, ignore_memleak, allow_pnl, non_local, diff --git a/CIME/test_scheduler.py b/CIME/test_scheduler.py index 47119a09320..b8b12ae08d2 100644 --- a/CIME/test_scheduler.py +++ b/CIME/test_scheduler.py @@ -1429,6 +1429,7 @@ def run_tests( check_throughput=False, check_memory=False, ignore_namelists=False, + ignore_diffs=False, ignore_memleak=False, ): ########################################################################### @@ -1484,6 +1485,7 @@ def run_tests( check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelists, + ignore_diffs=ignore_diffs, ignore_memleak=ignore_memleak, no_run=self._no_run, expect_test_complete=expect_test_complete, diff --git a/CIME/test_status.py b/CIME/test_status.py index 5f306b7db0e..5f32486ab51 100644 --- a/CIME/test_status.py +++ b/CIME/test_status.py @@ -113,6 +113,7 @@ def _test_helper2( check_throughput=False, check_memory=False, ignore_namelists=False, + ignore_diffs=False, no_run=False, no_perm=False, ): @@ -127,6 +128,7 @@ def _test_helper2( check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelists, + ignore_diffs=ignore_diffs, no_run=no_run, ) if rv is not None and the_status != rv: @@ -410,6 +412,7 @@ def _get_overall_status_based_on_phases( check_throughput=False, check_memory=False, ignore_namelists=False, + ignore_diffs=False, ignore_memleak=False, no_run=False, ): @@ -452,6 +455,7 @@ def _get_overall_status_based_on_phases( (not check_throughput and phase == THROUGHPUT_PHASE) or (not check_memory and phase == MEMCOMP_PHASE) or (ignore_namelists and phase == NAMELIST_PHASE) + or (ignore_diffs and phase == BASELINE_PHASE) or (ignore_memleak and phase == MEMLEAK_PHASE) ): continue @@ -493,6 +497,7 @@ def get_overall_test_status( check_throughput=False, check_memory=False, ignore_namelists=False, + ignore_diffs=False, ignore_memleak=False, no_run=False, ): @@ -527,6 +532,10 @@ def get_overall_test_status( ('FAIL', 'COMPARE_2') >>> _test_helper2('FAIL ERS.foo.A BASELINE\nFAIL ERS.foo.A NLCOMP\nPASS ERS.foo.A COMPARE_2\nPASS ERS.foo.A RUN') ('DIFF', 'BASELINE') + >>> _test_helper2('FAIL ERS.foo.A BASELINE\nPASS ERS.foo.A NLCOMP\nPASS ERS.foo.A COMPARE_2\nPASS ERS.foo.A RUN', ignore_diffs=True) + ('PASS', 'RUN') + >>> _test_helper2('FAIL ERS.foo.A BASELINE\nFAIL ERS.foo.A NLCOMP\nPASS ERS.foo.A COMPARE_2\nPASS ERS.foo.A RUN', ignore_diffs=True) + ('NLFAIL', 'RUN') >>> _test_helper2('FAIL ERS.foo.A BASELINE\nFAIL ERS.foo.A NLCOMP\nFAIL ERS.foo.A COMPARE_2\nPASS ERS.foo.A RUN') ('FAIL', 'COMPARE_2') >>> _test_helper2('PEND ERS.foo.A COMPARE_2\nFAIL ERS.foo.A RUN') @@ -585,6 +594,7 @@ def get_overall_test_status( check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelists, + ignore_diffs=ignore_diffs, ignore_memleak=ignore_memleak, no_run=no_run, ) @@ -602,6 +612,7 @@ def get_overall_test_status( check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelists, + ignore_diffs=ignore_diffs, ignore_memleak=ignore_memleak, no_run=no_run, ) diff --git a/CIME/wait_for_tests.py b/CIME/wait_for_tests.py index 10f27c10767..a6e87eaac8c 100644 --- a/CIME/wait_for_tests.py +++ b/CIME/wait_for_tests.py @@ -573,6 +573,7 @@ def wait_for_test( check_throughput, check_memory, ignore_namelists, + ignore_diffs, ignore_memleak, no_run, ): @@ -607,6 +608,7 @@ def wait_for_test( check_throughput=check_throughput, check_memory=check_memory, ignore_namelists=ignore_namelists, + ignore_diffs=ignore_diffs, ignore_memleak=ignore_memleak, ) @@ -649,6 +651,7 @@ def wait_for_tests_impl( check_throughput=False, check_memory=False, ignore_namelists=False, + ignore_diffs=False, ignore_memleak=False, no_run=False, ): @@ -665,6 +668,7 @@ def wait_for_tests_impl( check_throughput, check_memory, ignore_namelists, + ignore_diffs, ignore_memleak, no_run, ), @@ -717,6 +721,7 @@ def wait_for_tests( check_throughput=False, check_memory=False, ignore_namelists=False, + ignore_diffs=False, ignore_memleak=False, cdash_build_name=None, cdash_project=E3SM_MAIN_CDASH, @@ -739,6 +744,7 @@ def wait_for_tests( check_throughput, check_memory, ignore_namelists, + ignore_diffs, ignore_memleak, no_run, ) From eb13e2cb7cfb7a4200e5c9d9d4fa1372d37b817d Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Mon, 4 Mar 2024 11:12:26 -0800 Subject: [PATCH 16/38] Removes workflow trigger --- CIME/TRIGGER | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CIME/TRIGGER diff --git a/CIME/TRIGGER b/CIME/TRIGGER deleted file mode 100644 index f755cd95fdf..00000000000 --- a/CIME/TRIGGER +++ /dev/null @@ -1 +0,0 @@ -Wed Feb 21 08:26:04 AM PST 2024 From f08cdff656aae9c45a4c2d315c5653377932ebd6 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 8 Mar 2024 11:17:54 -0700 Subject: [PATCH 17/38] Rename var and combine expect --- CIME/bless_test_results.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/CIME/bless_test_results.py b/CIME/bless_test_results.py index 2d7ca4f72ee..b9119d37648 100644 --- a/CIME/bless_test_results.py +++ b/CIME/bless_test_results.py @@ -221,14 +221,11 @@ def bless_test_results( bless_tput = True bless_all_non_perf = not (namelists_only | hist_only | bless_tput | bless_mem) - perf_bless = bless_mem or bless_tput + is_perf_bless = bless_mem or bless_tput expect( - not (perf_bless and hist_only), - "Do not mix performance and non-performance blesses", - ) - expect( - not (perf_bless and namelists_only), + not (is_perf_bless and hist_only) and + not (is_perf_bless and namelists_only), "Do not mix performance and non-performance blesses", ) @@ -298,7 +295,7 @@ def bless_test_results( overall_result, phase = ts.get_overall_test_status( ignore_namelists=True, ignore_memleak=True, - ignore_diffs=perf_bless, + ignore_diffs=is_perf_bless, check_throughput=bless_tput, check_memory=bless_mem, ) From 236a10fe0099ae896066bb4c5a15436f0dd9b504 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 8 Mar 2024 11:39:46 -0700 Subject: [PATCH 18/38] Fix unit tests --- CIME/bless_test_results.py | 19 ++++++++----------- CIME/tests/test_unit_bless_test_results.py | 18 +++++++++--------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/CIME/bless_test_results.py b/CIME/bless_test_results.py index b9119d37648..98c7e3cc8c2 100644 --- a/CIME/bless_test_results.py +++ b/CIME/bless_test_results.py @@ -313,18 +313,15 @@ def bless_test_results( # Skip if test is build only i.e. testopts contains "B" if not build_only: - bless_needed = is_bless_needed( + hist_bless = is_hist_bless_needed( test_name, ts, broken_blesses, overall_result, no_skip_pass, phase + ) and (hist_only or bless_all_non_perf) + tput_bless = ( + bless_tput and ts.get_status(THROUGHPUT_PHASE) != TEST_PASS_STATUS + ) + mem_bless = ( + bless_mem and ts.get_status(MEMCOMP_PHASE) != TEST_PASS_STATUS ) - - if bless_needed: - hist_bless = hist_only or bless_all_non_perf - tput_bless = ( - bless_tput and ts.get_status(THROUGHPUT_PHASE) != TEST_PASS_STATUS - ) - mem_bless = ( - bless_mem and ts.get_status(MEMCOMP_PHASE) != TEST_PASS_STATUS - ) expect( not ((nl_bless or hist_bless) and (tput_bless or mem_bless)), @@ -472,7 +469,7 @@ def bless_test_results( return success -def is_bless_needed(test_name, ts, broken_blesses, overall_result, no_skip_pass, phase): +def is_hist_bless_needed(test_name, ts, broken_blesses, overall_result, no_skip_pass, phase): needed = False run_result = ts.get_status(RUN_PHASE) diff --git a/CIME/tests/test_unit_bless_test_results.py b/CIME/tests/test_unit_bless_test_results.py index 91315b30f8d..f6ebce94857 100644 --- a/CIME/tests/test_unit_bless_test_results.py +++ b/CIME/tests/test_unit_bless_test_results.py @@ -10,7 +10,7 @@ _bless_memory, bless_history, bless_namelists, - is_bless_needed, + is_hist_bless_needed, ) @@ -469,7 +469,7 @@ def test_bless_memory_only( ts = TestStatus.return_value ts.get_name.return_value = "SMS.f19_g16.S.docker_gnu" - ts.get_overall_test_status.return_value = ("PASS", "RUN") + ts.get_overall_test_status.return_value = ("DIFF", "MEMCOMP") ts.get_status.side_effect = ["PASS", "PASS", "FAIL", "FAIL"] case = Case.return_value.__enter__.return_value @@ -508,7 +508,7 @@ def test_bless_throughput_only( ts = TestStatus.return_value ts.get_name.return_value = "SMS.f19_g16.S.docker_gnu" - ts.get_overall_test_status.return_value = ("PASS", "RUN") + ts.get_overall_test_status.return_value = ("DIFF", "TPUTCOMP") ts.get_status.side_effect = ["PASS", "PASS", "FAIL", "FAIL"] case = Case.return_value.__enter__.return_value @@ -950,7 +950,7 @@ def test_is_bless_needed_no_skip_fail(self): broken_blesses = [] - needed = is_bless_needed( + needed = is_hist_bless_needed( "SMS.f19_g16.A", ts, broken_blesses, "PASS", True, "RUN" ) @@ -965,7 +965,7 @@ def test_is_bless_needed_overall_fail(self): broken_blesses = [] - needed = is_bless_needed( + needed = is_hist_bless_needed( "SMS.f19_g16.A", ts, broken_blesses, "FAIL", False, "RUN" ) @@ -978,7 +978,7 @@ def test_is_bless_needed_baseline_fail(self): broken_blesses = [] - needed = is_bless_needed( + needed = is_hist_bless_needed( "SMS.f19_g16.A", ts, broken_blesses, "PASS", False, "RUN" ) @@ -993,7 +993,7 @@ def test_is_bless_needed_run_phase_fail(self): broken_blesses = [] - needed = is_bless_needed( + needed = is_hist_bless_needed( "SMS.f19_g16.A", ts, broken_blesses, "PASS", False, "RUN" ) @@ -1006,7 +1006,7 @@ def test_is_bless_needed_no_run_phase(self): broken_blesses = [] - needed = is_bless_needed( + needed = is_hist_bless_needed( "SMS.f19_g16.A", ts, broken_blesses, "PASS", False, "RUN" ) @@ -1019,7 +1019,7 @@ def test_is_bless_needed(self): broken_blesses = [] - needed = is_bless_needed( + needed = is_hist_bless_needed( "SMS.f19_g16.A", ts, broken_blesses, "PASS", False, "RUN" ) From b3ed1b11d8df666ccf74a8ff3d52e22c829787c9 Mon Sep 17 00:00:00 2001 From: James Foucar Date: Fri, 8 Mar 2024 11:41:48 -0700 Subject: [PATCH 19/38] black --- CIME/bless_test_results.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CIME/bless_test_results.py b/CIME/bless_test_results.py index 98c7e3cc8c2..750b3a13870 100644 --- a/CIME/bless_test_results.py +++ b/CIME/bless_test_results.py @@ -224,8 +224,7 @@ def bless_test_results( is_perf_bless = bless_mem or bless_tput expect( - not (is_perf_bless and hist_only) and - not (is_perf_bless and namelists_only), + not (is_perf_bless and hist_only) and not (is_perf_bless and namelists_only), "Do not mix performance and non-performance blesses", ) @@ -319,9 +318,7 @@ def bless_test_results( tput_bless = ( bless_tput and ts.get_status(THROUGHPUT_PHASE) != TEST_PASS_STATUS ) - mem_bless = ( - bless_mem and ts.get_status(MEMCOMP_PHASE) != TEST_PASS_STATUS - ) + mem_bless = bless_mem and ts.get_status(MEMCOMP_PHASE) != TEST_PASS_STATUS expect( not ((nl_bless or hist_bless) and (tput_bless or mem_bless)), @@ -469,7 +466,9 @@ def bless_test_results( return success -def is_hist_bless_needed(test_name, ts, broken_blesses, overall_result, no_skip_pass, phase): +def is_hist_bless_needed( + test_name, ts, broken_blesses, overall_result, no_skip_pass, phase +): needed = False run_result = ts.get_status(RUN_PHASE) From 639b7e1c1b5037fa6dfdcddce70e777bc9c44ac8 Mon Sep 17 00:00:00 2001 From: Michael Kelleher Date: Sat, 9 Mar 2024 12:37:44 -0600 Subject: [PATCH 20/38] Update non-bfb test documentation --- scripts/climate_reproducibility/README.md | 84 +++++++++++------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/scripts/climate_reproducibility/README.md b/scripts/climate_reproducibility/README.md index c45862e8b8f..38640369b38 100644 --- a/scripts/climate_reproducibility/README.md +++ b/scripts/climate_reproducibility/README.md @@ -51,11 +51,11 @@ Primarily, the statistical analysis of the climates is done through [EVV](https: which will generate a portable test website to describe the results (pass or fail) in detail (see the extended output section below). -For E3SM supported machines, the `e3sm_simple` conda environment is provided for these tests and includes the `EVV` -conda package. You can activate the `e3sm_simple` environment in the same way as `e3sm_unified` environment: +For E3SM supported machines, the `cime_env` conda environment is provided for these tests and includes the `EVV` +conda package. You can activate the `cime_env` environment in the same way as `e3sm_unified` environment: ``` -source /load_latest_e3sm_simple.sh +source /load_latest_cime_env.sh ``` where `` is the machine-specific location of the activation script as described on this confluence page: @@ -63,52 +63,52 @@ where `` is the machine-specific location of the activation scrip https://acme-climate.atlassian.net/wiki/spaces/EIDMG/pages/780271950/Diagnostics+and+Analysis+Quickstart#DiagnosticsandAnalysisQuickstart-Accessingmetapackagesoftwarebyactivatingacondaenvironment If you don't have access to confluence or are unable to activate this environment for whatever reason, you can install -your own `e3sm_simple` conda environment with this command (once you have anaconda/miniconda installed): +your own `cime_env` conda environment with this command (once you have anaconda/miniconda installed): ``` -conda create -n e3sm-simple -c conda-forge -c e3sm e3sm-simple +conda create -n cime-env -c conda-forge -c e3sm cime-env ``` *NOTE: If you run into problems with getting this environment working on your machine, please open an issue on E3SM's -Github and tag @jhkennedy, or send Joseph H. Kennedy an email.* +Github and tag @mkstratos. -After you've activated the `e3sm_simple` environment, change to the `$E3SM/cime/scripts` directory (where `$E3SM` is the +After you've activated the `cime_env` environment, change to the `$E3SM/cime/scripts` directory (where `$E3SM` is the directory containing E3SM). Then to run one of the tests, you will use the `create_test` script like normal. To run the `MVK` test and generate a baseline, you would run a command like: ``` -./create_test MVK_PL.ne4_oQU240.FC5AV1C-L -g --baseline-root "/PATH/TO/BASELINE" +./create_test MVK_PS.ne4pg2_oQU480.F2010 -g --baseline-root "/PATH/TO/BASELINE" ``` And to compare to the baseline, you would run a command like: ``` -./create_test MVK_PL.ne4_oQU240.FC5AV1C-L -c --baseline-root "/PATH/TO/BASELINE" +./create_test MVK_PS.ne4pg2_oQU480.F2010 -c --baseline-root "/PATH/TO/BASELINE" ``` -*NOTE: The MVK run a 20 member ensemble for at least 13 months (using the last 12 for the +*NOTE: The MVK runs a 30 member ensemble for 13 months (using the last 12 for the statistical tests) and, depending on the machine, may take some fiddling to execute within a particular queue's wallclock time limit. You may want to over-ride the requested walltime using `--walltime HH:MM:SS` option to `create_test`.* -The full set of commands to run the MVK test used on Cori are: +The full set of commands to run the MVK test used on Perlmutter are: *Generate a baseline* ``` cd $E3SM/cime/scripts -source /global/project/projectdirs/acme/software/anaconda_envs/load_latest_e3sm_simple.sh +source /global/common/software/e3sm/anaconda_envs/load_latest_cime_env.sh -./create_test MVK_PL.ne4_ne4.FC5AV1C-L --baseline-root "${CSCRATCH}/baselines" --project acme -g -o --walltime 01:00:00 +./create_test MVK_PS.ne4pg2_oQU480.F2010 --baseline-root "${PSCRATCH}/baselines" --project e3sm -g -o --walltime 01:00:00 ``` *Compare to a baseline* ``` cd $E3SM/cime/scripts -source /global/project/projectdirs/acme/software/anaconda_envs/load_latest_e3sm_simple.sh +source /global/common/software/e3sm/anaconda_envs/load_latest_cime_env.sh -./create_test MVK_PL.ne4_ne4.FC5AV1C-L --baseline-root "${CSCRATCH}/baselines" --project acme -c --walltime 01:00:00 +./create_test MVK_PS.ne4pg2_oQU480.F2010 --baseline-root "${PSCRATCH}/baselines" --project e3sm -c --walltime 01:00:00 ``` ## Test pass/fail and extended output @@ -117,9 +117,9 @@ When you launch these tests and compare to a baseline, CIME will output the loca something like this: ``` -# On cori-knl: -./create_test MVK_PL.ne4_ne4.FC5AV1C-L --baseline-root "${CSCRATCH}/baselines" --project acme -c --walltime 01:00:00 - Creating test directory /global/cscratch1/sd/${USER}/acme_scratch/cori-knl/MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID +# On pm-cpu: +./create_test MVK_PS.ne4pg2_oQU480.F2010 --baseline-root "${PSCRATCH}/baselines" --project e3sm -c --walltime 01:00:00 + Creating test directory ${PSCRATCH}/e3sm_scratch/pm-cpu/MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID ``` Let's call that directory `$CASE_DIR`. Once all the jobs are finished, navigate to that directory and @@ -129,7 +129,7 @@ you can `cat TestStatus` to determine if the test passed or failed by looking at cd $CASE_DIR cat TestStatus ... - PASS MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel BASELINE + PASS MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel BASELINE ... ``` @@ -139,8 +139,8 @@ To get some basic summary statistics about the test that was run, look in the `T ``` 2019-08-14 22:09:02: BASELINE PASS for test 'YYYYMMDD_HHMMSS_RANDOMID'. Case: YYYYMMDD_HHMMSS_RANDOMID; Test status: pass; Variables analyzed: 118; Rejecting: 0; Critical value: 13; Ensembles: statistically identical - EVV results can be viewed at: /global/cscratch1/sd/${USER}/acme_scratch/cori-knl/MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID/run/MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv/ - EVV viewing instructions can be found at: https://github.com/E3SM-Project/E3SM/blob/master/cime/scripts/climate_reproducibility/README.md#test-passfail-and-extended-output + EVV results can be viewed at: ${PSCRATCH}/e3sm_scratch/pm-cpu/MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID/run/MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv/ + EVV viewing instructions can be found at: https://github.com/ESMCI/CIME/blob/master/scripts/climate_reproducibility/README.md#test-passfail-and-extended-output ``` EVV reports the location of the output website where you can see the details of the analysis. For @@ -153,18 +153,18 @@ the website directory to your machine and view it using EVV. ### View via ssh -For this example, we'll assume the tests were run on Cori at NERSC, but these instructions should be -easily adaptable to any E3SM supported machine. First, log into Cori via ssh and connect your local -8080 port to the 8080 port on Cori: +For this example, we'll assume the tests were run on Perlmutter at NERSC, but these instructions should be +easily adaptable to any E3SM supported machine. First, log into Perlmutter via ssh and connect your local +8080 port to the 8080 port on Perlmutter: ``` -ssh -L 8080:localhost:8080 [USER]@cori.nersc.gov +ssh -L 8080:localhost:8080 [USER]@saul-p1.nersc.gov ``` -Activate the `e3sm_simple` environment: +Activate the `cime_env` environment: ``` -source /global/project/projectdirs/acme/software/anaconda_envs/load_latest_e3sm_simple.sh +source /global/common/software/e3sm/anaconda_envs/load_latest_cime_env.sh ``` Navigate to the case's run directory: @@ -176,7 +176,7 @@ pushd ${CASE_DIR}/run Then, using EVV, serve the website over port 8080: ``` -evv -o PGN_P1x1.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv -s 8080 +evv -o PGN_P1x1.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv -s 8080 ``` Evv will then report to you the URL where you can view the website: @@ -194,17 +194,17 @@ Evv will then report to you the URL where you can view the website: Extended Verification and Validation for Earth System Models -------------------------------------------------------------------- - Current run: 2019-08-27 14:16:49 - User: kennedyj - OS Type: Linux 4.12.14-150.27-default - Machine: cori07 + Current run: 2024-03-06 07:56:37 + User: mek + OS Type: Linux 5.14.21-150400.24.81_12.0.87-cray_shasta_c + Machine: login31 Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) View the generated website by navigating to: - http://0.0.0.0:8080/PGN_P1x1.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv/index.html + http://0.0.0.0:8080/PGN_P1x1.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv/index.html Exit by pressing `ctrl+c` to send a keyboard interrupt. ``` @@ -214,20 +214,20 @@ browser to view the output website. ### View a local copy -For this example, we'll assume the tests were run on Cori at NERSC, but these instructions should be -easily adaptable to any E3SM supported machine. Install `e3sm_simple` locally and activate it: +For this example, we'll assume the tests were run on Perlmutter at NERSC, but these instructions should be +easily adaptable to any E3SM supported machine. Install `cime_env` locally and activate it: ``` -conda create -n e3sm_simple -c conda-forge -c e3sm e3sm-simple -conda activate e3sm_simple +conda create -n cime_env -c conda-forge -c e3sm cime-env +conda activate cime_env ``` Then, copy the website to your local machine, and view it: ``` # on your local machine -scp -r /global/cscratch1/sd/${USER}/acme_scratch/cori-knl/MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID/run/MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv . -evv -o MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv -s +scp -r ${PSCRATCH}/e3sm_scratch/pm-cpu/MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID/run/MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv . +evv -o MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv -s -------------------------------------------------------------------- ______ __ __ __ __ | ____| \ \ / / \ \ / / @@ -249,7 +249,7 @@ evv -o MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv -s View the generated website by navigating to: - http://0.0.0.0:8000/MVK_PL.ne4_ne4.FC5AV1C-L.cori-knl_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv/index.html + http://0.0.0.0:8000/MVK_PS.ne4pg2_oQU480.F2010.pm-cpu_intel.C.YYYYMMDD_HHMMSS_RANDOMID.evv/index.html Exit by pressing `ctrl+c` to send a keyboard interrupt. @@ -262,6 +262,6 @@ browser to view the output website. **Please note:** the output website uses some JavaScript to render elements of the page (especially figures), and opening up the `index.html` file using the `file://` protocol in a web browser will likely not work well (most browser have stopped allowing access to "local resources" like JavaScript through the `file://` -protocol). You can view the website by either copying it to a hosted location (`~/WWW` which is hosted at -`http://users.nccs.gov/~user` on Titan, for example) or copying it to your local machine and running a +protocol). You can view the website by either copying it to a hosted location (`/global/cfs/projectdirs/e3sm/www/${USER}` which is hosted at +`https://portal.nersc.gov/project/e3sm/${USER}` on NERSC, for example) or copying it to your local machine and running a local http server (included in python!) and viewing it through an address like `http://0.0.0.0:8000/index.html`. From 5115e0db4751882876c2290f33bb4f2f07e0011f Mon Sep 17 00:00:00 2001 From: Michael Kelleher Date: Sat, 9 Mar 2024 12:39:10 -0600 Subject: [PATCH 21/38] Point tsc/pgn tests to new input data --- CIME/SystemTests/pgn.py | 9 ++++----- CIME/SystemTests/tsc.py | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CIME/SystemTests/pgn.py b/CIME/SystemTests/pgn.py index ac68773aeb4..a8696c0afd2 100644 --- a/CIME/SystemTests/pgn.py +++ b/CIME/SystemTests/pgn.py @@ -46,7 +46,7 @@ ) FCLD_NC = "cam.h0.cloud.nc" INIT_COND_FILE_TEMPLATE = ( - "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" + "20240305.v3p0p0.F2010.ne4pg2_oQU480.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" ) INSTANCE_FILE_TEMPLATE = "{}{}_{:04d}.h0.0001-01-01-00000{}.nc" @@ -97,8 +97,8 @@ def build_phase(self, sharedlib_only=False, model_only=False): logger.debug("PGN_INFO: Updating user_nl_* files") csmdata_root = self._case.get_value("DIN_LOC_ROOT") - csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4_v3_init") - csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4_oQU240_v3_init") + csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4pg2_v3_init") + csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4pg2_v3_init") iinst = 1 for icond in range(1, NUMBER_INITIAL_CONDITIONS + 1): @@ -236,11 +236,10 @@ def _compare_baseline(self): viewing = ( "{}\n" " EVV viewing instructions can be found at: " - " https://github.com/E3SM-Project/E3SM/blob/master/cime/scripts/" + " https://github.com/ESMCI/CIME/blob/master/scripts/" "climate_reproducibility/README.md#test-passfail-and-extended-output" "".format(evv_out_dir) ) - comments = ( "{} {} for test '{}'.\n" " {}\n" diff --git a/CIME/SystemTests/tsc.py b/CIME/SystemTests/tsc.py index 1a37ecaac5d..f50fd4c334b 100644 --- a/CIME/SystemTests/tsc.py +++ b/CIME/SystemTests/tsc.py @@ -33,7 +33,7 @@ OUT_FREQ = 10 # seconds INSPECT_AT = [300, 450, 600] # seconds INIT_COND_FILE_TEMPLATE = ( - "20231105.v3b01.F2010.ne4_oQU240.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" + "20240305.v3p0p0.F2010.ne4pg2_oQU480.chrysalis.{}.{}.0002-{:02d}-01-00000.nc" ) VAR_LIST = [ "T", @@ -102,8 +102,8 @@ def _run_with_specified_dtime(self, dtime=2): self._case.set_value("STOP_OPTION", "nsteps") csmdata_root = self._case.get_value("DIN_LOC_ROOT") - csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4_v3_init") - csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4_oQU240_v3_init") + csmdata_atm = os.path.join(csmdata_root, "atm/cam/inic/homme/ne4pg2_v3_init") + csmdata_lnd = os.path.join(csmdata_root, "lnd/clm2/initdata/ne4pg2_v3_init") nstep_output = OUT_FREQ // dtime for iinst in range(1, NINST + 1): @@ -225,7 +225,7 @@ def _compare_baseline(self): viewing = ( "{}\n" " EVV viewing instructions can be found at: " - " https://github.com/E3SM-Project/E3SM/blob/master/cime/scripts/" + " https://github.com/ESMCI/CIME/blob/master/scripts/" "climate_reproducibility/README.md#test-passfail-and-extended-output" "".format(evv_out_dir) ) From 6d21f7673f2188ebe5e8438b5cb89e7d90d68720 Mon Sep 17 00:00:00 2001 From: Bill Sacks Date: Tue, 12 Mar 2024 10:59:06 -0600 Subject: [PATCH 22/38] Initialize machine to None This follows the logic in the _v2 version of this function. Resolves ESMCI/cime#4588 --- CIME/XML/machines.py | 1 + 1 file changed, 1 insertion(+) diff --git a/CIME/XML/machines.py b/CIME/XML/machines.py index e3a047d25de..b5c10332acb 100644 --- a/CIME/XML/machines.py +++ b/CIME/XML/machines.py @@ -263,6 +263,7 @@ def _probe_machine_name_one_guess_v3(self, nametomatch): children = [y for x in nodes for y in self.get_children(root=x)] + machine = None for child in children: machtocheck = self.get(child, "MACH") regex_str = self.text(child) From 65ff24dcdde0d1e7a15204d136acce6e8ccc1042 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 13 Mar 2024 10:41:32 -0700 Subject: [PATCH 23/38] Removes ghcr_prune pull_request trigger --- .github/workflows/ghcr-prune.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ghcr-prune.yml b/.github/workflows/ghcr-prune.yml index 5e26f83e3ce..998b6a5330c 100644 --- a/.github/workflows/ghcr-prune.yml +++ b/.github/workflows/ghcr-prune.yml @@ -4,9 +4,6 @@ on: # run once a day - cron: '0 2 * * *' - # Temporary to test - pull_request: - permissions: {} jobs: From 83b4a906bae03a55202e0b082ce68c72779c4035 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 13 Mar 2024 10:42:40 -0700 Subject: [PATCH 24/38] Fixes running build-containers on a merge, so latest tag is created --- .github/workflows/testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 994a2dd1b4a..44dc61639d4 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -34,7 +34,7 @@ permissions: jobs: build-containers: runs-on: ubuntu-latest - if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + if: ${{ github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository }} permissions: packages: write steps: From 4e24cbdad812bc833067657f86386be0aa8d2f96 Mon Sep 17 00:00:00 2001 From: Chris Fischer Date: Tue, 19 Mar 2024 16:29:36 -0600 Subject: [PATCH 25/38] Update server name for the test database. --- CIME/XML/test_reporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/XML/test_reporter.py b/CIME/XML/test_reporter.py index 3ef87c957a4..93f117a8a46 100644 --- a/CIME/XML/test_reporter.py +++ b/CIME/XML/test_reporter.py @@ -76,7 +76,7 @@ def push2testdb(self): os.system("stty echo") print() params = {"username": username, "password": password, "testXML": xmlstr} - url = "https://csegweb.cgd.ucar.edu/testdb/cgi-bin/processXMLtest.cgi" + url = "https://cseg.cgd.ucar.edu/testdb/cgi-bin/processXMLtest.cgi" data = urllib.parse.urlencode(params) data = data.encode("ascii") req = urllib.request.Request(url, data) From 975869b0b5367fdca109a781902c916126b0cebf Mon Sep 17 00:00:00 2001 From: James Foucar Date: Wed, 20 Mar 2024 12:39:39 -0600 Subject: [PATCH 26/38] Update cprnc to 1.0.7 --- CIME/non_py/cprnc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIME/non_py/cprnc b/CIME/non_py/cprnc index 9276b219750..594f80155dc 160000 --- a/CIME/non_py/cprnc +++ b/CIME/non_py/cprnc @@ -1 +1 @@ -Subproject commit 9276b219750881633d8673c72ec80ac821f96d82 +Subproject commit 594f80155dc1f1f2c5ea06ed5271ee2c04316d1f From 93c48ae12e71dfd0a30c8a193efca4c26813bcbd Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 20 Mar 2024 12:29:47 -0700 Subject: [PATCH 27/38] Adds container pr tag --- .github/workflows/testing.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 44dc61639d4..6397d5d64d4 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -57,6 +57,7 @@ jobs: images: ghcr.io/ESMCI/cime tags: | type=raw,value=latest,enable=${{ github.event_name == 'push' }} + type=ref,event=pull_request,enable=${{ github.event_name == 'pull_request' }} type=sha,format=long - name: Build and push uses: docker/build-push-action@v3 From 1ae1e1a1bfd9eb3245ca7181ce4cb6e9e381baba Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 20 Mar 2024 12:30:38 -0700 Subject: [PATCH 28/38] Adds temporary trigger to dockerfile --- docker/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index a148d921d4c..341ea4c575f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -111,6 +111,9 @@ WORKDIR /src/cime COPY .cime /root/.cime COPY entrypoint.sh /entrypoint.sh +# TODO: REMOVE trigger +ENV TRIGGER=0 + ENTRYPOINT [ "/entrypoint.sh" ] FROM base as slurm From 4164d25b60989ccf93e41c4c856f5d956d162d9e Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 20 Mar 2024 12:31:57 -0700 Subject: [PATCH 29/38] Fixes event type --- .github/workflows/testing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 6397d5d64d4..81494fb57b6 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -57,7 +57,7 @@ jobs: images: ghcr.io/ESMCI/cime tags: | type=raw,value=latest,enable=${{ github.event_name == 'push' }} - type=ref,event=pull_request,enable=${{ github.event_name == 'pull_request' }} + type=ref,event=pr,enable=${{ github.event_name == 'pull_request' }} type=sha,format=long - name: Build and push uses: docker/build-push-action@v3 From effc4e3315b2aa1a025e923fdcb4ac094ea11883 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Wed, 20 Mar 2024 13:39:21 -0700 Subject: [PATCH 30/38] Updates ghcr-prune to remove pr- tags after pr is closed --- .github/scripts/ghcr-prune.py | 95 ++++++++++++++++++++++++-------- .github/workflows/ghcr-prune.yml | 4 +- 2 files changed, 75 insertions(+), 24 deletions(-) diff --git a/.github/scripts/ghcr-prune.py b/.github/scripts/ghcr-prune.py index 87b5db7e112..e5f57e481dc 100644 --- a/.github/scripts/ghcr-prune.py +++ b/.github/scripts/ghcr-prune.py @@ -6,6 +6,11 @@ from datetime import datetime from datetime import timedelta + +class GHCRPruneError(Exception): + pass + + description = """ This script can be used to prune container images hosted on ghcr.io.\n @@ -16,17 +21,28 @@ You can filter containers by any combination of name, age, and untagged. """ -parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawTextHelpFormatter) +parser = argparse.ArgumentParser( + description=description, formatter_class=argparse.RawTextHelpFormatter +) parser.add_argument("--token", required=True, help='GitHub token with "repo" scope') parser.add_argument("--org", required=True, help="Organization name") parser.add_argument("--name", required=True, help="Package name") parser.add_argument( - "--age", type=int, help="Filter versions by age, removing anything older than" + "--age", + type=int, + help="Filter versions by age, removing anything older than", + default=7, ) parser.add_argument( "--filter", help="Filter which versions are consider for pruning", default=".*" ) +parser.add_argument( + "--filter-pr", + action="store_true", + help="Filter pull requests, will skip removal if pull request is still open.", +) +parser.add_argument("--pr-prefix", default="pr-", help="Prefix for a pull request tag") parser.add_argument("--untagged", action="store_true", help="Prune untagged versions") parser.add_argument( "--dry-run", action="store_true", help="Does not actually delete anything" @@ -43,6 +59,8 @@ logger = logging.getLogger("ghcr-prune") +logger.debug(f"Running with arguments:\n{kwargs}") + class GitHubPaginate: """Iterator for GitHub API. @@ -51,13 +69,19 @@ class GitHubPaginate: https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api?apiVersion=2022-11-28 """ - def __init__(self, token, org, name, age, filter, untagged, **_): + + def __init__( + self, token, org, name, age, filter, untagged, filter_pr, pr_prefix, **_ + ): self.token = token self.session = None self.url = ( f"https://api.github.com/orgs/{org}/packages/container/{name}/versions" ) + self.pr_url = f"https://api.github.com/repos/{org}/{name}/pulls" self.expired = datetime.now() - timedelta(days=age) + self.filter_pr = filter_pr + self.pr_prefix = pr_prefix self.filter = re.compile(filter) self.page = None self.untagged = untagged @@ -72,12 +96,27 @@ def create_session(self): } ) + def is_pr_open(self, pr_number): + logger.info(f"Checking if PR {pr_number} is still open") + + pr_url = f"{self.pr_url}/{pr_number}" + + response = self.session.get(pr_url) + + response.raise_for_status() + + data = response.json() + + state = data["state"] + + return state == "open" + def grab_page(self): if self.session is None: - raise Exception("Must create session first") + raise GHCRPruneError("Must create session first") if self.url is None: - raise Exception("No more pages") + raise GHCRPruneError("No more pages") response = self.session.get(self.url) @@ -90,7 +129,7 @@ def grab_page(self): if remaining <= 0: reset = response.headers["X-RateLimit-Reset"] - raise Exception(f"Hit ratelimit will reset at {reset}") + raise GHCRPruneError(f"Hit ratelimit will reset at {reset}") try: self.url = self.get_next_url(response.headers["Link"]) @@ -120,29 +159,39 @@ def filter_results(self, data): logger.debug(f"Processing\n{json.dumps(x, indent=2)}") - try: - tag = x["metadata"]["container"]["tags"][0] - except IndexError: + tags = x["metadata"]["container"]["tags"] + + if len(tags) == 0: logger.info(f'Found untagged version {x["id"]}') if self.untagged: + logger.info(f'Pruning {x["id"]}, untagged') + results.append(url) continue - if not self.filter.match(tag): - logger.info(f"Skipping {tag}, did not match filter") + for tag in tags: + if self.filter_pr and tag.startswith(self.pr_prefix): + pr_number = tag[len(self.pr_prefix) :] - continue + if self.is_pr_open(pr_number): + logger.info(f"Skipping {tag}, PR is still open") + + continue + elif not self.filter.match(tag): + logger.info(f"Skipping {tag}, did not match filter") - if updated_at < self.expired: - logger.info( - f"Pruning {tag}, updated at {updated_at}, expiration {self.expired}" - ) + continue - results.append(url) - else: - logger.info(f"Skipping {tag}, more recent than {self.expired}") + if updated_at < self.expired: + logger.info( + f"Pruning {tag}, updated at {updated_at}, expiration {self.expired}" + ) + + results.append(url) + else: + logger.info(f"Skipping {tag}, more recent than {self.expired}") return results @@ -155,7 +204,7 @@ def __next__(self): if self.page is None or len(self.page) == 0: try: self.page = self.grab_page() - except Exception as e: + except GHCRPruneError as e: logger.debug(f"StopIteration condition {e!r}") raise StopIteration from None @@ -181,7 +230,7 @@ def remove_container(self, url): pager = GitHubPaginate(**kwargs) for url in pager: - if kwargs["dry_run"]: - logger.info(f"Pruning {url}") - else: + logger.info(f"Pruning {url}") + + if not kwargs["dry_run"]: pager.remove_container(url) diff --git a/.github/workflows/ghcr-prune.yml b/.github/workflows/ghcr-prune.yml index 998b6a5330c..6771916b6e7 100644 --- a/.github/workflows/ghcr-prune.yml +++ b/.github/workflows/ghcr-prune.yml @@ -4,6 +4,8 @@ on: # run once a day - cron: '0 2 * * *' +workflow_dispatch: + permissions: {} jobs: @@ -18,4 +20,4 @@ jobs: pip install requests # remove containers older than 14 days and only generated by testing workflow - python .github/scripts/ghcr-prune.py --token ${{ secrets.GITHUB_TOKEN }} --org esmci --name cime --age 14 --filter sha- --untagged + python .github/scripts/ghcr-prune.py --token ${{ secrets.GITHUB_TOKEN }} --org esmci --name cime --age 14 --filter sha- --filter-pr --untagged From 591b8f4d040b40c9d19738aa8831c88465ea99bf Mon Sep 17 00:00:00 2001 From: Mariana Vertenstein Date: Fri, 22 Mar 2024 14:22:39 +0100 Subject: [PATCH 31/38] addition of dglc --- CIME/Tools/Makefile | 8 ++++---- CIME/data/config/cesm/config_files.xml | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CIME/Tools/Makefile b/CIME/Tools/Makefile index 1e6d0f1896c..8cece92eda5 100644 --- a/CIME/Tools/Makefile +++ b/CIME/Tools/Makefile @@ -300,6 +300,10 @@ ifeq ($(ULIBDEP),$(null)) ULIBDEP += $(LIBROOT)/libatm.a CPPDEFS += -DATM_PRESENT endif + ifeq ($(GLC_PRESENT),TRUE) + ULIBDEP += $(LIBROOT)/libglc.a + CPPDEFS += -DGLC_PRESENT + endif ifeq ($(ICE_PRESENT),TRUE) ULIBDEP += $(LIBROOT)/libice.a CPPDEFS += -DICE_PRESENT @@ -316,10 +320,6 @@ ifeq ($(ULIBDEP),$(null)) ULIBDEP += $(LIBROOT)/librof.a CPPDEFS += -DROF_PRESENT endif - ifeq ($(GLC_PRESENT),TRUE) - ULIBDEP += $(LIBROOT)/libglc.a - CPPDEFS += -DGLC_PRESENT - endif ifeq ($(WAV_PRESENT),TRUE) ULIBDEP += $(LIBROOT)/libwav.a CPPDEFS += -DWAV_PRESENT diff --git a/CIME/data/config/cesm/config_files.xml b/CIME/data/config/cesm/config_files.xml index a83773d2335..3a892091c39 100644 --- a/CIME/data/config/cesm/config_files.xml +++ b/CIME/data/config/cesm/config_files.xml @@ -197,7 +197,8 @@ unset $SRCROOT/components/cism/ - $SRCROOT/components/cpl7/components/data_comps_$COMP_INTERFACE/dglc + $SRCROOT/components/cpl7/components/data_comps_$COMP_INTERFACE/dglc + $SRCROOT/components/cdeps/dglc $SRCROOT/components/cpl7/components/stub_comps_$COMP_INTERFACE/sglc $CIMEROOT/CIME/non_py/src/components/stub_comps_$COMP_INTERFACE/sglc $SRCROOT/components/cpl7/components/xcpl_comps_$COMP_INTERFACE/xglc @@ -358,6 +359,7 @@ $COMP_ROOT_DIR_ICE/cime_config/config_archive.xml $COMP_ROOT_DIR_LND/cime_config/config_archive.xml $COMP_ROOT_DIR_OCN/cime_config/config_archive.xml + $COMP_ROOT_DIR_GLC/cime_config/config_archive.xml $COMP_ROOT_DIR_WAV/cime_config/config_archive.xml $COMP_ROOT_DIR_ATM/cime_config/config_archive.xml @@ -429,6 +431,7 @@ $SRCROOT/components/cdeps/dlnd/cime_config/testdefs/testlist_dlnd.xml $SRCROOT/components/cdeps/docn/cime_config/testdefs/testlist_docn.xml $SRCROOT/components/cdeps/drof/cime_config/testdefs/testlist_drof.xml + $SRCROOT/components/cdeps/dglc/cime_config/testdefs/testlist_dglc.xml $SRCROOT/components/cdeps/dwav/cime_config/testdefs/testlist_dwav.xml case_last @@ -461,6 +464,7 @@ $SRCROOT/components/cdeps/dlnd/cime_config/testdefs/testmods_dirs $SRCROOT/components/cdeps/docn/cime_config/testdefs/testmods_dirs $SRCROOT/components/cdeps/drof/cime_config/testdefs/testmods_dirs + $SRCROOT/components/cdeps/dglc/cime_config/testdefs/testmods_dirs $SRCROOT/components/cdeps/dwav/cime_config/testdefs/testmods_dirs case_last @@ -504,6 +508,7 @@ $COMP_ROOT_DIR_ICE/cime_config/namelist_definition_dice.xml $COMP_ROOT_DIR_LND/cime_config/namelist_definition_dlnd.xml $COMP_ROOT_DIR_OCN/cime_config/namelist_definition_docn.xml + $COMP_ROOT_DIR_GLC/cime_config/namelist_definition_dglc.xml $COMP_ROOT_DIR_WAV/cime_config/namelist_definition_dwav.xml From 091c4971025fc66b09d947322cedb8310e4aac08 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 22 Mar 2024 10:14:11 -0700 Subject: [PATCH 32/38] Fixes permissions --- .github/workflows/ghcr-prune.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ghcr-prune.yml b/.github/workflows/ghcr-prune.yml index 6771916b6e7..f7669cbd2b3 100644 --- a/.github/workflows/ghcr-prune.yml +++ b/.github/workflows/ghcr-prune.yml @@ -12,6 +12,7 @@ jobs: prune: permissions: packages: write + pull-requests: read runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 From a508c9d26c425fcfeba7ea574b2e483d3d903b92 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Fri, 22 Mar 2024 10:15:17 -0700 Subject: [PATCH 33/38] Fixes workflow dispatch --- .github/workflows/ghcr-prune.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ghcr-prune.yml b/.github/workflows/ghcr-prune.yml index f7669cbd2b3..c5066a2d667 100644 --- a/.github/workflows/ghcr-prune.yml +++ b/.github/workflows/ghcr-prune.yml @@ -4,7 +4,7 @@ on: # run once a day - cron: '0 2 * * *' -workflow_dispatch: + workflow_dispatch: permissions: {} From bbd66031c4827dcca2fa7011c5fa1eca907aa618 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Wed, 27 Mar 2024 12:59:53 -0600 Subject: [PATCH 34/38] fix an issue with single component runs which do use mediator --- CIME/case/case_run.py | 7 ++++++- CIME/non_py/cprnc | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CIME/case/case_run.py b/CIME/case/case_run.py index 9dd92ec4876..dd49786350b 100644 --- a/CIME/case/case_run.py +++ b/CIME/case/case_run.py @@ -316,9 +316,14 @@ def _post_run_check(case, lid): cpl_logs.append( os.path.join(rundir, file_prefix + "_%04d.log." % (inst + 1) + lid) ) + if driver == "nuopc" and comp_standalone: + cpl_logs.append( + os.path.join(rundir, "med_%04d.log." % (inst + 1) + lid) + ) else: cpl_logs = [os.path.join(rundir, file_prefix + ".log." + lid)] - + if driver == "nuopc" and comp_standalone: + cpl_logs.append(os.path.join(rundir, "med.log." + lid)) cpl_logfile = cpl_logs[0] # find the last model.log and cpl.log model_logfile = os.path.join(rundir, model + ".log." + lid) diff --git a/CIME/non_py/cprnc b/CIME/non_py/cprnc index 594f80155dc..9276b219750 160000 --- a/CIME/non_py/cprnc +++ b/CIME/non_py/cprnc @@ -1 +1 @@ -Subproject commit 594f80155dc1f1f2c5ea06ed5271ee2c04316d1f +Subproject commit 9276b219750881633d8673c72ec80ac821f96d82 From df0411fcc7a1c9ec69b3a85121fddd5d6b119423 Mon Sep 17 00:00:00 2001 From: Mariana Vertenstein Date: Thu, 28 Mar 2024 09:39:16 -0600 Subject: [PATCH 35/38] restored original Makefile --- CIME/Tools/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CIME/Tools/Makefile b/CIME/Tools/Makefile index 5b81c4854bf..e3ddb9c2042 100644 --- a/CIME/Tools/Makefile +++ b/CIME/Tools/Makefile @@ -300,10 +300,6 @@ ifeq ($(ULIBDEP),$(null)) ULIBDEP += $(LIBROOT)/libatm.a CPPDEFS += -DATM_PRESENT endif - ifeq ($(GLC_PRESENT),TRUE) - ULIBDEP += $(LIBROOT)/libglc.a - CPPDEFS += -DGLC_PRESENT - endif ifeq ($(ICE_PRESENT),TRUE) ULIBDEP += $(LIBROOT)/libice.a CPPDEFS += -DICE_PRESENT @@ -320,6 +316,10 @@ ifeq ($(ULIBDEP),$(null)) ULIBDEP += $(LIBROOT)/librof.a CPPDEFS += -DROF_PRESENT endif + ifeq ($(GLC_PRESENT),TRUE) + ULIBDEP += $(LIBROOT)/libglc.a + CPPDEFS += -DGLC_PRESENT + endif ifeq ($(WAV_PRESENT),TRUE) ULIBDEP += $(LIBROOT)/libwav.a CPPDEFS += -DWAV_PRESENT From dea0d66d0245ed43dad013f13d31f56d850096ed Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Thu, 28 Mar 2024 10:07:47 -0700 Subject: [PATCH 36/38] Fixes ghcr-prune script to prune version only when all tags are invalid --- .github/scripts/ghcr-prune.py | 37 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/.github/scripts/ghcr-prune.py b/.github/scripts/ghcr-prune.py index e5f57e481dc..37c538bd621 100644 --- a/.github/scripts/ghcr-prune.py +++ b/.github/scripts/ghcr-prune.py @@ -153,6 +153,8 @@ def filter_results(self, data): logger.info(f"Processing {len(data)} containers") + logger.info(f"Expiration date set to {self.expired}") + for x in data: url = x["url"] updated_at = datetime.strptime(x["updated_at"], "%Y-%m-%dT%H:%M:%SZ") @@ -165,33 +167,46 @@ def filter_results(self, data): logger.info(f'Found untagged version {x["id"]}') if self.untagged: - logger.info(f'Pruning {x["id"]}, untagged') + logger.info(f'Pruning version {x["id"]}') results.append(url) continue + # Any tag that is still valid will cause a pacakge version to not be removed + remove_package_version = True + for tag in tags: if self.filter_pr and tag.startswith(self.pr_prefix): pr_number = tag[len(self.pr_prefix) :] if self.is_pr_open(pr_number): - logger.info(f"Skipping {tag}, PR is still open") - - continue - elif not self.filter.match(tag): - logger.info(f"Skipping {tag}, did not match filter") + logger.info( + f"Skipping package version {x['id']}, PR {pr_number} is still open" + ) - continue + remove_package_version = False - if updated_at < self.expired: + break + elif self.filter.match(tag) and updated_at > self.expired: logger.info( - f"Pruning {tag}, updated at {updated_at}, expiration {self.expired}" + f"Skipping package version {x['id']}, tag {tag!r} matched but was updated at {updated_at}" ) - results.append(url) + remove_package_version = False + + break else: - logger.info(f"Skipping {tag}, more recent than {self.expired}") + logger.info(f"Skipping package version {x['id']}, tag {tag!r}") + + remove_package_version = False + + break + + if remove_package_version: + logger.info(f"Pruning package version {x['id']}") + + results.append(url) return results From 5dbce34d03410cec3c2fe5de24ff94d88319479f Mon Sep 17 00:00:00 2001 From: Lizzie Lundgren Date: Thu, 21 Mar 2024 09:30:49 -0600 Subject: [PATCH 37/38] Fix bug in path to CAM script cam.case_setup.py Just prior to the cime6.0.217 tag there was a change in the original code to call cam.case_setup.py during case setup. The change added a conditional for file path existence, but the file path added was incorrect. This causes the script to never be called and GEOS-Chem compsets will subsequently all fail. Signed-off-by: Lizzie Lundgren --- CIME/case/case_setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CIME/case/case_setup.py b/CIME/case/case_setup.py index a170d1bfddd..730a9911452 100644 --- a/CIME/case/case_setup.py +++ b/CIME/case/case_setup.py @@ -424,8 +424,10 @@ def _case_setup_impl( ) if comp == "cam": camroot = case.get_value("COMP_ROOT_DIR_ATM") - if os.path.exists(os.path.join(camroot, "cam.case_setup.py")): - logger.debug("Running cam.case_setup.py") + if os.path.exists( + os.path.join(camroot, "cime_config/cam.case_setup.py") + ): + logger.info("Running cam.case_setup.py") run_cmd_no_fail( "python {cam}/cime_config/cam.case_setup.py {cam} {case}".format( cam=camroot, case=caseroot From 3d34073f6b894f96b3dbb236edf9ef050916e2f1 Mon Sep 17 00:00:00 2001 From: Jason Boutte Date: Mon, 15 Apr 2024 12:44:04 -0700 Subject: [PATCH 38/38] Disables ghcr-prune workflow --- .github/workflows/ghcr-prune.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ghcr-prune.yml b/.github/workflows/ghcr-prune.yml index c5066a2d667..ca4649170b0 100644 --- a/.github/workflows/ghcr-prune.yml +++ b/.github/workflows/ghcr-prune.yml @@ -1,9 +1,5 @@ name: Prune ghcr.io container images on: - schedule: - # run once a day - - cron: '0 2 * * *' - workflow_dispatch: permissions: {}