gitlab.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. const Definition = require('@npmcli/config/lib/definitions/definition.js')
  2. const globalDefinitions = require('@npmcli/config/lib/definitions/definitions.js')
  3. const TrustCommand = require('../../trust-cmd.js')
  4. const path = require('node:path')
  5. class TrustGitLab extends TrustCommand {
  6. static description = 'Create a trusted relationship between a package and GitLab CI/CD'
  7. static name = 'gitlab'
  8. static positionals = 1 // expects at most 1 positional (package name)
  9. static providerName = 'GitLab CI/CD'
  10. static providerEntity = 'GitLab project'
  11. static providerFile = 'GitLab CI/CD Pipeline'
  12. static providerHostname = 'https://gitlab.com'
  13. // entity means project / repository
  14. static entityKey = 'project'
  15. static usage = [
  16. '[package] --file [--project|--repo|--repository] [--env|--environment] [-y|--yes]',
  17. ]
  18. static definitions = [
  19. new Definition('file', {
  20. default: null,
  21. type: String,
  22. required: true,
  23. description: 'Name of pipeline file (e.g., .gitlab-ci.yml)',
  24. }),
  25. new Definition('project', {
  26. default: null,
  27. type: String,
  28. description: 'Name of the project in the format group/project or group/subgroup/project',
  29. }),
  30. new Definition('environment', {
  31. default: null,
  32. type: String,
  33. description: 'CI environment name',
  34. alias: ['env'],
  35. }),
  36. // globals are alphabetical
  37. globalDefinitions['dry-run'],
  38. globalDefinitions.json,
  39. globalDefinitions.registry,
  40. globalDefinitions.yes,
  41. ]
  42. getEntityUrl ({ providerHostname, file, entity }) {
  43. if (file) {
  44. return new URL(`${entity}/-/blob/HEAD/${file}`, providerHostname).toString()
  45. }
  46. return new URL(entity, providerHostname).toString()
  47. }
  48. validateEntity (entity) {
  49. if (entity.split('/').length < 2) {
  50. throw new Error(`${this.constructor.providerEntity} must be specified in the format group/project or group/subgroup/project`)
  51. }
  52. }
  53. validateFile (file) {
  54. if (file !== path.basename(file)) {
  55. throw new Error('GitLab CI/CD pipeline file must be just a file not a path')
  56. }
  57. }
  58. static optionsToBody (options) {
  59. const { file, project, environment } = options
  60. const trustConfig = {
  61. type: 'gitlab',
  62. claims: {
  63. project_path: project,
  64. // this looks off, but this is correct
  65. /** The ref path to the top-level pipeline definition, for example, gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main. Introduced in GitLab 16.2. This claim is null unless the pipeline definition is located in the same project. */
  66. ci_config_ref_uri: {
  67. file,
  68. },
  69. ...(environment) && { environment },
  70. },
  71. }
  72. return trustConfig
  73. }
  74. // Convert API response body to options
  75. static bodyToOptions (body) {
  76. const file = body.claims?.ci_config_ref_uri?.file
  77. const project = body.claims?.project_path
  78. const environment = body.claims?.environment
  79. return {
  80. ...(body.id) && { id: body.id },
  81. ...(body.type) && { type: body.type },
  82. ...(file) && { file },
  83. ...(project) && { project },
  84. ...(environment) && { environment },
  85. }
  86. }
  87. async exec (positionalArgs, flags) {
  88. await this.createConfigCommand({
  89. positionalArgs,
  90. flags,
  91. })
  92. }
  93. }
  94. module.exports = TrustGitLab