name: publish-pr-on-npm
on:
  workflow_call:
    inputs:
      pull_request_json:
        description: String that contain JSON payload for `pull_request` event.
        required: true
        type: string
    secrets:
      npm_canary_pr_publish_token:
        description: NPM token to publish canary release.
        required: true
permissions: {}
jobs:
  build-npm-dist:
    runs-on: ubuntu-latest
    permissions:
      contents: read # for actions/checkout
    steps:
      - name: Checkout repo
        uses: actions/checkout@v3
        with:
          persist-credentials: false
          ref: ${{ fromJSON(inputs.pull_request_json).merge_commit_sha }}

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          cache: npm
          node-version-file: '.node-version'

      - name: Install Dependencies
        run: npm ci --ignore-scripts

      - name: Build NPM package
        run: npm run build:npm

      - name: Upload npmDist package
        uses: actions/upload-artifact@v3
        with:
          name: npmDist
          path: ./npmDist

  publish-canary:
    runs-on: ubuntu-latest
    name: Publish Canary
    environment: canary-pr-npm
    needs: [build-npm-dist]
    permissions:
      contents: read # for actions/checkout
    steps:
      - name: Checkout repo
        uses: actions/checkout@v3
        with:
          persist-credentials: false

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          cache: npm
          node-version-file: '.node-version'
          # 'registry-url' is required for 'npm publish'
          registry-url: 'https://registry.npmjs.org'

      - uses: actions/download-artifact@v3
        with:
          name: npmDist
          path: npmDist

      - name: Modify NPM package to be canary release
        env:
          PULL_REQUEST_JSON: ${{ inputs.pull_request_json }}
        uses: actions/github-script@v6
        with:
          script: |
            const fs = require('node:fs');
            const assert = require('node:assert');

            const pull_request = JSON.parse(process.env.PULL_REQUEST_JSON);
            const packageJSONPath = './npmDist/package.json';
            const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, 'utf-8'));

            // Override entire 'publishConfig' since it can contain untrusted data.
            packageJSON.publishConfig = { tag: `canary-pr-${pull_request.number}` };

            assert(!packageJSON.version.includes('+'), 'Can not append after metadata');
            packageJSON.version += packageJSON.version.includes('-') ? '.' : '-';
            packageJSON.version += `canary.pr.${pull_request.number}.${pull_request.merge_commit_sha}`;

            packageJSON.deprecated =
              `You are using canary version build from ${pull_request.html_url}, no gurantees provided so please use your own discretion.`;

            assert(
              packageJSON.scripts == null,
              'No scripts allowed for security reasons!',
            );

            fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON, null, 2));

            const replyMessage = `
            The latest changes of this PR are available on NPM as
            [graphql@${packageJSON.version}](https://www.npmjs.com/package/graphql/v/${packageJSON.version})
            **Note: no gurantees provided so please use your own discretion.**

            Also you can depend on latest version built from this PR:
            \`npm install --save graphql@${packageJSON.publishConfig.tag}\`
            `;
            fs.writeFileSync('./replyMessage.txt', replyMessage.trim());

      - name: Publish NPM package
        run: npm publish --ignore-scripts ./npmDist
        env:
          NODE_AUTH_TOKEN: ${{ secrets.npm_canary_pr_publish_token }}

      - name: Upload replyMessage
        uses: actions/upload-artifact@v3
        with:
          name: replyMessage
          path: ./replyMessage.txt