github.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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 TrustGitHub extends TrustCommand {
  6. static description = 'Create a trusted relationship between a package and GitHub Actions'
  7. static name = 'github'
  8. static positionals = 1 // expects at most 1 positional (package name)
  9. static providerName = 'GitHub Actions'
  10. static providerEntity = 'GitHub repository'
  11. static providerFile = 'GitHub Actions Workflow'
  12. static providerHostname = 'https://github.com'
  13. // entity means project / repository
  14. static entityKey = 'repository'
  15. static usage = [
  16. '[package] --file [--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 workflow file within a repositories .GitHub folder (must end in yaml, yml)',
  24. }),
  25. new Definition('repository', {
  26. default: null,
  27. type: String,
  28. description: 'Name of the repository in the format owner/repo',
  29. alias: ['repo'],
  30. }),
  31. new Definition('environment', {
  32. default: null,
  33. type: String,
  34. description: 'CI environment name',
  35. alias: ['env'],
  36. }),
  37. // globals are alphabetical
  38. globalDefinitions['dry-run'],
  39. globalDefinitions.json,
  40. globalDefinitions.registry,
  41. globalDefinitions.yes,
  42. ]
  43. getEntityUrl ({ providerHostname, file, entity }) {
  44. if (file) {
  45. return new URL(`${entity}/blob/HEAD/.github/workflows/${file}`, providerHostname).toString()
  46. }
  47. return new URL(entity, providerHostname).toString()
  48. }
  49. validateEntity (entity) {
  50. if (entity.split('/').length !== 2) {
  51. throw new Error(`${this.constructor.providerEntity} must be specified in the format owner/repository`)
  52. }
  53. }
  54. validateFile (file) {
  55. if (file !== path.basename(file)) {
  56. throw new Error('GitHub Actions workflow must be just a file not a path')
  57. }
  58. }
  59. static optionsToBody (options) {
  60. const { file, repository, environment } = options
  61. const trustConfig = {
  62. type: 'github',
  63. claims: {
  64. repository,
  65. workflow_ref: {
  66. file,
  67. },
  68. ...(environment) && { environment },
  69. },
  70. }
  71. return trustConfig
  72. }
  73. // Convert API response body to options
  74. static bodyToOptions (body) {
  75. const file = body.claims?.workflow_ref?.file
  76. const repository = body.claims?.repository
  77. const environment = body.claims?.environment
  78. return {
  79. ...(body.id) && { id: body.id },
  80. ...(body.type) && { type: body.type },
  81. ...(file) && { file },
  82. ...(repository) && { repository },
  83. ...(environment) && { environment },
  84. }
  85. }
  86. async exec (positionalArgs, flags) {
  87. await this.createConfigCommand({
  88. positionalArgs,
  89. flags,
  90. })
  91. }
  92. }
  93. module.exports = TrustGitHub