Deprecating a version of C-PAC

In the rare occasion that a version of C-PAC needs to be deprecated, we add CRITICAL_ALERT.rst as a runtime warning and rename the deprecated image tag to ${DEPRECATED_TAG}-DEPRECATED and replace the original tag for the deprecated image with an image that only displays CRITICAL_ALERT.rst. For example, fcpindi/c-pac:release-v1.8.1-DEPRECATED is the tag that would be needed to run v1.8.1 after v1.8.1 was deprecated.

To semiautomatically deprecate a published version of C-PAC, follow these steps:

  1. Write a CRITICAL ALERT (e.g., “Critical Alert for fMRIPrep-Options in C-PAC v1.8.1 - v1.8.3”) describing the need for the deprecation, the affected versions, and any recommendations.

  2. Include that CRITICAL ALERT in the GitHub release notes for new version (e.g., C-PAC/releases/v.1.8.4 “C-PAC Version 1.8.4 Beta”).

  3. Use CPAC-Development/deprecate to deprecate the affected version images on Docker Hub. This process requires adequate permissions in the fcp-indi organization on Docker Hub to docker push.

    1. If you aren’t already logged into Docker Hub, docker login.

      In a local clone or copy of CPAC-Development:

    2. Replace the critical alert in CRITICAL_ALERT.rst with the CRITICAL_ALERT from step one, above.

    3. Update cpac_pipeline.py and run.py:

      1. Overwrite the current versions in the CPAC-Development/deprecate with the versions from the source code of the version of C-PAC to deprecate.

      2. Add

        shutil.copyfile('/CRITICAL_ALERT.rst',
                        os.path.join(log_dir, 'CRITICAL_ALERT.rst'))
        

        to cpac_pipeline.py after

        if not os.path.exists(log_dir):
           os.makedirs(os.path.join(log_dir))
        

        (e.g., cpac_pipeline.py#L264-L265@6cd6c67) and make sure shutil is imported before calling that library.

      3. Also in cpac_pipeline.py, update the variable execution_info to include {critical_alert} at the end, like cpac_pipeline.py#L370@6cd6c67:

        execution_info = """
        
           End of subject workflow {workflow}
        
           CPAC run complete:
        
              Pipeline configuration: {pipeline}
              Subject workflow: {workflow}
              Elapsed run time (minutes): {elapsed}
              Timing information saved in {log_dir}/cpac_individual_timing_{pipeline}.csv
              System time of start:      {run_start}
              System time of completion: {run_finish}
        
        {critical_alert}
        """
        

        Note

        There are probably at least two definitions of execution_info that need {critical_alert} appended to them (e.g., cpac_pipeline.py#L706@6cd6c67).

      4. Also in cpac_pipeline.py, define critical_alert based on the CRITICAL_ALERT.rst file you already updated (e.g., cpac_pipeline.py#L373-L376@6cd6c67):

        with open('/CRITICAL_ALERT.rst', 'r') as critical_alert_file:
           critical_alert = '\n'.join([
                 f'    {line.rstrip()}' for line in critical_alert_file.readlines()])
        
      5. Also in cpac_pipeline.py, update any calls to execution_info.format() to populate the string variable {critical_alert} with the critical_alert you defined above (e.g., cpac_pipeline.py#L723@6cd6c67):

        logger.info(execution_info.format(
           workflow=workflow.name,
           pipeline=c.pipeline_setup['pipeline_name'],
           log_dir=c.pipeline_setup['log_directory']['path'],
           elapsed=(time.time() - pipeline_start_time) / 60,
           run_start=pipeline_start_datetime,
           run_finish=strftime("%Y-%m-%d %H:%M:%S"),
           critical_alert=critical_alert
        ))
        
      6. In run.py, print the contents of CRITICAL_ALERT.rst, e.g. run.py#L216-L220@6cd6c67:

        with open('/CRITICAL_ALERT.rst', 'r') as critical_alert_file:
           critical_alert = ''.join([line for line in
                                     critical_alert_file.readlines() if
                                     not line.startswith('.. ')])
        print(critical_alert)
        
    4. From the deprecate subdirectory, run

      ./build_and_deprecate ${DEPRECATED_TAG} ${RECOMMENDED_MINIMUM_VERSION}
      

      for each tag (as ${DEPRECATED_TAG}) that needs to be deprecated. This script will build the replacement images and push them to Docker Hub, overwriting the original image. See fcpindi/c-pac Tags | Docker Hub for all C-PAC tags currently published on Docker Hub. ${RECOMMENDED_MINIMUM_VERSION} is the semver without any leading v. For example

      for each TAG in "" -lite -ABCD-HCP -fMRIPrep-LTS
      do
        ./build_and_deprecate release-v1.8.1$TAG 1.8.4
      done
      

      to deprecate all variants of C-PAC v1.8.1 with recommended mimumum version v1.8.4.

      If the version to be deprecated is already deprecated but the critical alert needs to be updated, that can be done with the same syntax with ./rebuild_and_deprecate (e.g.,

      ./rebuild_and_deprecate release-v1.8.1-lite 1.8.4
      

      to update the critical alert for release-v1.8.1-lite and release-v1.8.1-DEPRECATED).

  4. Add the critical alert to the release notes of each newly deprecated version, or update the critical alert if one already exists for that version (e.g., C-PAC/releases/v.1.8.1 “C-PAC Version 1.8.1 Beta”).

  5. Trigger a rebuild of this documentation for the new version of C-PAC.