CLI tool and GH workflow to highlight PR changes (#32063)
This commit is contained in:
parent
02ef6c534e
commit
2f4f8277bf
|
@ -0,0 +1,88 @@
|
|||
name: Highlight templates and hooks changes
|
||||
on: pull_request
|
||||
jobs:
|
||||
analyze:
|
||||
name: Check pull request changes to highlight
|
||||
runs-on: ubuntu-20.04
|
||||
outputs:
|
||||
results: ${{ steps.results.outputs.results }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install prerequisites
|
||||
run: |
|
||||
npm install -g pnpm@^6.24.2
|
||||
pnpm install
|
||||
- name: Run analyzer
|
||||
id: run
|
||||
run: ./tools/code-analyzer/bin/dev analyzer "$GITHUB_HEAD_REF" -o github
|
||||
- name: Print results
|
||||
id: results
|
||||
run: echo "::set-output name=results::${{ steps.run.outputs.templates }}${{ steps.run.outputs.wphooks }}"
|
||||
comment:
|
||||
name: Add comment to hightlight changes
|
||||
needs: analyze
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@v2
|
||||
id: find-comment
|
||||
with:
|
||||
issue-number: ${{ github.event.number }}
|
||||
comment-author: woocommercebot
|
||||
- name: Add comment
|
||||
if: ${{ needs.analyze.outputs.results && (steps.find-comment.outputs.comment-id == '') }}
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
github-token: ${{ secrets.WC_BOT_TRIAGE_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '## New hook or template changes in this PR${{ needs.analyze.outputs.results }}'
|
||||
})
|
||||
- name: Update comment
|
||||
if: ${{ needs.analyze.outputs.results && steps.find-comment.outputs.comment-id }}
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
github-token: ${{ secrets.WC_BOT_TRIAGE_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.updateComment({
|
||||
comment_id: ${{ steps.find-comment.outputs.comment-id }},
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '## New hook or template changes in this PR${{ needs.analyze.outputs.results }}'
|
||||
})
|
||||
- name: Delete comment
|
||||
if: ${{ !needs.analyze.outputs.results && steps.find-comment.outputs.comment-id }}
|
||||
uses: izhangzhihao/delete-comment@master
|
||||
with:
|
||||
github_token: ${{ secrets.WC_BOT_TRIAGE_TOKEN }}
|
||||
delete_user_name: woocommercebot
|
||||
issue_number: ${{ github.event.number }}
|
||||
- name: Add label
|
||||
if: ${{ needs.analyze.outputs.results }}
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
github-token: ${{ secrets.WC_BOT_TRIAGE_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['release: highlight']
|
||||
})
|
||||
- name: Remove label
|
||||
if: ${{ !needs.analyze.outputs.results }}
|
||||
continue-on-error: true
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
github-token: ${{ secrets.WC_BOT_TRIAGE_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.removeLabel({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name: ['release: highlight']
|
||||
})
|
150
pnpm-lock.yaml
150
pnpm-lock.yaml
|
@ -1643,6 +1643,33 @@ importers:
|
|||
sass: 1.45.0
|
||||
stylelint: 13.8.0
|
||||
|
||||
tools/code-analyzer:
|
||||
specifiers:
|
||||
'@oclif/core': ^1
|
||||
'@oclif/plugin-help': ^5
|
||||
'@oclif/plugin-plugins': ^2.0.1
|
||||
'@types/node': ^16.9.4
|
||||
eslint: ^7.32.0
|
||||
globby: ^11
|
||||
oclif: ^2
|
||||
shx: ^0.3.3
|
||||
ts-node: ^10.2.1
|
||||
tslib: ^2.3.1
|
||||
typescript: ^4.4.3
|
||||
dependencies:
|
||||
'@oclif/core': 1.3.4
|
||||
'@oclif/plugin-help': 5.1.11
|
||||
'@oclif/plugin-plugins': 2.1.0
|
||||
devDependencies:
|
||||
'@types/node': 16.10.3
|
||||
eslint: 7.32.0
|
||||
globby: 11.1.0
|
||||
oclif: 2.4.5
|
||||
shx: 0.3.4
|
||||
ts-node: 10.5.0_506ca6ef959d35afcce359030b1bc9ff
|
||||
tslib: 2.3.1
|
||||
typescript: 4.6.2
|
||||
|
||||
tools/monorepo-merge:
|
||||
specifiers:
|
||||
'@oclif/core': ^1
|
||||
|
@ -1802,7 +1829,7 @@ packages:
|
|||
/@babel/code-frame/7.12.11:
|
||||
resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==}
|
||||
dependencies:
|
||||
'@babel/highlight': 7.16.0
|
||||
'@babel/highlight': 7.16.10
|
||||
dev: true
|
||||
|
||||
/@babel/code-frame/7.16.0:
|
||||
|
@ -8234,7 +8261,7 @@ packages:
|
|||
ignore: 4.0.6
|
||||
import-fresh: 3.3.0
|
||||
js-yaml: 3.14.1
|
||||
minimatch: 3.0.4
|
||||
minimatch: 3.1.2
|
||||
strip-json-comments: 3.1.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -8332,7 +8359,7 @@ packages:
|
|||
dependencies:
|
||||
'@humanwhocodes/object-schema': 1.2.1
|
||||
debug: 4.3.4
|
||||
minimatch: 3.0.4
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
@ -9931,11 +9958,11 @@ packages:
|
|||
chalk: 4.1.2
|
||||
clean-stack: 3.0.1
|
||||
cli-progress: 3.10.0
|
||||
debug: 4.3.3_supports-color@8.1.1
|
||||
debug: 4.3.4_supports-color@8.1.1
|
||||
ejs: 3.1.6
|
||||
fs-extra: 9.1.0
|
||||
get-package-type: 0.1.0
|
||||
globby: 11.0.4
|
||||
globby: 11.1.0
|
||||
hyperlinker: 1.0.0
|
||||
indent-string: 4.0.0
|
||||
is-wsl: 2.2.0
|
||||
|
@ -9979,7 +10006,7 @@ packages:
|
|||
'@oclif/color': 1.0.1
|
||||
'@oclif/core': 1.3.4
|
||||
chalk: 4.1.2
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
fs-extra: 9.1.0
|
||||
http-call: 5.3.0
|
||||
load-json-file: 5.3.0
|
||||
|
@ -9997,7 +10024,7 @@ packages:
|
|||
dependencies:
|
||||
'@oclif/core': 1.3.4
|
||||
chalk: 4.1.2
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
fs-extra: 9.1.0
|
||||
http-call: 5.3.0
|
||||
lodash: 4.17.21
|
||||
|
@ -13617,7 +13644,7 @@ packages:
|
|||
resolution: {integrity: sha512-ayJ0iOCDNHnKpKTgBG6Q6JOnHTj9zFta+3j2b8Ejza0e4cvRyMn0ZoLEmbPrTHe5YYRlDYPvPWVdV4cTaRyH7g==}
|
||||
dependencies:
|
||||
'@types/expect': 1.20.4
|
||||
'@types/node': 16.10.3
|
||||
'@types/node': 17.0.21
|
||||
dev: true
|
||||
|
||||
/@types/webpack-env/1.16.3:
|
||||
|
@ -13686,7 +13713,6 @@ packages:
|
|||
re-resizable: 4.11.0
|
||||
transitivePeerDependencies:
|
||||
- react
|
||||
- react-dom
|
||||
dev: true
|
||||
|
||||
/@types/wordpress__compose/4.0.1:
|
||||
|
@ -16678,7 +16704,7 @@ packages:
|
|||
resolution: {integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
dependencies:
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
depd: 1.1.2
|
||||
humanize-ms: 1.2.1
|
||||
transitivePeerDependencies:
|
||||
|
@ -20530,18 +20556,6 @@ packages:
|
|||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
/debug/4.3.3_supports-color@8.1.1:
|
||||
resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==}
|
||||
engines: {node: '>=6.0'}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
supports-color: 8.1.1
|
||||
|
||||
/debug/4.3.3_supports-color@9.2.2:
|
||||
resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==}
|
||||
engines: {node: '>=6.0'}
|
||||
|
@ -20566,6 +20580,18 @@ packages:
|
|||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
/debug/4.3.4_supports-color@8.1.1:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
supports-color: 8.1.1
|
||||
|
||||
/debuglog/1.0.1:
|
||||
resolution: {integrity: sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=}
|
||||
dev: true
|
||||
|
@ -22432,7 +22458,7 @@ packages:
|
|||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.3
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
doctrine: 3.0.0
|
||||
enquirer: 2.3.6
|
||||
escape-string-regexp: 4.0.0
|
||||
|
@ -22455,7 +22481,7 @@ packages:
|
|||
json-stable-stringify-without-jsonify: 1.0.1
|
||||
levn: 0.4.1
|
||||
lodash.merge: 4.6.2
|
||||
minimatch: 3.0.4
|
||||
minimatch: 3.1.2
|
||||
natural-compare: 1.4.0
|
||||
optionator: 0.9.1
|
||||
progress: 2.0.3
|
||||
|
@ -22463,7 +22489,7 @@ packages:
|
|||
semver: 7.3.5
|
||||
strip-ansi: 6.0.1
|
||||
strip-json-comments: 3.1.1
|
||||
table: 6.7.3
|
||||
table: 6.8.0
|
||||
text-table: 0.2.0
|
||||
v8-compile-cache: 2.3.0
|
||||
transitivePeerDependencies:
|
||||
|
@ -23282,7 +23308,7 @@ packages:
|
|||
/filelist/1.0.2:
|
||||
resolution: {integrity: sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==}
|
||||
dependencies:
|
||||
minimatch: 3.0.4
|
||||
minimatch: 3.1.2
|
||||
|
||||
/fileset/2.0.3:
|
||||
resolution: {integrity: sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=}
|
||||
|
@ -24341,9 +24367,9 @@ packages:
|
|||
'@types/glob': 7.2.0
|
||||
array-union: 2.1.0
|
||||
dir-glob: 3.0.1
|
||||
fast-glob: 3.2.7
|
||||
fast-glob: 3.2.11
|
||||
glob: 7.2.0
|
||||
ignore: 5.1.9
|
||||
ignore: 5.2.0
|
||||
merge2: 1.4.1
|
||||
slash: 3.0.0
|
||||
dev: true
|
||||
|
@ -25155,7 +25181,7 @@ packages:
|
|||
engines: {node: '>=8.0.0'}
|
||||
dependencies:
|
||||
content-type: 1.0.4
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
is-retry-allowed: 1.2.0
|
||||
is-stream: 2.0.1
|
||||
parse-json: 4.0.0
|
||||
|
@ -25220,7 +25246,7 @@ packages:
|
|||
dependencies:
|
||||
'@tootallnate/once': 2.0.0
|
||||
agent-base: 6.0.2
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
@ -25687,7 +25713,7 @@ packages:
|
|||
mute-stream: 0.0.8
|
||||
ora: 5.4.1
|
||||
run-async: 2.4.1
|
||||
rxjs: 7.5.4
|
||||
rxjs: 7.5.5
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
through: 2.3.8
|
||||
|
@ -26571,7 +26597,7 @@ packages:
|
|||
async: 0.9.2
|
||||
chalk: 2.4.2
|
||||
filelist: 1.0.2
|
||||
minimatch: 3.0.4
|
||||
minimatch: 3.1.2
|
||||
|
||||
/jest-allure/0.1.3:
|
||||
resolution: {integrity: sha512-EkO3LmkPx/a4VDg81JKtdy6kFXI0D1rHRIJ5Sa9MZaGtFYpgiCJFa6XwTgIySaVN+3+QBbIt1558CEkIW7FKFA==}
|
||||
|
@ -29172,7 +29198,7 @@ packages:
|
|||
resolution: {integrity: sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
graceful-fs: 4.2.8
|
||||
graceful-fs: 4.2.9
|
||||
parse-json: 4.0.0
|
||||
pify: 4.0.1
|
||||
strip-bom: 3.0.0
|
||||
|
@ -29497,6 +29523,7 @@ packages:
|
|||
/lru-cache/7.4.0:
|
||||
resolution: {integrity: sha512-YOfuyWa/Ee+PXbDm40j9WXyJrzQUynVbgn4Km643UYcWNcrSfRkKL0WaiUcxcIbkXcVTgNpDqSnPXntWXT75cw==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Please update to latest patch version to fix memory leak https://github.com/isaacs/node-lru-cache/issues/227
|
||||
dev: true
|
||||
|
||||
/lru/3.1.0:
|
||||
|
@ -29807,7 +29834,7 @@ packages:
|
|||
commondir: 1.0.1
|
||||
deep-extend: 0.6.0
|
||||
ejs: 3.1.6
|
||||
globby: 11.0.4
|
||||
globby: 11.1.0
|
||||
isbinaryfile: 4.0.8
|
||||
mem-fs: 2.2.1
|
||||
minimatch: 3.1.2
|
||||
|
@ -31084,7 +31111,7 @@ packages:
|
|||
'@oclif/plugin-warn-if-update-available': 2.0.4
|
||||
aws-sdk: 2.1079.0
|
||||
concurrently: 7.0.0
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
find-yarn-workspace-root: 2.0.0
|
||||
fs-extra: 8.1.0
|
||||
github-slugger: 1.4.0
|
||||
|
@ -31380,7 +31407,7 @@ packages:
|
|||
resolution: {integrity: sha512-UJKdSzgd3KOnXXAtqN5+/eeHcvTn1hBkesEmElVgvO/NAYcxAvmjzIGmnNd3Tb/gRAvMBdNRFD4qAWdHxY6QXg==}
|
||||
engines: {node: '>=12.10.0'}
|
||||
dependencies:
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
p-queue: 6.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -33424,7 +33451,7 @@ packages:
|
|||
engines: {node: '>=8.0.0'}
|
||||
dependencies:
|
||||
chalk: 2.4.2
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
execa: 0.10.0
|
||||
fs-extra: 6.0.1
|
||||
get-stream: 5.2.0
|
||||
|
@ -35284,12 +35311,6 @@ packages:
|
|||
dependencies:
|
||||
tslib: 1.14.1
|
||||
|
||||
/rxjs/7.5.4:
|
||||
resolution: {integrity: sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==}
|
||||
dependencies:
|
||||
tslib: 2.3.1
|
||||
dev: true
|
||||
|
||||
/rxjs/7.5.5:
|
||||
resolution: {integrity: sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==}
|
||||
dependencies:
|
||||
|
@ -35870,7 +35891,7 @@ packages:
|
|||
engines: {node: '>= 10'}
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
socks: 2.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -37720,6 +37741,37 @@ packages:
|
|||
webpack: 5.70.0
|
||||
dev: true
|
||||
|
||||
/ts-node/10.5.0_506ca6ef959d35afcce359030b1bc9ff:
|
||||
resolution: {integrity: sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@swc/core': '>=1.2.50'
|
||||
'@swc/wasm': '>=1.2.50'
|
||||
'@types/node': '*'
|
||||
typescript: '>=2.7'
|
||||
peerDependenciesMeta:
|
||||
'@swc/core':
|
||||
optional: true
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.7.0
|
||||
'@tsconfig/node10': 1.0.8
|
||||
'@tsconfig/node12': 1.0.9
|
||||
'@tsconfig/node14': 1.0.1
|
||||
'@tsconfig/node16': 1.0.2
|
||||
'@types/node': 16.10.3
|
||||
acorn: 8.7.0
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.2
|
||||
make-error: 1.3.6
|
||||
typescript: 4.6.2
|
||||
v8-compile-cache-lib: 3.0.0
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
|
||||
/ts-node/10.5.0_e0d88945dfc7787883e9c330c9196a96:
|
||||
resolution: {integrity: sha512-6kEJKwVxAJ35W4akuiysfKwKmjkbYxwQMTBaAxo9KKAx/Yd26mPUyhGz3ji+EsJoAgrLqVsYHNuuYwQe22lbtw==}
|
||||
hasBin: true
|
||||
|
@ -37740,7 +37792,7 @@ packages:
|
|||
'@tsconfig/node14': 1.0.1
|
||||
'@tsconfig/node16': 1.0.2
|
||||
'@types/node': 16.10.3
|
||||
acorn: 8.5.0
|
||||
acorn: 8.7.0
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
|
@ -39823,13 +39875,13 @@ packages:
|
|||
cli-table: 0.3.11
|
||||
commander: 7.1.0
|
||||
dateformat: 4.6.3
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
diff: 5.0.0
|
||||
error: 10.4.0
|
||||
escape-string-regexp: 4.0.0
|
||||
execa: 5.1.1
|
||||
find-up: 5.0.0
|
||||
globby: 11.0.4
|
||||
globby: 11.1.0
|
||||
grouped-queue: 2.0.0
|
||||
inquirer: 8.2.0
|
||||
is-scoped: 2.1.0
|
||||
|
@ -39837,7 +39889,7 @@ packages:
|
|||
log-symbols: 4.1.0
|
||||
mem-fs: 2.2.1
|
||||
mem-fs-editor: 9.4.0_mem-fs@2.2.1
|
||||
minimatch: 3.0.4
|
||||
minimatch: 3.1.2
|
||||
npmlog: 5.0.1
|
||||
p-queue: 6.6.2
|
||||
p-transform: 1.3.0
|
||||
|
@ -39865,7 +39917,7 @@ packages:
|
|||
dependencies:
|
||||
chalk: 4.1.2
|
||||
dargs: 7.0.0
|
||||
debug: 4.3.3
|
||||
debug: 4.3.4
|
||||
execa: 4.1.0
|
||||
github-username: 6.0.0
|
||||
lodash: 4.17.21
|
||||
|
|
|
@ -2,3 +2,4 @@ packages:
|
|||
- 'packages/js/**'
|
||||
- 'plugins/**'
|
||||
- 'tools/monorepo-merge'
|
||||
- 'tools/code-analyzer'
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/dist
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"ignorePatterns": [ "dist/", "node_modules/" ],
|
||||
"plugins": [ "@typescript-eslint/eslint-plugin" ],
|
||||
"extends": [ "plugin:@wordpress/eslint-plugin/recommended-with-formatting" ],
|
||||
"rules": {
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
/oclif.manifest.json
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const oclif = require('@oclif/core')
|
||||
|
||||
const path = require('path')
|
||||
const project = path.join(__dirname, '..', 'tsconfig.json')
|
||||
|
||||
// In dev mode -> use ts-node and dev plugins
|
||||
process.env.NODE_ENV = 'development'
|
||||
|
||||
require('ts-node').register({project})
|
||||
|
||||
// In dev mode, always show stack traces
|
||||
oclif.settings.debug = true;
|
||||
|
||||
// Start the CLI
|
||||
oclif.run().then(oclif.flush).catch(oclif.Errors.handle)
|
|
@ -0,0 +1,3 @@
|
|||
@echo off
|
||||
|
||||
node "%~dp0\dev" %*
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const oclif = require('@oclif/core')
|
||||
|
||||
oclif.run().then(require('@oclif/core/flush')).catch(require('@oclif/core/handle'))
|
|
@ -0,0 +1,3 @@
|
|||
@echo off
|
||||
|
||||
node "%~dp0\run" %*
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"name": "code-analyzer",
|
||||
"version": "0.0.0",
|
||||
"description": "A tool to analyze code changes in WooCommerce Monorepo.",
|
||||
"author": "Automattic",
|
||||
"bin": {
|
||||
"code-analyzer": "./bin/run"
|
||||
},
|
||||
"homepage": "https://github.com/woocommerce/woocommerce",
|
||||
"license": "GPLv2",
|
||||
"main": "dist/index.js",
|
||||
"repository": "woocommerce/woocommerce",
|
||||
"files": [
|
||||
"/bin",
|
||||
"/dist",
|
||||
"/npm-shrinkwrap.json",
|
||||
"/oclif.manifest.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"@oclif/core": "^1",
|
||||
"@oclif/plugin-help": "^5",
|
||||
"@oclif/plugin-plugins": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.9.4",
|
||||
"eslint": "^7.32.0",
|
||||
"globby": "^11",
|
||||
"oclif": "^2",
|
||||
"shx": "^0.3.3",
|
||||
"ts-node": "^10.2.1",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.4.3"
|
||||
},
|
||||
"oclif": {
|
||||
"bin": "code-analyzer",
|
||||
"dirname": "code-analyzer",
|
||||
"commands": "./dist/commands",
|
||||
"plugins": [
|
||||
"@oclif/plugin-help",
|
||||
"@oclif/plugin-plugins"
|
||||
],
|
||||
"topicSeparator": " ",
|
||||
"topics": {
|
||||
"analyzer": {
|
||||
"description": "Analyzes code changes in the monorepo."
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "shx rm -rf dist && tsc -b",
|
||||
"lint": "eslint . --ext .ts --config .eslintrc",
|
||||
"postpack": "shx rm -f oclif.manifest.json",
|
||||
"posttest": "pnpm lint",
|
||||
"prepack": "pnpm build && oclif manifest"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"types": "dist/index.d.ts"
|
||||
}
|
|
@ -0,0 +1,553 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { CliUx, Command, Flags } from '@oclif/core';
|
||||
import { tmpdir } from 'os';
|
||||
import { join } from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { MONOREPO_ROOT } from '../../const';
|
||||
|
||||
/**
|
||||
* Analyzer class
|
||||
*/
|
||||
export default class Analyzer extends Command {
|
||||
/**
|
||||
* CLI description
|
||||
*/
|
||||
static description = 'Analyze code changes in WooCommerce Monorepo.';
|
||||
|
||||
/**
|
||||
* CLI arguments
|
||||
*/
|
||||
static args = [
|
||||
{
|
||||
name: 'compare',
|
||||
description:
|
||||
'GitHub branch or commit hash to compare against the base branch/commit.',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* CLI flags.
|
||||
*/
|
||||
static flags = {
|
||||
base: Flags.string( {
|
||||
char: 'b',
|
||||
description: 'GitHub base branch or commit hash.',
|
||||
default: 'trunk',
|
||||
} ),
|
||||
output: Flags.string( {
|
||||
char: 'o',
|
||||
description: 'Output styling.',
|
||||
options: [ 'console', 'github' ],
|
||||
default: 'console',
|
||||
} ),
|
||||
source: Flags.string( {
|
||||
char: 's',
|
||||
description: 'GitHub organization/repository.',
|
||||
default: 'woocommerce/woocommerce',
|
||||
} ),
|
||||
plugin: Flags.string( {
|
||||
char: 'p',
|
||||
description: 'Plugin to check for',
|
||||
options: [ 'core', 'admin', 'beta' ],
|
||||
default: 'core',
|
||||
} ),
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is called to execute the command
|
||||
*/
|
||||
async run(): Promise< void > {
|
||||
const { args, flags } = await this.parse( Analyzer );
|
||||
|
||||
await this.validateArgs( flags.source );
|
||||
|
||||
const patchContent = await this.getChanges(
|
||||
flags.source,
|
||||
args.compare,
|
||||
flags.base
|
||||
);
|
||||
|
||||
const pluginData = await this.getPluginData( flags.plugin );
|
||||
this.log( `${ pluginData[ 1 ] } Version: ${ pluginData[ 0 ] }` );
|
||||
|
||||
await this.scanChanges( patchContent, pluginData[ 0 ], flags.output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates all of the arguments to make sure
|
||||
*
|
||||
* @param {string} source The GitHub repository we are merging.
|
||||
*/
|
||||
private async validateArgs( source: string ): Promise< void > {
|
||||
// We only support pulling from GitHub so the format needs to match that.
|
||||
if ( ! source.match( /^[a-z0-9\-]+\/[a-z0-9\-]+$/ ) ) {
|
||||
this.error(
|
||||
'The "source" argument must be in "organization/repository" format'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin data
|
||||
*
|
||||
* @param {string} plugin Plugin slug.
|
||||
* @return {Promise<string[]>} Promise.
|
||||
*/
|
||||
private async getPluginData( plugin: string ): Promise< string[] > {
|
||||
/**
|
||||
* List of plugins from our monorepo.
|
||||
*/
|
||||
const plugins = <any>{
|
||||
core: {
|
||||
name: 'WooCommerce',
|
||||
mainFile: join(
|
||||
MONOREPO_ROOT,
|
||||
'plugins',
|
||||
'woocommerce',
|
||||
'woocommerce.php'
|
||||
),
|
||||
},
|
||||
admin: {
|
||||
name: 'WooCommerce Admin',
|
||||
mainFile: join(
|
||||
MONOREPO_ROOT,
|
||||
'plugins',
|
||||
'woocommerce-admin',
|
||||
'woocommerce-admin.php'
|
||||
),
|
||||
},
|
||||
beta: {
|
||||
name: 'WooCommerce Beta Tester',
|
||||
mainFile: join(
|
||||
MONOREPO_ROOT,
|
||||
'plugins',
|
||||
'woocommerce-beta-tester',
|
||||
'woocommerce-beta-tester.php'
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
const pluginData = plugins[ plugin ];
|
||||
|
||||
CliUx.ux.action.start( `Getting ${ pluginData.name } version` );
|
||||
|
||||
const content = readFileSync( pluginData.mainFile ).toString();
|
||||
const rawVer = content.match( /^\s+\*\s+Version:\s+(.*)/m );
|
||||
|
||||
if ( ! rawVer ) {
|
||||
this.error( 'Failed to find plugin version!' );
|
||||
}
|
||||
const version = rawVer[ 1 ].replace( /\-.*/, '' );
|
||||
|
||||
CliUx.ux.action.stop();
|
||||
|
||||
return [ version, pluginData.name, pluginData.mainFile ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch branches from origin.
|
||||
*
|
||||
* @param {string} branch branch/commit hash.
|
||||
* @return {Promise<boolean>} Promise.
|
||||
*/
|
||||
private async fetchBranch( branch: string ): Promise< boolean > {
|
||||
CliUx.ux.action.start( `Fetching ${ branch }` );
|
||||
const branches = execSync( 'git branch', {
|
||||
encoding: 'utf-8',
|
||||
} );
|
||||
|
||||
const branchExistsLocally = branches.includes( branch );
|
||||
|
||||
if ( branchExistsLocally ) {
|
||||
CliUx.ux.action.stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
// Fetch branch.
|
||||
execSync( `git fetch origin ${ branch }` );
|
||||
// Create branch.
|
||||
execSync( `git branch ${ branch } origin/${ branch }` );
|
||||
} catch ( e ) {
|
||||
this.error( `Unable to fetch ${ branch }` );
|
||||
}
|
||||
|
||||
CliUx.ux.action.stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a patch file into the temp directory and return its contents
|
||||
*
|
||||
* @param {string} source The GitHub repository.
|
||||
* @param {string} compare Branch/commit hash to compare against the base.
|
||||
* @param {string} base Base branch/commit hash.
|
||||
* @return {Promise<string>} Promise.
|
||||
*/
|
||||
private async getChanges(
|
||||
source: string,
|
||||
compare: string,
|
||||
base: string
|
||||
): Promise< string > {
|
||||
const filename = `${ source }-${ base }-${ compare }.patch`.replace(
|
||||
/\//g,
|
||||
'-'
|
||||
);
|
||||
const filepath = join( tmpdir(), filename );
|
||||
|
||||
await this.fetchBranch( base );
|
||||
await this.fetchBranch( compare );
|
||||
|
||||
CliUx.ux.action.start( 'Generating patch for ' + compare );
|
||||
|
||||
try {
|
||||
const diffCommand = `git diff ${ base }...${ compare } > ${ filepath }`;
|
||||
execSync( diffCommand );
|
||||
} catch ( e ) {
|
||||
this.error(
|
||||
'Unable to create diff. Check that git origin, base branch, and compare branch all exist.'
|
||||
);
|
||||
}
|
||||
|
||||
const content = readFileSync( filepath ).toString();
|
||||
|
||||
CliUx.ux.action.stop();
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get patches
|
||||
*
|
||||
* @param {string} content Patch content.
|
||||
* @param {RegExp} regex Regex to find specific patches.
|
||||
* @return {Promise<string[]>} Promise.
|
||||
*/
|
||||
private async getPatches(
|
||||
content: string,
|
||||
regex: RegExp
|
||||
): Promise< string[] > {
|
||||
const patches = content.split( 'diff --git ' );
|
||||
const changes: string[] = [];
|
||||
|
||||
for ( const p in patches ) {
|
||||
const patch = patches[ p ];
|
||||
const id = patch.match( regex );
|
||||
|
||||
if ( id ) {
|
||||
changes.push( patch );
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename from patch
|
||||
*
|
||||
* @param {string} str String to extract filename from.
|
||||
* @return {Promise<string>} Promise.
|
||||
*/
|
||||
private async getFilename( str: string ): Promise< string > {
|
||||
return str.replace( /^a(.*)\s.*/, '$1' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format version string for regex.
|
||||
*
|
||||
* @param {string} rawVersion Raw version number.
|
||||
* @return {Promise<string>} Promise.
|
||||
*/
|
||||
private async getVersionRegex( rawVersion: string ): Promise< string > {
|
||||
const version = rawVersion.replace( /\./g, '\\.' );
|
||||
|
||||
if ( rawVersion.endsWith( '.0' ) ) {
|
||||
return version + '|' + version.slice( 0, -3 ) + '\\n';
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan patches for changes in templates, hooks and database schema
|
||||
*
|
||||
* @param {string} content Patch content.
|
||||
* @param {string} version Current product version.
|
||||
* @param {string} output Output style.
|
||||
*/
|
||||
private async scanChanges(
|
||||
content: string,
|
||||
version: string,
|
||||
output: string
|
||||
): Promise< void > {
|
||||
const templates = await this.scanTemplates( content, version );
|
||||
const hooks = await this.scanHooks( content, version, output );
|
||||
// @todo: Scan for changes to database schema.
|
||||
|
||||
if ( templates.size ) {
|
||||
await this.printTemplateResults(
|
||||
templates,
|
||||
output,
|
||||
'TEMPLATE CHANGES'
|
||||
);
|
||||
} else {
|
||||
this.log( 'No template changes found' );
|
||||
}
|
||||
|
||||
if ( hooks.size ) {
|
||||
await this.printHookResults( hooks, output, 'HOOKS' );
|
||||
} else {
|
||||
this.log( 'No new hooks found' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print template results
|
||||
*
|
||||
* @param {Map<string, string[]>} data Raw data.
|
||||
* @param {string} output Output style.
|
||||
* @param {string} title Section title.
|
||||
*/
|
||||
private async printTemplateResults(
|
||||
data: Map< string, string[] >,
|
||||
output: string,
|
||||
title: string
|
||||
): Promise< void > {
|
||||
if ( output === 'github' ) {
|
||||
let opt = '\\n\\n### Template changes:';
|
||||
for ( const [ key, value ] of data ) {
|
||||
opt += `\\n* **file:** ${ key }`;
|
||||
opt += `\\n * ${ value[ 0 ].toUpperCase() }: ${ value[ 2 ] }`;
|
||||
this.log(
|
||||
`::${ value[ 0 ] } file=${ key },line=1,title=${ value[ 1 ] }::${ value[ 2 ] }`
|
||||
);
|
||||
}
|
||||
|
||||
this.log( `::set-output name=templates::${ opt }` );
|
||||
} else {
|
||||
this.log( `\n## ${ title }:` );
|
||||
for ( const [ key, value ] of data ) {
|
||||
this.log( 'FILE: ' + key );
|
||||
this.log(
|
||||
'---------------------------------------------------'
|
||||
);
|
||||
this.log(
|
||||
` ${ value[ 0 ].toUpperCase() } | ${ value[ 1 ] } | ${
|
||||
value[ 2 ]
|
||||
}`
|
||||
);
|
||||
this.log(
|
||||
'---------------------------------------------------'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print hook results
|
||||
*
|
||||
* @param {Map} data Raw data.
|
||||
* @param {string} output Output style.
|
||||
* @param {string} title Section title.
|
||||
*/
|
||||
private async printHookResults(
|
||||
data: Map< string, Map< string, string[] > >,
|
||||
output: string,
|
||||
title: string
|
||||
): Promise< void > {
|
||||
if ( output === 'github' ) {
|
||||
let opt = '\\n\\n### New hooks:';
|
||||
for ( const [ key, value ] of data ) {
|
||||
if ( value.size ) {
|
||||
opt += `\\n* **file:** ${ key }`;
|
||||
for ( const [ k, v ] of value ) {
|
||||
opt += `\\n * ${ v[ 0 ].toUpperCase() }: ${ v[ 2 ] }`;
|
||||
this.log(
|
||||
`::${ v[ 0 ] } file=${ key },line=1,title=${ v[ 1 ] } - ${ k }::${ v[ 2 ] }`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.log( `::set-output name=wphooks::${ opt }` );
|
||||
} else {
|
||||
this.log( `\n## ${ title }:` );
|
||||
for ( const [ key, value ] of data ) {
|
||||
if ( value.size ) {
|
||||
this.log( 'FILE: ' + key );
|
||||
this.log(
|
||||
'---------------------------------------------------'
|
||||
);
|
||||
for ( const [ k, v ] of value ) {
|
||||
this.log( 'HOOK: ' + k );
|
||||
this.log(
|
||||
'---------------------------------------------------'
|
||||
);
|
||||
this.log(
|
||||
` ${ v[ 0 ].toUpperCase() } | ${ v[ 1 ] } | ${
|
||||
v[ 2 ]
|
||||
}`
|
||||
);
|
||||
this.log(
|
||||
'---------------------------------------------------'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hook name.
|
||||
*
|
||||
* @param {string} name Raw hook name.
|
||||
* @return {Promise<string>} Promise.
|
||||
*/
|
||||
private async getHookName( name: string ): Promise< string > {
|
||||
if ( name.indexOf( ',' ) > -1 ) {
|
||||
name = name.substring( 0, name.indexOf( ',' ) );
|
||||
}
|
||||
|
||||
return name.replace( /(\'|\")/g, '' ).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan patches for changes in templates
|
||||
*
|
||||
* @param {string} content Patch content.
|
||||
* @param {string} version Current product version.
|
||||
* @return {Promise<Map<string, string[]>>} Promise.
|
||||
*/
|
||||
private async scanTemplates(
|
||||
content: string,
|
||||
version: string
|
||||
): Promise< Map< string, string[] > > {
|
||||
CliUx.ux.action.start( 'Scanning template changes' );
|
||||
|
||||
const report: Map< string, string[] > = new Map< string, string[] >();
|
||||
|
||||
if ( ! content.match( /diff --git a\/(.+)\/templates\/(.+)/g ) ) {
|
||||
CliUx.ux.action.stop();
|
||||
return report;
|
||||
}
|
||||
|
||||
const matchPatches = /^a\/(.+)\/templates\/(.+)/g;
|
||||
const title = 'Template change detected';
|
||||
const patches = await this.getPatches( content, matchPatches );
|
||||
const matchVersion = `^(\\+.+\\*.+)(@version)\\s+(${ version.replace(
|
||||
/\./g,
|
||||
'\\.'
|
||||
) }).*`;
|
||||
const versionRegex = new RegExp( matchVersion, 'g' );
|
||||
|
||||
for ( const p in patches ) {
|
||||
const patch = patches[ p ];
|
||||
const lines = patch.split( '\n' );
|
||||
const filepath = await this.getFilename( lines[ 0 ] );
|
||||
let code = 'warning';
|
||||
let message = 'This template may require a version bump!';
|
||||
|
||||
for ( const l in lines ) {
|
||||
const line = lines[ l ];
|
||||
|
||||
if ( line.match( versionRegex ) ) {
|
||||
code = 'notice';
|
||||
message = 'Version bump found';
|
||||
}
|
||||
}
|
||||
|
||||
if ( code === 'notice' && report.get( filepath ) ) {
|
||||
report.set( filepath, [ code, title, message ] );
|
||||
} else if ( ! report.get( filepath ) ) {
|
||||
report.set( filepath, [ code, title, message ] );
|
||||
}
|
||||
}
|
||||
|
||||
CliUx.ux.action.stop();
|
||||
return report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan patches for hooks
|
||||
*
|
||||
* @param {string} content Patch content.
|
||||
* @param {string} version Current product version.
|
||||
* @param {string} output Output style.
|
||||
* @return {Promise<Map<string, Map<string, string[]>>>} Promise.
|
||||
*/
|
||||
private async scanHooks(
|
||||
content: string,
|
||||
version: string,
|
||||
output: string
|
||||
): Promise< Map< string, Map< string, string[] > > > {
|
||||
CliUx.ux.action.start( 'Scanning for new hooks' );
|
||||
|
||||
const report: Map< string, Map< string, string[] > > = new Map<
|
||||
string,
|
||||
Map< string, string[] >
|
||||
>();
|
||||
|
||||
if ( ! content.match( /diff --git a\/(.+).php/g ) ) {
|
||||
CliUx.ux.action.stop();
|
||||
return report;
|
||||
}
|
||||
|
||||
const matchPatches = /^a\/(.+).php/g;
|
||||
const patches = await this.getPatches( content, matchPatches );
|
||||
const verRegEx = await this.getVersionRegex( version );
|
||||
const matchHooks = `@since\\s+(${ verRegEx })(.*?)(apply_filters|do_action)\\((\\s+)?(\\'|\\")(.*?)(\\'|\\")`;
|
||||
const newRegEx = new RegExp( matchHooks, 'gs' );
|
||||
|
||||
for ( const p in patches ) {
|
||||
const patch = patches[ p ];
|
||||
const results = patch.match( newRegEx );
|
||||
const hooksList: Map< string, string[] > = new Map<
|
||||
string,
|
||||
string[]
|
||||
>();
|
||||
|
||||
if ( ! results ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const lines = patch.split( '\n' );
|
||||
const filepath = await this.getFilename( lines[ 0 ] );
|
||||
|
||||
for ( const raw of results ) {
|
||||
// Extract hook name and type.
|
||||
const hookName = raw.match(
|
||||
/(.*)(do_action|apply_filters)\(\s+'(.*)'/
|
||||
);
|
||||
|
||||
if ( ! hookName ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const name = await this.getHookName( hookName[ 3 ] );
|
||||
const kind =
|
||||
hookName[ 2 ] === 'do_action' ? 'action' : 'filter';
|
||||
const CLIMessage = `\'${ name }\' introduced in ${ version }`;
|
||||
const GithubMessage = `\\'${ name }\\' introduced in ${ version }`;
|
||||
const message =
|
||||
output === 'github' ? GithubMessage : CLIMessage;
|
||||
const title = `New ${ kind } found`;
|
||||
|
||||
if ( ! hookName[ 2 ].startsWith( '-' ) ) {
|
||||
hooksList.set( name, [ 'NOTICE', title, message ] );
|
||||
}
|
||||
}
|
||||
|
||||
report.set( filepath, hooksList );
|
||||
}
|
||||
|
||||
CliUx.ux.action.stop();
|
||||
return report;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { dirname } from 'path';
|
||||
|
||||
// Escape from ./tools/monorepo-merge/src
|
||||
export const MONOREPO_ROOT = dirname( dirname( dirname( __dirname ) ) );
|
|
@ -0,0 +1 @@
|
|||
export { run } from '@oclif/core';
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"importHelpers": true,
|
||||
"module": "commonjs",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"target": "es2019"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue