Introduce a model to abstract SCM service integration

[finishes #80208778]
You probably considered this already, but maybe we could share this code. We'd only need to pass user in, right? I could go either way since it's only used in 2 spots.