I feel this. There is a gigantic difference in usability (and in my experience, productivity and maintainability) between the two self-hostable platforms (Gitlab being much better than Github enterprise), and I'm not sure that there's really a good set of metrics to expose when an executive says "here's the easy cost bottom line" between the two. Somehow, the fact that the free GitLab product is already significantly better than the paid GH product seems to be missed as well.
There's just too much FUD about not having a service contract, and that since GH and MS are household names, people assume their products are better and will move forward more quickly. That is not my experience at all, across several companies that have tried both.
All I can say is I'll probably invest in GitLab when it IPOs. It's almost certainly going to be undervalued.
To be honest I would really recommend giving either Gitlab CI or Github actions a shot. One of the main factors in my thing failing was the inability to compete with the vertical integration these tools both have, which is a massive lever for simplicity, power and reliability.
The disadvantage you rightly highlight is some degree of lock in, should you ever need to move your code, but if you put the core logic of your workflows into scripts (which you likely should do regardless) then this really isn't a big issue.
Genuinely, give Github actions a try - see if your opinion doesn't change once you see its advantages.
Basically there are large build/integration/test jobs that are centrally managed on Jenkins via Pipeline/Jenkinsfile, but then we offer a library of relatively simple common-case gitlab-ci configs that can be trivially pulled in, so most common cases are basically a one-liner (build dpkg, build setuptools, build sphinx, run nose, etc), but from the dev's point of view it's a self-serve thing rather than some mystery-meat process that can only be altered by filing DevOps tickets and hoping for the best.
TBH I think my biggest complaint with GitLab CI is the insistence that every job is a brand new container. This means if you, say, have a big NPM project that installs thousands of dependencies on every run, you have to either a) hit your repo multiple times and not worry about it, b) figure out a local-enough caching proxy for your repo that it doesn't matter, c) combine your build/test/lint stages into a single one, d) build from a nightly container that has a bunch of it pre-installed, e) abuse the artifacts system to pass the workspace between jobs, f) spend multiple hours trying to make the supplied caching mechanism work, only to find that no matter what you do, NPM ignores the cache and re-fetches every time, and even if it worked, you'd have to pick between various non-ideal cache-keying strategies: https://docs.gitlab.com/ee/ci/caching/
https://docs.gitlab.com/runner/configuration/feature-flags.h...