CircleCI Field Guide
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage
Edit page

Publishing an Orb to multiple namespaces

Sometimes, an organization may wish to share a private orb with multiple organizations. Currently, private orbs are by definition restricted to a single organization.

However, this limitation can be circumvented by publishing an orb to multiple namespaces simultaneously. This can be integrated into the automated pipeline that deploys the orb. The overhead is minimal, making this a viable workaround for many users seeking this functionality.

Prerequisites

An orb that is already being built, tested, and deployed in the conventional manner as outlined by the Orb Development Kit.

Concept

To deploy the orb to multiple namespaces, a copy of the “packed” orb created as part of the orb deployment pipeline is required. Small, necessary, but automated changes will be made to this copy, which is then deployed to the secondary namespace.

Implementation

All of this behavior can be achieved by adding a single additional job to the existing test-deploy workflow. The lint-pack workflow will remain unchanged.

Creating the replica source

Conventionally, the packed orb exists in the workspace in orb.yml. The first step is to copy this orb.

- run:
    name: Create replica of the orb
    command: cp dist/orb.yml dist/orb-replica-my-namespace-2.yml

Updating the replica to use the new namespace

This step is only strictly necessary if the orb uses other private orbs. It’s important to note that those other private orbs will already need to be published as replicas.

In such cases, the orb will be referencing orbs in a namespace it does not have access to.

For example:

orbs:
  my-other-private-orb: my-namespace-1/my-private-orb@volatile

However, there isn’t access to private orbs in my-namespace-1 when publishing to my-namespace-2.

Therefore, any of these references in the replica can be automatically updated.

# Update the replica's source to use its own organisations private orbs
# Note: this has not been extensively tested
- run:
    name: Update private orb references in replica source
    command: |
      # Here we'll just refactor the YAML to replace any orbs from org-1 to use the namespace org-2
      # note this could be more concise but this makes sure to gracefully handle inline orbs
      ORIGINAL_ORG_NAME="org-1"
      NEW_ORG_NAME="org-2"
      SOURCE_FILE="dist/orb-replica.yml"
      # Get list of keys under orbs
      keys=$(yq '(.orbs | keys)[]' $SOURCE_FILE)
      for key in $keys
      do
        # Trim key
        key=$(echo $key | xargs)
        # Get current value
        value=$(yq ".orbs.\"$key\"" $SOURCE_FILE)
        # If the value is a string containing "$ORIGINAL_ORG_NAME/",
        if [[ $value == "${ORIGINAL_ORG_NAME}/"* ]]
        then
          echo "Updating $value to use $NEW_ORG_NAME"
          # Note this line updates the yaml file in-place
          yq e -i ".orbs.\"$key\" = \"${value//$ORIGINAL_ORG_NAME/$NEW_ORG_NAME}\"" $SOURCE_FILE
        fi
      done      

The replica orb will now have no remaining references to the primary namespace (my-namespace-1).

Caveats

Technically, the above script might not catch everything if there are some inline orbs that use private orbs. However, this is not a common scenario.

E.g

orbs:
  some-inline-orb:
    orbs:
      my-orb: private-namespace/my-orb@volatile

private-namespace would not be caught here.

Publish the orb

This replica is now ready to be published in the usual fashion. You can either do this manually or using the orb-tools orb.

Manually

# Note this job needs a PAT for the replica org
- run:
    name: Publish orb replica
    # See `circleci orb publish` for full params
    command: circleci orb publish dist/orb-replica-my-namespace-2.yml replica-namespace/my-orb

Using orb-tools

The orb-tools orb only provides the publish function as a job, so you’ll need to add the replica to the workspace before the publish job runs.

# You'll already have an orb-tools/publish job in your workflow
- orb-tools/publish:
    requires: [] #require your test jobs
    context: [] # PAT context

# test-publish workflow
- create-replicas:
    requires: [] # require your test jobs

# dist/orb-replica-my-namespace-2.yml needs to be added to the workspace in `create-replicas`
- orb-tools/publish:
    name: publish-replica-my-namespace-2
    requres: [create-replica]
    context: [my-namespace-2-pat]
    orb_file_name: dist/orb-replica-my-namespace-2.yml
    orb_name: my-namespace-2/orb-name

Wrap up

In conclusion, with this approach, you should find that you are able to deploy a private orb to multiple organizations in a single pipeline with minimal fuss.