diff --git a/.github/workflows/discovery.yaml b/.github/workflows/discovery.yaml new file mode 100644 index 00000000..3d5523df --- /dev/null +++ b/.github/workflows/discovery.yaml @@ -0,0 +1,23 @@ +on: + schedule: + - cron: '0 12 * * *' + pull_request: + workflow_dispatch: +name: Update Discovery Generated Types +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: 16 + # Install all deps, including dev dependencies. + - run: npm install + # Generate types + - run: npm run types + # Submit pull request + - run: npm run submit-discovery-pr + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/package.json b/package.json index b5545d1b..08d8d1f7 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "docs-test": "linkinator docs", "predocs-test": "npm run docs", "types": "node scripts/gen-types.js", + "submit-discovery-pr": "node scripts/submit-discovery-pr.js", "prelint": "cd samples; npm link ../; npm install", "precompile": "gts clean" }, @@ -55,7 +56,9 @@ "arrify": "^2.0.1", "big.js": "^6.0.0", "duplexify": "^4.0.0", + "execa": "^5.0.0", "extend": "^3.0.2", + "gaxios": "^6.0.3", "is": "^3.3.0", "stream-events": "^1.0.5", "uuid": "^9.0.0" diff --git a/scripts/submit-discovery-pr.js b/scripts/submit-discovery-pr.js new file mode 100644 index 00000000..4017f53b --- /dev/null +++ b/scripts/submit-discovery-pr.js @@ -0,0 +1,92 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const execa = require('execa'); +const gaxios = require('gaxios'); + +const REPO = 'alvarowolfx/nodejs-bigquery'; +const BRANCH = 'update-discovery/patch'; +const TRACK_PATHS = ['src/types.d.ts']; +const COMMIT_MESSAGE = 'chore: update types from Discovery'; +const COMMIT_BODY = + 'Automated pull-request to keep BigQuery Discovery types up-to-date.'; + +async function submitDiscoveryPR() { + const statusResult = await execa('git', ['status', '--porcelain']); + const status = statusResult.stdout; + const statusFiles = status.split('\n').map(x => x.slice(3)); + + const foundChanges = statusFiles.filter(f => { + return TRACK_PATHS.some(filename => f.startsWith(filename)); + }); + console.log(`Changes found in ${foundChanges.length} files`); + console.log(foundChanges.join('\n')); + + if (foundChanges.length === 0) { + console.log('No changes found'); + return; + } + + if (process.env.GITHUB_ACTIONS) { + await execa('git', ['config', 'user.email', 'yoshi-automation@google.com']); + await execa('git', ['config', 'user.name', 'Yoshi Automation']); + } + + await execa('git', ['checkout', '-B', BRANCH]); + for (const filename of foundChanges) { + await execa('git', ['add', filename]); + } + await execa('git', ['commit', '-m', COMMIT_MESSAGE, '-m', COMMIT_BODY]); + await execa('git', ['push', 'origin', BRANCH, '--force']); + + const githubToken = process.env.GITHUB_TOKEN; + if (!githubToken) { + throw new Error('please include a GITHUB_TOKEN'); + } + + try { + // Open the pull request with the GITHUB_TOKEN + await gaxios.request({ + method: 'POST', + headers: { + Authorization: `token ${githubToken}`, + }, + url: `https://api.github.com/repos/${REPO}/pulls`, + data: { + title: COMMIT_MESSAGE, + head: BRANCH, + base: 'main', + body: COMMIT_BODY, + }, + }); + } catch (err) { + console.error('failed to submit Pull Request:', err); + if (err.response && err.response.data) { + if (err.response.data.errors) { + const errors = err.response.data.errors; + const exists = errors.some(err => + err.message.includes('already exists') + ); + if (!exists) { + throw err; + } + console.log('PR already exists'); + } + } else { + throw err; + } + } +} + +submitDiscoveryPR();