Skip to content

[duplicate-code] Duplicate Code: Cloud Provider Store Cache Infrastructure in linode, digitalocean, and pnap stores #133

Description

@github-actions

Assignee: @copilot

Summary

The Vuex store modules for three cloud providers (linode, digitalocean, and pnap) contain an identical 29-line cache infrastructure block — the same state, mutations.setCache, getters.fromCache, and cachedCommand action are copy-pasted verbatim across all three files. Any bug fix or enhancement to the caching logic must be applied to three separate places.

Duplication Details

Pattern: Shared credential-keyed cache state + mutations + getters + cachedCommand action

  • Severity: High
  • Occurrences: 3 files
  • Locations:
    • shell/store/linode.js (lines 6–96)
    • shell/store/digitalocean.js (lines 24–152)
    • shell/store/pnap.js (lines 6–75)

Identical state + mutations + getters block (22 lines — exact copy in all 3 files):

export const state = () => {
  return { cache: {} };
};

export const mutations = {
  setCache(state, { credentialId, key, value }) {
    let cache = state.cache[credentialId];

    if ( !cache ) {
      cache = {};
      state.cache[credentialId] = cache;
    }

    cache[key] = value;
  },
};

export const getters = {
  fromCache: (state) => ({ credentialId, key }) => {
    return state.cache[credentialId]?.[key];
  },
};

Nearly-identical cachedCommand action (12 lines in each file):

async cachedCommand({ getters, commit, dispatch }, { credentialId, command }) {
  let out = getters['fromCache']({ credentialId, key: command });

  if ( !out ) {
    out = await dispatch('request', { credentialId, command });
    commit('setCache', {
      credentialId, key: command, value: out
    });
  }

  return out;
},

Impact Analysis

  • Maintainability: Any change to caching logic (e.g., cache invalidation, TTL support, error handling) must be duplicated across all three files.
  • Bug Risk: A bug fix in one store could easily be missed in the others, leading to inconsistent behaviour.
  • Code Bloat: ~34 lines repeated three times adds ~68 lines of avoidable code.

Refactoring Recommendations

  1. Extract shared cache factory — Create shell/store/cloud-provider-cache.js that exports the shared state, mutations, getters, and cachedCommand action:

    • Estimated effort: 1–2 hours
    • Benefits: Single source of truth, easier testing, consistent behaviour
    // shell/store/cloud-provider-cache.js
    export const createCacheState = () => ({ cache: {} });
    
    export const cacheMutations = {
      setCache(state, { credentialId, key, value }) {
        let cache = state.cache[credentialId];
        if (!cache) {
          cache = {};
          state.cache[credentialId] = cache;
        }
        cache[key] = value;
      },
    };
    
    export const cacheGetters = {
      fromCache: (state) => ({ credentialId, key }) => state.cache[credentialId]?.[key],
    };
    
    export const cachedCommandAction = {
      async cachedCommand({ getters, commit, dispatch }, { credentialId, command }) {
        let out = getters['fromCache']({ credentialId, key: command });
        if (!out) {
          out = await dispatch('request', { credentialId, command });
          commit('setCache', { credentialId, key: command, value: out });
        }
        return out;
      },
    };
  2. Update each store to spread the shared pieces:

    import { createCacheState, cacheMutations, cacheGetters, cachedCommandAction } from './cloud-provider-cache';
    
    export const state = createCacheState;
    export const mutations = { ...cacheMutations };
    export const getters = { ...cacheGetters };
    export const actions = {
      ...cachedCommandAction,
      // provider-specific actions...
    };

Implementation Checklist

  • Review duplication findings
  • Create shell/store/cloud-provider-cache.js shared module
  • Update shell/store/linode.js to use shared module
  • Update shell/store/digitalocean.js to use shared module
  • Update shell/store/pnap.js to use shared module
  • Add/update unit tests for the shared module
  • Verify no functionality broken

Analysis Metadata

  • Analyzed Files: 3 (shell/store/linode.js, shell/store/digitalocean.js, shell/store/pnap.js)
  • Detection Method: Semantic code analysis + line-by-line diff
  • Commit: 3331497
  • Analysis Date: 2026-07-04T21:20:52Z

Generated by Duplicate Code Detector · ● 2.2M ·

  • expires on Jul 6, 2026, 9:24 PM UTC

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions