Merge df38582da of vercel/turbo into canary

This commit is contained in:
Tobias Koppers 2023-03-13 14:23:28 +01:00
commit b98469c86b
12493 changed files with 764271 additions and 0 deletions

2
.alexignore Normal file
View file

@ -0,0 +1,2 @@
CODE_OF_CONDUCT.md
examples/

23
.alexrc Normal file
View file

@ -0,0 +1,23 @@
{
"allow": [
"attacks",
"color",
"dead",
"execute",
"executed",
"executes",
"execution",
"executions",
"failed",
"failure",
"failures",
"fire",
"fires",
"hook",
"hooks",
"host-hostess",
"invalid",
"remains",
"white"
]
}

25
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,25 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
# [Optional] Uncomment this section to install additional OS packages.
# These are required to run playwright properly
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends \
gconf-service libxext6 libxfixes3 libxi6 libxrandr2 \
libxrender1 libcairo2 libcups2 libdbus-1-3 libexpat1 \
libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 \
libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 \
libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 \
libxdamage1 libxss1 libxtst6 libappindicator1 libnss3 libasound2 \
libatk1.0-0 libc6 libdrm-dev libgbm-dev ca-certificates fonts-liberation lsb-release xdg-utils wget
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
# [Optional] Uncomment if you want to install more global node modules
# RUN su node -c "npm install -g <your-package-list-here>"
# Enable pnpm
RUN corepack enable pnpm

View file

@ -0,0 +1,55 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM node:${VARIANT}
# [Option] Install zsh
ARG INSTALL_ZSH="true"
# [Option] Upgrade OS packages to their latest versions
ARG UPGRADE_PACKAGES="true"
# Install needed packages, yarn, nvm and setup non-root user. Use a separate RUN statement to add your own dependencies.
ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
ARG NPM_GLOBAL=/usr/local/share/npm-global
ENV NVM_DIR=/usr/local/share/nvm
ENV NVM_SYMLINK_CURRENT=true \
PATH=${NPM_GLOBAL}/bin:${NVM_DIR}/current/bin:${PATH}
COPY library-scripts/*.sh library-scripts/*.env /tmp/library-scripts/
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# Remove imagemagick due to https://security-tracker.debian.org/tracker/CVE-2019-10131
&& apt-get purge -y imagemagick imagemagick-6-common \
# Install common packages, non-root user, update yarn and install nvm
&& bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \
# Install yarn, nvm
&& rm -rf /opt/yarn-* /usr/local/bin/yarn /usr/local/bin/yarnpkg \
&& bash /tmp/library-scripts/node-debian.sh "${NVM_DIR}" "none" "${USERNAME}" \
# Configure global npm install location, use group to adapt to UID/GID changes
&& if ! cat /etc/group | grep -e "^npm:" > /dev/null 2>&1; then groupadd -r npm; fi \
&& usermod -a -G npm ${USERNAME} \
&& umask 0002 \
&& mkdir -p ${NPM_GLOBAL} \
&& touch /usr/local/etc/npmrc \
&& chown ${USERNAME}:npm ${NPM_GLOBAL} /usr/local/etc/npmrc \
&& chmod g+s ${NPM_GLOBAL} \
&& npm config -g set prefix ${NPM_GLOBAL} \
&& sudo -u ${USERNAME} npm config -g set prefix ${NPM_GLOBAL} \
# Install eslint
&& su ${USERNAME} -c "umask 0002 && npm install -g eslint" \
&& npm cache clean --force > /dev/null 2>&1 \
# Install python-is-python3 on bullseye to prevent node-gyp regressions
&& . /etc/os-release \
&& if [ "${VERSION_CODENAME}" = "bullseye" ]; then apt-get -y install --no-install-recommends python-is-python3; fi \
# Clean up
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /root/.gnupg /tmp/library-scripts
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
# [Optional] Uncomment if you want to install more global node modules
# RUN su node -c "npm install -g <your-package-list-here>""

View file

@ -0,0 +1,38 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.0/containers/javascript-node
{
"name": "Next.js Dev Container",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local arm64/Apple Silicon.
"args": {
"VARIANT": "16-bullseye"
}
},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": ["dbaeumer.vscode-eslint"]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node",
"features": {
// For some reason "git" or "rust" doesn't work
"ghcr.io/devcontainers/features/git:1": "os-provided",
"ghcr.io/devcontainers/features/rust:1": "latest"
// Github latest can't be installed due to GPG issues: https://github.com/cli/cli/discussions/6222
// "github-cli": "latest",
},
"remoteEnv": {
"DISPLAY": ":0"
}
}

40
.eslintignore Normal file
View file

@ -0,0 +1,40 @@
node_modules
**/.next/**
**/_next/**
**/dist/**
e2e-tests/**
examples/with-eslint/**
examples/with-typescript-eslint-jest/**
examples/with-kea/**
examples/with-custom-babel-config/**
examples/with-flow/**
examples/with-jest/**
examples/with-mobx-state-tree/**
examples/with-mobx/**
examples/with-tigris/db/models/todoItems.ts
packages/next/src/bundles/webpack/packages/*.runtime.js
packages/next/src/bundles/webpack/packages/lazy-compilation-*.js
packages/next/src/compiled/**/*
packages/react-refresh-utils/**/*.js
packages/react-dev-overlay/lib/**
**/__tmp__/**
.github/actions/next-stats-action/.work
.github/actions/issue-validator/index.mjs
packages/next-codemod/transforms/__testfixtures__/**/*
packages/next-codemod/transforms/__tests__/**/*
packages/next-codemod/**/*.js
packages/next-codemod/**/*.d.ts
packages/next-env/**/*.d.ts
packages/create-next-app/templates/**
test/integration/eslint/**
test/integration/script-loader/**/*
test/development/basic/legacy-decorators/**/*
test/production/emit-decorator-metadata/**/*.js
test/e2e/app-dir/rsc-errors/app/swc/use-client/page.js
test-timings.json
packages/next-swc/crates/**
bench/nested-deps/pages/**
bench/nested-deps/components/**
packages/next-bundle-analyzer/index.d.ts
examples/with-typescript-graphql/lib/gql/
test/development/basic/hmr/components/parse-error.js

350
.eslintrc.json Normal file
View file

@ -0,0 +1,350 @@
{
"root": true,
"parser": "@babel/eslint-parser",
"plugins": ["react", "react-hooks", "jest", "import", "jsdoc"],
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true
},
"parserOptions": {
"requireConfigFile": false,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
},
"babelOptions": {
"presets": ["next/babel"],
"caller": {
// Eslint supports top level await when a parser for it is included. We enable the parser by default for Babel.
"supportsTopLevelAwait": true
}
}
},
"settings": {
"react": {
"version": "detect"
},
"import/internal-regex": "^next/"
},
"overrides": [
{
"files": ["test/**/*.js", "test/**/*.ts", "**/*.test.ts"],
"extends": ["plugin:jest/recommended"],
"rules": {
"jest/expect-expect": "off",
"jest/no-disabled-tests": "off",
"jest/no-conditional-expect": "off",
"jest/valid-title": "off",
"jest/no-interpolation-in-snapshots": "off",
"jest/no-export": "off"
}
},
{ "files": ["**/__tests__/**"], "env": { "jest": true } },
{
"files": ["**/*.ts", "**/*.tsx"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
},
"warnOnUnsupportedTypeScriptVersion": false
},
"plugins": ["@typescript-eslint"],
"rules": {
// Already handled by TS
"no-dupe-class-members": "off",
"no-undef": "off",
// Add TypeScript specific rules (and turn off ESLint equivalents)
"@typescript-eslint/consistent-type-assertions": "warn",
"no-array-constructor": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-namespace": "error",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": [
"warn",
{
"functions": true,
"classes": true,
"variables": true,
"enums": true,
"typedefs": true
}
],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"args": "none",
"ignoreRestSiblings": true
}
],
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": "warn",
"@typescript-eslint/prefer-literal-enum-member": "error",
"@typescript-eslint/prefer-namespace-keyword": "error"
},
"overrides": [
{
"files": ["packages/**"],
"rules": {
"jsdoc/no-types": "error",
"jsdoc/no-undefined-types": "error"
}
}
]
},
{
"files": [
"test/**/*",
"examples/**/*",
"packages/create-next-app/templates/**/*"
],
"rules": { "react/react-in-jsx-scope": "off" }
},
{
"files": ["examples/**/*"],
"rules": {
"@typescript-eslint/no-use-before-define": [
"error",
{
"functions": true,
"classes": true,
"variables": true,
"enums": true,
"typedefs": true
}
],
"import/no-anonymous-default-export": [
"error",
{
// React components:
"allowArrowFunction": false,
"allowAnonymousClass": false,
"allowAnonymousFunction": false,
// Non-React stuff:
"allowArray": true,
"allowCallExpression": true,
"allowLiteral": true,
"allowObject": true
}
]
}
},
{
"files": ["packages/**"],
"rules": {
"no-shadow": ["warn", { "builtinGlobals": false }],
"import/no-extraneous-dependencies": [
"error",
{ "devDependencies": false }
]
}
},
{
"files": ["packages/**/*.tsx", "packages/**/*.ts"],
"rules": {
// Note: you must disable the base rule as it can report incorrect errors
"no-shadow": "off",
"@typescript-eslint/no-shadow": ["warn", { "builtinGlobals": false }],
"@typescript-eslint/no-unused-vars": [
"warn",
{
"args": "all",
"argsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
]
}
},
{
"files": [
"packages/eslint-plugin-next/**/*.js",
"test/unit/eslint-plugin-next/**/*.test.ts"
],
"extends": ["plugin:eslint-plugin/recommended"],
"parserOptions": {
"sourceType": "script"
},
"rules": {
"eslint-plugin/prefer-replace-text": "error",
"eslint-plugin/report-message-format": [
"error",
".+\\. See: https://nextjs.org/docs/messages/[a-z\\-]+$"
],
"eslint-plugin/require-meta-docs-description": [
"error",
{
"pattern": ".+"
}
],
"eslint-plugin/require-meta-docs-url": "error"
}
}
],
"rules": {
"array-callback-return": "warn",
"default-case": ["warn", { "commentPattern": "^no default$" }],
"dot-location": ["warn", "property"],
"eqeqeq": ["warn", "smart"],
"new-parens": "warn",
"no-array-constructor": "warn",
"no-caller": "warn",
"no-cond-assign": ["warn", "except-parens"],
"no-const-assign": "warn",
"no-control-regex": "warn",
"no-delete-var": "warn",
"no-dupe-args": "warn",
"no-dupe-class-members": "warn",
"no-dupe-keys": "warn",
"no-duplicate-case": "warn",
"no-empty-character-class": "warn",
"no-empty-pattern": "warn",
"no-eval": "warn",
"no-ex-assign": "warn",
"no-extend-native": "warn",
"no-extra-bind": "warn",
"no-extra-label": "warn",
"no-fallthrough": "warn",
"no-func-assign": "warn",
"no-implied-eval": "warn",
"no-invalid-regexp": "warn",
"no-iterator": "warn",
"no-label-var": "warn",
"no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }],
"no-lone-blocks": "warn",
"no-loop-func": "warn",
"no-mixed-operators": [
"warn",
{
"groups": [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": false
}
],
"no-multi-str": "warn",
"no-native-reassign": "warn",
"no-negated-in-lhs": "warn",
"no-new-func": "warn",
"no-new-object": "warn",
"no-new-symbol": "warn",
"no-new-wrappers": "warn",
"no-obj-calls": "warn",
"no-octal": "warn",
"no-octal-escape": "warn",
"no-regex-spaces": "warn",
"no-restricted-syntax": [
"warn",
"WithStatement",
{
"message": "substr() is deprecated, use slice() or substring() instead",
"selector": "MemberExpression > Identifier[name='substr']"
}
],
"no-script-url": "warn",
"no-self-assign": "warn",
"no-self-compare": "warn",
"no-sequences": "warn",
"no-shadow-restricted-names": "warn",
"no-sparse-arrays": "warn",
"no-template-curly-in-string": "error",
"no-this-before-super": "warn",
"no-throw-literal": "warn",
"no-undef": "error",
"no-unexpected-multiline": "warn",
"no-unreachable": "warn",
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-labels": "warn",
"no-unused-vars": [
"warn",
{
"args": "none",
"ignoreRestSiblings": true
}
],
"no-use-before-define": [
"warn",
{
"functions": false,
"classes": false,
"variables": false
}
],
"no-useless-computed-key": "warn",
"no-useless-concat": "warn",
"no-useless-constructor": "warn",
"no-useless-escape": "warn",
"no-useless-rename": [
"warn",
{
"ignoreDestructuring": false,
"ignoreImport": false,
"ignoreExport": false
}
],
"no-with": "warn",
"no-whitespace-before-property": "warn",
"react-hooks/exhaustive-deps": "warn",
"require-yield": "warn",
"rest-spread-spacing": ["warn", "never"],
"strict": ["warn", "never"],
"unicode-bom": ["warn", "never"],
"use-isnan": "warn",
"valid-typeof": "warn",
"getter-return": "warn",
"react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }],
"react/jsx-no-comment-textnodes": "warn",
"react/jsx-no-duplicate-props": "warn",
"react/jsx-no-target-blank": "warn",
"react/jsx-no-undef": "error",
"react/jsx-pascal-case": [
"warn",
{
"allowAllCaps": true,
"ignore": []
}
],
"react/jsx-uses-react": "warn",
"react/jsx-uses-vars": "warn",
"react/no-danger-with-children": "warn",
"react/no-deprecated": "warn",
"react/no-direct-mutation-state": "warn",
"react/no-is-mounted": "warn",
"react/no-typos": "error",
"react/react-in-jsx-scope": "error",
"react/require-render-return": "error",
"react/style-prop-object": "warn",
"react-hooks/rules-of-hooks": "error",
// "@typescript-eslint/non-nullable-type-assertion-style": "warn",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/no-redeclare": [
"warn",
{ "builtinGlobals": false, "ignoreDeclarationMerge": true }
]
}
}

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
packages/next/bundles/** -text
packages/next/compiled/** -text

19
.github/.kodiak.toml vendored Normal file
View file

@ -0,0 +1,19 @@
# .kodiak.toml
version = 1
[merge]
automerge_label = "ready to land"
require_automerge_label = false
method = "squash"
delete_branch_on_merge = true
optimistic_updates = true
prioritize_ready_to_merge = true
notify_on_conflict = false
[merge.message]
title = "pull_request_title"
body = "pull_request_body"
include_coauthors= true
include_pr_number = true
body_type = "markdown"
strip_html_comments = true

24
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1,24 @@
# Learn how to add code owners here:
# https://help.github.com/en/articles/about-code-owners
* @timneutkens @ijjk @shuding @huozhi @feedthejim
/.github/ @timneutkens @ijjk @shuding @styfle @huozhi @padmaia @balazsorban44 @jankaifer
/docs/ @timneutkens @ijjk @shuding @styfle @huozhi @padmaia @leerob @balazsorban44 @jankaifer
/errors/ @timneutkens @ijjk @shuding @styfle @huozhi @padmaia @leerob @balazsorban44 @jankaifer
/examples/ @timneutkens @ijjk @shuding @leerob @steven-tey @balazsorban44 @jankaifer
# SWC Build & Telemetry (@padmaia)
/packages/next/build/ @timneutkens @ijjk @shuding @padmaia @huozhi
/packages/next/telemetry/ @timneutkens @ijjk @shuding @padmaia
/packages/next-swc/ @timneutkens @ijjk @shuding @vercel/web-tooling
/packages/next/build/swc/ @timneutkens @ijjk @shuding @vercel/web-tooling
# Image Component (@styfle)
/**/*image* @timneutkens @ijjk @shuding @styfle
/**/*image*/** @timneutkens @ijjk @shuding @styfle
/packages/next/client/use-intersection.tsx @timneutkens @ijjk @shuding @styfle
/packages/next/server/lib/squoosh/ @timneutkens @ijjk @shuding @styfle
/packages/next/server/serve-static.ts @timneutkens @ijjk @shuding @styfle
/packages/next/server/config.ts @timneutkens @ijjk @shuding @styfle

20
.github/DISCUSSION_TEMPLATE/help.yml vendored Normal file
View file

@ -0,0 +1,20 @@
body:
- type: textarea
attributes:
label: Summary
description: What do you need help with?
validations:
required: true
- type: textarea
attributes:
label: Additional information
description: Any code snippets, error messages, or dependency details that may be related? (`next info`)
render: js
validations:
required: false
- type: input
attributes:
label: Example
description: A link to a minimal reproduction is helpful for collaborative debugging!
validations:
required: false

33
.github/DISCUSSION_TEMPLATE/ideas.yml vendored Normal file
View file

@ -0,0 +1,33 @@
body:
- type: textarea
attributes:
label: Goals
description: Short list of what the feature request aims to address?
value: |
1.
2.
3.
validations:
required: true
- type: textarea
attributes:
label: Non-Goals
description: Short list of what the feature request _does not_ aim to address?
value: |
1.
2.
3.
validations:
required: false
- type: textarea
attributes:
label: Background
description: Discuss prior art, why do you think this feature is needed? Are there current alternatives?
validations:
required: true
- type: textarea
attributes:
label: Proposal
description: How should this feature be implemented? Are you interested in contributing?
validations:
required: true

93
.github/ISSUE_TEMPLATE/1.bug_report.yml vendored Normal file
View file

@ -0,0 +1,93 @@
name: Bug Report
description: Create a bug report for the Next.js core
labels: ['template: bug']
body:
- type: markdown
attributes:
value: |
*Note:* If you leave out sections, the issue might be moved to the ["Help" section](https://github.com/vercel/next.js/discussions/categories/help).
[examples](https://github.com/vercel/next.js/tree/canary/examples) related issue should be reported using [this](https://github.com/vercel/next.js/issues/new?assignees=&labels=type%3A+example%2Ctemplate%3A+bug&template=2.example_bug_report.yml) issue template instead.
Feature requests should be opened as [discussions](https://github.com/vercel/next.js/discussions/new?category=ideas). [Read more](https://github.com/vercel/next.js/blob/canary/contributing/core/adding-features.md).
- type: checkboxes
attributes:
label: Verify canary release
description: '`next@canary` is the canary version of Next.js that ships daily. It includes all features and fixes that have not been released to the stable version yet. Think of canary as a public beta. Some issues may already be fixed in the canary version, so please verify that your issue reproduces before opening a new issue.'
options:
- label: I verified that the issue exists in the latest Next.js canary release
required: true
- type: textarea
attributes:
label: Provide environment information
description: Please run `next info` in the root directory of your project and paste the results. You might need to use `npx --no-install next info` if next is not in the current PATH.
render: bash
validations:
required: true
- type: dropdown
attributes:
label: Which area(s) of Next.js are affected? (leave empty if unsure)
multiple: true
options:
- 'App directory (appDir: true)'
- 'CLI (create-next-app)'
- 'Data fetching (gS(S)P, getInitialProps)'
- 'Dynamic imports (next/dynamic)'
- 'ESLint (eslint-config-next)'
- 'Font optimization (@next/font)'
- 'Image optimization (next/image, next/legacy/image)'
- 'Internationalization (i18n)'
- 'Jest (next/jest)'
- 'MDX (@next/mdx)'
- 'Metadata (metadata, generateMetadata, next/head, head.js)'
- 'Middleware / Edge (API routes, runtime)'
- 'Package manager (npm, pnpm, Yarn)'
- 'Routing (next/router, next/navigation, next/link)'
- 'Script optimization (next/script)'
- 'Standalone mode (output: "standalone")'
- 'Static HTML Export (next export)'
- 'SWC minifier (swcMinify: true)'
- 'SWC transpilation'
- 'Turbopack (--turbo)'
- 'TypeScript'
- type: input
attributes:
label: Link to the code that reproduces this issue
description: |
A link to a GitHub repository, a [CodeSandbox](https://codesandbox.io/p/sandbox/github/vercel/next.js/tree/canary/examples/reproduction-template) or a [StackBlitz](https://stackblitz.com/fork/github/vercel/next.js/tree/canary/examples/reproduction-template) minimal reproduction. Minimal reproductions should be created from our [bug report template with `npx create-next-app -e reproduction-template`](https://github.com/vercel/next.js/tree/canary/examples/reproduction-template) and should include only changes that contribute to the issue.
To report an App Router related issue, you can use these templates: [CodeSandbox](https://codesandbox.io/p/sandbox/github/vercel/next.js/tree/canary/examples/reproduction-template-app-dir), [StackBlitz](https://stackblitz.com/fork/github/vercel/next.js/tree/canary/examples/reproduction-template-app-dir) or [`npx create-next-app -e reproduction-template-app-dir`](https://github.com/vercel/next.js/tree/canary/examples/reproduction-template-app-dir)
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
validations:
required: true
- type: textarea
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: markdown
attributes:
value: Before posting the issue go through the steps you've written down to make sure the steps provided are detailed and clear.
- type: markdown
attributes:
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
- type: markdown
attributes:
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
- type: input
attributes:
label: Which browser are you using? (if relevant)
description: 'Please specify the exact version. For example: Chrome 100.0.4878.0'
- type: input
attributes:
label: How are you deploying your application? (if relevant)
description: 'For example: next start, next export, Vercel, Other platform'

View file

@ -0,0 +1,64 @@
name: Bug Report for Examples
description: Create a bug report for one of the Next.js examples
labels: ['area: examples']
body:
- type: markdown
attributes:
value: |
*Note:* If you leave out sections, the issue might be moved to the ["Help" section](https://github.com/vercel/next.js/discussions/categories/help).
Thanks for taking the time to file a bug report for [one of the examples](https://github.com/vercel/next.js/tree/canary/examples)! Please fill out this form as completely as possible.
- type: checkboxes
attributes:
label: Verify canary release
description: '`next@canary` is the canary version of Next.js that ships daily. It includes all features and fixes that have not been released to the stable version yet. Think of canary as a public beta. Some issues may already be fixed in the canary version, so please verify that your issue reproduces before opening a new issue.'
options:
- label: I verified that the issue exists in the latest Next.js canary release
required: true
- type: textarea
attributes:
label: Provide environment information
description: Please run `next info` in the root directory of your project and paste the results. You might need to use `npx --no-install next info` if next is not in the current PATH.
render: bash
validations:
required: true
- type: input
attributes:
label: Which example does this report relate to?
description: "See a complete list in the [examples folder](https://github.com/vercel/next.js/tree/canary/examples). For example: `with-styled-components`. Note: Examples not in the examples folder might be maintained by the example's library author. Check out their projects before opening the issue on Next.js"
validations:
required: true
- type: input
attributes:
label: What browser are you using? (if relevant)
description: 'Please specify the exact version. For example: Chrome 100.0.4878.0'
- type: input
attributes:
label: How are you deploying your application? (if relevant)
description: 'For example: next start, next export, Vercel, Other platform'
- type: textarea
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: To Reproduce
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the relevant example. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
validations:
required: true
- type: markdown
attributes:
value: Before posting the issue go through the steps you've written down to make sure the steps provided are detailed and clear.
- type: markdown
attributes:
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
- type: markdown
attributes:
value: Thanks in advance!

View file

@ -0,0 +1,24 @@
name: 'Docs Request for an Update or Improvement'
description: A request to update or improve Next.js documentation
title: 'Docs: '
labels:
- 'template: documentation'
body:
- type: textarea
attributes:
label: What is the improvement or update you wish to see?
description: 'Example: I would like to see more examples of how to use the `<Link>` component. Or, the `<Link>` component docs are missing information.'
validations:
required: true
- type: textarea
attributes:
label: Is there any context that might help us understand?
description: A clear description of any added context that might help us understand.
validations:
required: true
- type: input
attributes:
label: Does the docs page already exist? Please link to it.
description: 'Example: https://nextjs.org/docs/api-reference/next/link'
validations:
required: false

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Ask a question
url: https://github.com/vercel/next.js/discussions
about: Ask questions and discuss with other community members
- name: Feature request
url: https://github.com/vercel/next.js/discussions/new?category=ideas
about: Feature requests should be opened as discussions

View file

@ -0,0 +1,2 @@
!package-lock.json
lib/

View file

@ -0,0 +1,6 @@
name: 'Issue auto label'
description: 'vercel/next.js specific auto-labeling action'
author: 'Next.js team'
runs:
using: 'node16'
main: 'index.js'

9220
.github/actions/issue-on-comment/index.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,659 @@
@actions/core
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/github
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/http-client
MIT
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/auth-token
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/core
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/endpoint
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/graphql
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/plugin-paginate-rest
MIT
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/plugin-rest-endpoint-methods
MIT
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/request
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/request-error
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@vercel/ncc
MIT
Copyright 2018 ZEIT, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
before-after-hook
Apache-2.0
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Gregor Martynus and other contributors.
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
http://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.
deprecation
ISC
The ISC License
Copyright (c) Gregor Martynus and contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
is-plain-object
MIT
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
nextjs-project
The MIT License (MIT)
Copyright (c) 2023 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
node-fetch
MIT
The MIT License (MIT)
Copyright (c) 2016 David Frank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
once
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
tr46
MIT
tunnel
MIT
The MIT License (MIT)
Copyright (c) 2012 Koichi Kobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
universal-user-agent
ISC
# [ISC License](https://spdx.org/licenses/ISC)
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
uuid
MIT
The MIT License (MIT)
Copyright (c) 2010-2020 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
webidl-conversions
BSD-2-Clause
# The BSD 2-Clause License
Copyright (c) 2014, Domenic Denicola
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
whatwg-url
MIT
The MIT License (MIT)
Copyright (c) 20152016 Sebastian Mayr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
wrappy
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

478
.github/actions/issue-on-comment/package-lock.json generated vendored Normal file
View file

@ -0,0 +1,478 @@
{
"name": "issue-on-comment",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"@actions/core": "1.10.0",
"@actions/github": "5.1.1"
},
"devDependencies": {
"@types/node": "^18.11.0",
"@vercel/ncc": "0.34.0",
"typescript": "^4.4.4"
}
},
"node_modules/@actions/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/github": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
"integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
}
},
"node_modules/@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": {
"tunnel": "^0.0.6"
}
},
"node_modules/@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"dependencies": {
"@octokit/types": "^6.0.3"
}
},
"node_modules/@octokit/core": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"dependencies": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.3",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"dependencies": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"dependencies": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/openapi-types": {
"version": "12.10.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.10.1.tgz",
"integrity": "sha512-P+SukKanjFY0ZhsK6wSVnQmxTP2eVPPE8OPSNuxaMYtgVzwJZgfGdwlYjf4RlRU4vLEw4ts2fsE2icG4nZ5ddQ=="
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "2.21.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
"dependencies": {
"@octokit/types": "^6.40.0"
},
"peerDependencies": {
"@octokit/core": ">=2"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "5.16.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
"integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
"dependencies": {
"@octokit/types": "^6.39.0",
"deprecation": "^2.3.1"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"dependencies": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"dependencies": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"node_modules/@octokit/types": {
"version": "6.40.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.40.0.tgz",
"integrity": "sha512-MFZOU5r8SwgJWDMhrLUSvyJPtVsqA6VnbVI3TNbsmw+Jnvrktzvq2fYES/6RiJA/5Ykdwq4mJmtlYUfW7CGjmw==",
"dependencies": {
"@octokit/openapi-types": "^12.10.0"
}
},
"node_modules/@types/node": {
"version": "18.11.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
"integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
"dev": true
},
"node_modules/@vercel/ncc": {
"version": "0.34.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A==",
"dev": true,
"bin": {
"ncc": "dist/ncc/cli.js"
}
},
"node_modules/before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
},
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/typescript": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
},
"dependencies": {
"@actions/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"requires": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"@actions/github": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
"integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
"requires": {
"@actions/http-client": "^2.0.1",
"@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
}
},
"@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": {
"tunnel": "^0.0.6"
}
},
"@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"requires": {
"@octokit/types": "^6.0.3"
}
},
"@octokit/core": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"requires": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.3",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"requires": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"requires": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"version": "12.10.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.10.1.tgz",
"integrity": "sha512-P+SukKanjFY0ZhsK6wSVnQmxTP2eVPPE8OPSNuxaMYtgVzwJZgfGdwlYjf4RlRU4vLEw4ts2fsE2icG4nZ5ddQ=="
},
"@octokit/plugin-paginate-rest": {
"version": "2.21.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
"requires": {
"@octokit/types": "^6.40.0"
}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "5.16.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
"integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
"requires": {
"@octokit/types": "^6.39.0",
"deprecation": "^2.3.1"
}
},
"@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"requires": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"requires": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/types": {
"version": "6.40.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.40.0.tgz",
"integrity": "sha512-MFZOU5r8SwgJWDMhrLUSvyJPtVsqA6VnbVI3TNbsmw+Jnvrktzvq2fYES/6RiJA/5Ykdwq4mJmtlYUfW7CGjmw==",
"requires": {
"@octokit/openapi-types": "^12.10.0"
}
},
"@types/node": {
"version": "18.11.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
"integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
"dev": true
},
"@vercel/ncc": {
"version": "0.34.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A==",
"dev": true
},
"before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
},
"deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
},
"node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"typescript": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
"dev": true
},
"universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
}
}

View file

@ -0,0 +1,22 @@
{
"private": true,
"exports": "./index.js",
"files": [
"src"
],
"scripts": {
"types": "tsc",
"pack": "ncc -m -o . build lib/index.js --license licenses.txt",
"build": "npm run types && npm run pack"
},
"devDependencies": {
"@types/node": "^18.11.0",
"@vercel/ncc": "0.34.0",
"typescript": "^4.4.4"
},
"dependencies": {
"@actions/core": "1.10.0",
"@actions/github": "5.1.1"
},
"packageManager": "npm@9.2.0"
}

View file

@ -0,0 +1,45 @@
import * as github from '@actions/github'
import * as core from '@actions/core'
const LABELS = {
VERIFY_CANARY: 'please verify canary',
ADD_REPRODUCTION: 'please add a complete reproduction',
NEEDS_TRIAGE: 'type: needs triage',
}
const labelsRequireUserInput = [LABELS.VERIFY_CANARY, LABELS.ADD_REPRODUCTION]
function assertNotNullable<T>(value: T): asserts value is NonNullable<T> {
if (value === undefined || value === null)
throw new Error('Unexpected nullable value')
}
async function run() {
try {
const { payload, repo } = github.context
const { issue, comment } = payload
assertNotNullable(issue)
assertNotNullable(comment)
if (!process.env.GITHUB_TOKEN) return
const client = github.getOctokit(process.env.GITHUB_TOKEN).rest
const issueCommon = { ...repo, issue_number: issue.number }
const issueLabels: string[] = issue.labels.map((label: any) => label.name)
if (labelsRequireUserInput.some((label) => issueLabels.includes(label))) {
if (comment.user.type !== 'Bot') {
client.issues.addLabels({
...issueCommon,
labels: [LABELS.NEEDS_TRIAGE],
})
}
}
} catch (error: any) {
core.setFailed(error.message)
}
}
run()

View file

@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"outDir": "./lib",
"rootDir": "./src",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"typeRoots": ["./node_modules/@types"]
},
"exclude": ["node_modules", "../../../node_modules"]
}

View file

@ -0,0 +1,2 @@
!dist
!package-lock.json

View file

@ -0,0 +1,42 @@
Please verify that your issue can be recreated with `next@canary`.
### **Why was this issue marked with the `please verify canary` label?**
We noticed the provided reproduction was using an older version of Next.js, instead of `canary`.
The canary version of Next.js ships daily and includes all features and fixes that have not been released to the stable version yet. You can think of canary as a _public beta_. Some issues may already be fixed in the canary version, so please verify that your issue reproduces by running `npm install next@canary` and test it in your project, using your reproduction steps.
If the issue does not reproduce with the `canary` version, then it has already been fixed and this issue can be closed.
### **How can I quickly verify if my issue has been fixed in `canary`?**
The safest way is to install `next@canary` in your project and test it, but you can also search through [closed Next.js issues](https://github.com/vercel/next.js/issues?q=is%3Aissue+is%3Aclosed) for duplicates or check the [Next.js releases](https://github.com/vercel/next.js/releases). You can also use the GitHub [template](https://github.com/vercel/next.js/tree/canary/examples/reproduction-template) (preferred), or the [CodeSandbox](https://codesandbox.io/s/github/vercel/next.js/tree/canary/examples/reproduction-template) or [StackBlitz](https://stackblitz.com/fork/github/vercel/next.js/tree/canary/examples/reproduction-template) templates to create a reproduction with `canary` from scratch.
### **My issue has been open for a long time, why do I need to verify `canary` now?**
Next.js does not backport bug fixes to older versions of Next.js. Instead, we are trying to introduce only a minimal amount of breaking changes between major releases.
### **What happens if I don't verify against the canary version of Next.js?**
An issue with the `please verify canary` that receives no meaningful activity (e.g. new comments that acknowledge verification against `canary`) will be automatically closed and locked after 30 days.
If your issue has not been resolved in that time and it has been closed/locked, please open a new issue, with the required reproduction, using `next@canary`.
### **I did not open this issue, but it is relevant to me, what can I do to help?**
Anyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps. Furthermore, you can upvote the issue using the :+1: reaction on the topmost comment (please **do not** comment "I have the same issue" without reproduction steps). Then, we can sort issues by votes to prioritize.
### **I think my reproduction is good enough, why aren't you looking into it quicker?**
We look into every Next.js issue and constantly monitor open issues for new comments.
However, sometimes we might miss one or two due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.
Upvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.
### **Useful Resources**
- [How to Contribute to Open Source (Next.js)](https://www.youtube.com/watch?v=cuoNzXFLitc)
- [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve)
- [Reporting a Next.js bug](https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml)
- [Next.js Triaging issues](https://github.com/vercel/next.js/blob/canary/contributing/repository/triaging.md)

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,659 @@
@actions/core
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/github
MIT
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@actions/http-client
MIT
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/auth-token
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/core
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/endpoint
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/graphql
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/plugin-paginate-rest
MIT
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/plugin-rest-endpoint-methods
MIT
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@octokit/request
MIT
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@octokit/request-error
MIT
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@vercel/ncc
MIT
Copyright 2018 ZEIT, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
before-after-hook
Apache-2.0
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Gregor Martynus and other contributors.
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
http://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.
deprecation
ISC
The ISC License
Copyright (c) Gregor Martynus and contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
is-plain-object
MIT
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
nextjs-project
The MIT License (MIT)
Copyright (c) 2022 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
node-fetch
MIT
The MIT License (MIT)
Copyright (c) 2016 David Frank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
once
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
tr46
MIT
tunnel
MIT
The MIT License (MIT)
Copyright (c) 2012 Koichi Kobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
universal-user-agent
ISC
# [ISC License](https://spdx.org/licenses/ISC)
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
uuid
MIT
The MIT License (MIT)
Copyright (c) 2010-2020 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
webidl-conversions
BSD-2-Clause
# The BSD 2-Clause License
Copyright (c) 2014, Domenic Denicola
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
whatwg-url
MIT
The MIT License (MIT)
Copyright (c) 20152016 Sebastian Mayr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
wrappy
ISC
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

430
.github/actions/issue-validator/package-lock.json generated vendored Normal file
View file

@ -0,0 +1,430 @@
{
"name": "issue-validator",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"@actions/core": "1.9.0",
"@actions/github": "5.0.3"
},
"devDependencies": {
"@vercel/ncc": "0.34.0"
}
},
"node_modules/@actions/core": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.0.tgz",
"integrity": "sha512-5pbM693Ih59ZdUhgk+fts+bUWTnIdHV3kwOSr+QIoFHMLg7Gzhwm0cifDY/AG68ekEJAkHnQVpcy4f6GjmzBCA==",
"dependencies": {
"@actions/http-client": "^2.0.1"
}
},
"node_modules/@actions/github": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.3.tgz",
"integrity": "sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
}
},
"node_modules/@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": {
"tunnel": "^0.0.6"
}
},
"node_modules/@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"dependencies": {
"@octokit/types": "^6.0.3"
}
},
"node_modules/@octokit/core": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"dependencies": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.3",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"dependencies": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"dependencies": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/openapi-types": {
"version": "12.10.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.10.1.tgz",
"integrity": "sha512-P+SukKanjFY0ZhsK6wSVnQmxTP2eVPPE8OPSNuxaMYtgVzwJZgfGdwlYjf4RlRU4vLEw4ts2fsE2icG4nZ5ddQ=="
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "2.21.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
"dependencies": {
"@octokit/types": "^6.40.0"
},
"peerDependencies": {
"@octokit/core": ">=2"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "5.16.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
"integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
"dependencies": {
"@octokit/types": "^6.39.0",
"deprecation": "^2.3.1"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"dependencies": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
}
},
"node_modules/@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"dependencies": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"node_modules/@octokit/types": {
"version": "6.40.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.40.0.tgz",
"integrity": "sha512-MFZOU5r8SwgJWDMhrLUSvyJPtVsqA6VnbVI3TNbsmw+Jnvrktzvq2fYES/6RiJA/5Ykdwq4mJmtlYUfW7CGjmw==",
"dependencies": {
"@octokit/openapi-types": "^12.10.0"
}
},
"node_modules/@vercel/ncc": {
"version": "0.34.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A==",
"dev": true,
"bin": {
"ncc": "dist/ncc/cli.js"
}
},
"node_modules/before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
},
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
},
"dependencies": {
"@actions/core": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.0.tgz",
"integrity": "sha512-5pbM693Ih59ZdUhgk+fts+bUWTnIdHV3kwOSr+QIoFHMLg7Gzhwm0cifDY/AG68ekEJAkHnQVpcy4f6GjmzBCA==",
"requires": {
"@actions/http-client": "^2.0.1"
}
},
"@actions/github": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.3.tgz",
"integrity": "sha512-myjA/pdLQfhUGLtRZC/J4L1RXOG4o6aYdiEq+zr5wVVKljzbFld+xv10k1FX6IkIJtNxbAq44BdwSNpQ015P0A==",
"requires": {
"@actions/http-client": "^2.0.1",
"@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
}
},
"@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": {
"tunnel": "^0.0.6"
}
},
"@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"requires": {
"@octokit/types": "^6.0.3"
}
},
"@octokit/core": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"requires": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.3",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"requires": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"requires": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"version": "12.10.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.10.1.tgz",
"integrity": "sha512-P+SukKanjFY0ZhsK6wSVnQmxTP2eVPPE8OPSNuxaMYtgVzwJZgfGdwlYjf4RlRU4vLEw4ts2fsE2icG4nZ5ddQ=="
},
"@octokit/plugin-paginate-rest": {
"version": "2.21.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
"integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
"requires": {
"@octokit/types": "^6.40.0"
}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "5.16.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
"integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
"requires": {
"@octokit/types": "^6.39.0",
"deprecation": "^2.3.1"
}
},
"@octokit/request": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"requires": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"requires": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/types": {
"version": "6.40.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.40.0.tgz",
"integrity": "sha512-MFZOU5r8SwgJWDMhrLUSvyJPtVsqA6VnbVI3TNbsmw+Jnvrktzvq2fYES/6RiJA/5Ykdwq4mJmtlYUfW7CGjmw==",
"requires": {
"@octokit/openapi-types": "^12.10.0"
}
},
"@vercel/ncc": {
"version": "0.34.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A==",
"dev": true
},
"before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
},
"deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
},
"node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
}
}

View file

@ -0,0 +1,14 @@
{
"private": true,
"exports": "./index.mjs",
"scripts": {
"build": "ncc -m -o . build src/index.mjs --license licenses.txt"
},
"devDependencies": {
"@vercel/ncc": "0.34.0"
},
"dependencies": {
"@actions/core": "1.10.0",
"@actions/github": "5.1.1"
}
}

View file

@ -0,0 +1,38 @@
We cannot recreate the issue with the provided information. **Please add a reproduction in order for us to be able to investigate.**
### **Why was this issue marked with the `please add a complete reproduction` label?**
To be able to investigate, we need access to a reproduction to identify what triggered the issue. We prefer a link to a public GitHub repository ([template](https://github.com/vercel/next.js/tree/canary/examples/reproduction-template)), but you can also use a tool like [CodeSandbox](https://codesandbox.io/s/github/vercel/next.js/tree/canary/examples/reproduction-template) or [StackBlitz](https://stackblitz.com/fork/github/vercel/next.js/tree/canary/examples/reproduction-template).
To make sure the issue is resolved as quickly as possible, please make sure that the reproduction is as **minimal** as possible. This means that you should **remove unnecessary code, files, and dependencies** that do not contribute to the issue.
Please test your reproduction against the latest version of Next.js (`next@canary`) to make sure your issue has not already been fixed.
### **I added a link, why was it still marked?**
Ensure the link is pointing to a codebase that is accessible (e.g. not a private repository). "[example.com](http://example.com/)", "n/a", "will add later", etc. are not acceptable links -- we need to see a public codebase. See the above section for accepted links.
### **What happens if I don't provide a sufficient minimal reproduction?**
Issues with the `please add a complete reproduction` label that receives no meaningful activity (e.g. new comments with a reproduction link) are automatically closed and locked after 30 days.
If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction.
### **I did not open this issue, but it is relevant to me, what can I do to help?**
Anyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps. Furthermore, you can upvote the issue using the :+1: reaction on the topmost comment (please **do not** comment "I have the same issue" without reproduction steps). Then, we can sort issues by votes to prioritize.
### **I think my reproduction is good enough, why aren't you looking into it quicker?**
We look into every Next.js issue and constantly monitor open issues for new comments.
However, sometimes we might miss one or two due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.
Upvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.
### **Useful Resources**
- [How to Contribute to Open Source (Next.js)](https://www.youtube.com/watch?v=cuoNzXFLitc)
- [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve)
- [Reporting a Next.js bug](https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml)
- [Next.js Triaging issues](https://github.com/vercel/next.js/blob/canary/contributing/repository/triaging.md)

View file

@ -0,0 +1,141 @@
// @ts-check
// @ts-expect-error
import * as github from '@actions/github'
// @ts-expect-error
import * as core from '@actions/core'
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
const verifyCanaryLabel = 'please verify canary'
const addReproductionLabel = 'please add a complete reproduction'
// const bugLabel = 'template: bug'
const __dirname =
'/home/runner/work/next.js/next.js/.github/actions/issue-validator'
/**
* @typedef {{
* id :number
* node_id :string
* url :string
* name :string
* description :string
* color :string
* default :boolean
* }} Label
*
* @typedef {{
* pull_request: any
* issue?: {body: string, number: number, labels: Label[]}
* label: Label
* }} Payload
*
* @typedef {{
* payload: Payload
* repo: any
* }} Context
*/
async function run() {
try {
/** @type {Context} */
const { payload, repo } = github.context
const {
issue,
pull_request,
label: { name: newLabel },
} = payload
if (pull_request || !issue?.body || !process.env.GITHUB_TOKEN) return
const labels = issue.labels.map((l) => l.name)
// const isBugReport =
// labels.includes(bugLabel) || newLabel === bugLabel || !labels.length
if (
// !(isBugReport && issue.number > 43554) &&
![verifyCanaryLabel, addReproductionLabel].includes(newLabel) &&
!(
labels.includes(verifyCanaryLabel) ||
labels.includes(addReproductionLabel)
)
) {
return core.info(
'Not a bug report or not manually labeled or already labeled.'
)
}
// /** @param {string|null|undefined} link */
// async function hasRepro(link) {
// if (!link) return false
// try {
// const url = new URL(link)
// if (['example.com'].includes(url.hostname)) {
// return false
// }
// } catch {
// return false
// }
// const response = await fetch(link)
// return response.ok
// }
// const hasValidRepro =
// isBugReport &&
// (await hasRepro(
// issue.body.match(
// /will be addressed faster\n\n(.*)\n\n### To Reproduce/i
// )?.[1]
// ))
const client = github.getOctokit(process.env.GITHUB_TOKEN).rest
const issueCommon = { ...repo, issue_number: issue.number }
if (
newLabel === addReproductionLabel
// || !hasValidRepro
) {
await Promise.all([
client.issues.addLabels({
...issueCommon,
labels: [addReproductionLabel],
}),
client.issues.createComment({
...issueCommon,
body: readFileSync(join(__dirname, 'repro.md'), 'utf8'),
}),
])
return core.info(
'Commented on issue, because it did not have a sufficient reproduction.'
)
}
// const isVerifyCanaryChecked =
// isBugReport &&
// issue.body.match(
// /- \[x\] I verified that the issue exists in the latest Next.js canary release/i
// )
if (
newLabel === verifyCanaryLabel
// || !isVerifyCanaryChecked
) {
await Promise.all([
client.issues.addLabels({
...issueCommon,
labels: [verifyCanaryLabel],
}),
client.issues.createComment({
...issueCommon,
body: readFileSync(join(__dirname, 'canary.md'), 'utf8'),
}),
])
return core.info(
'Commented on issue, because it was not verified against canary.'
)
}
} catch (error) {
core.setFailed(error.message)
}
}
run()

View file

@ -0,0 +1,3 @@
**/node_modules
out.md
.work

View file

@ -0,0 +1,20 @@
FROM node:16-bullseye
LABEL com.github.actions.name="Next.js PR Stats"
LABEL com.github.actions.description="Compares stats of a PR with the main branch"
LABEL repository="https://github.com/vercel/next-stats-action"
COPY . /next-stats
# Install node_modules
RUN npm i -g pnpm@7.24.3
RUN cd /next-stats && pnpm install --production
RUN git config --global user.email 'stats@localhost'
RUN git config --global user.name 'next stats'
RUN apt update
RUN apt install apache2-utils -y
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View file

@ -0,0 +1,93 @@
# Next.js Stats GitHub Action
> Downloads and runs project with provided configs gathering stats to compare branches
See it in action at Next.js https://github.com/vercel/next.js
## Getting Started
1. Add a `.stats-app` folder to your project with a [`stats-config.js`](#stats-config) and any files to run against for example a test app that is to be built
2. Add the action to your [workflow](https://help.github.com/en/articles/configuring-a-workflow)
3. Enjoy the stats
## Stats Config
```TypeScript
const StatsConfig = {
// the Heading to show at the top of stats comments
commentHeading: 'Stats from current PR' | undefined,
commentReleaseHeading: 'Stats from current release' | undefined,
// the command to build your project if not done on post install
initialBuildCommand: undefined | string,
skipInitialInstall: undefined | boolean,
// the command to build the app (app source should be in `.stats-app`)
appBuildCommand: string,
appStartCommand: string | undefined,
// the main branch to compare against (what PRs will be merging into)
mainBranch: 'canary',
// the main repository path (relative to https://github.com/)
mainRepo: 'vercel/next.js',
// whether to attempt auto merging the main branch into PR before running stats
autoMergeMain: boolean | undefined,
// an array of configs for each run
configs: [
{ // first run's config
// title of the run
title: 'fastMode stats',
// whether to diff the outputted files (default: onOutputChange)
diff: 'onOutputChange' | false | undefined,
// config files to add before running diff (if `undefined` uses `configFiles`)
diffConfigFiles: [] | undefined,
// renames to apply to make file names deterministic
renames: [
{
srcGlob: 'main-*.js',
dest: 'main.js'
}
],
// config files to add before running (removed before successive runs)
configFiles: [
{
path: './next.config.js',
content: 'module.exports = { fastMode: true }'
}
],
// an array of file groups to diff/track
filesToTrack: [
{
name: 'Pages',
globs: [
'build/pages/**/*.js'
]
}
],
// an array of URLs to fetch while `appStartCommand` is running
// will be output to fetched-pages/${pathname}.html
pagesToFetch: [
'https://localhost:$PORT/page-1'
]
},
{ // second run's config
title: 'slowMode stats',
diff: false,
configFiles: [
{
path: './next.config.js',
content: 'module.exports = { slowMode: true }'
}
],
filesToTrack: [
{
name: 'Main Bundles',
globs: [
'build/runtime/webpack-*.js',
'build/runtime/main-*.js',
]
}
]
},
]
}
module.exports = StatsConfig
```

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -eu # stop on error
export HOME=/root
node /next-stats/src/index.js

View file

@ -0,0 +1,18 @@
{
"private": true,
"main": "src/index.js",
"dependencies": {
"async-sema": "^3.1.0",
"execa": "2.0.3",
"fs-extra": "^8.1.0",
"get-port": "^5.0.0",
"glob": "^7.1.4",
"gzip-size": "^5.1.1",
"minimatch": "^3.0.4",
"node-fetch": "^2.6.0",
"prettier": "^1.18.2",
"pretty-bytes": "^5.3.0",
"pretty-ms": "^5.0.0",
"semver": "7.3.4"
}
}

View file

@ -0,0 +1,274 @@
const path = require('path')
const fs = require('fs').promises
const fetch = require('node-fetch')
const prettyMs = require('pretty-ms')
const logger = require('./util/logger')
const prettyBytes = require('pretty-bytes')
const { benchTitle } = require('./constants')
const gzipIgnoreRegex = new RegExp(`(General|^Serverless|${benchTitle})`)
const prettify = (val, type = 'bytes') => {
if (typeof val !== 'number') return 'N/A'
return type === 'bytes' ? prettyBytes(val) : prettyMs(val)
}
const round = (num, places) => {
const placesFactor = Math.pow(10, places)
return Math.round(num * placesFactor) / placesFactor
}
const shortenLabel = (itemKey) =>
itemKey.length > 24
? `${itemKey.slice(0, 12)}..${itemKey.slice(-12)}`
: itemKey
const twoMB = 2 * 1024 * 1024
module.exports = async function addComment(
results = [],
actionInfo,
statsConfig
) {
let comment = `# ${
actionInfo.isRelease
? statsConfig.commentReleaseHeading || 'Stats from current release'
: statsConfig.commentHeading || 'Stats from current PR'
}\n\n`
const tableHead = `| | ${statsConfig.mainRepo} ${statsConfig.mainBranch} ${
actionInfo.lastStableTag || ''
} | ${actionInfo.prRepo} ${actionInfo.prRef} | Change |\n| - | - | - | - |\n`
for (let i = 0; i < results.length; i++) {
const result = results[i]
const isLastResult = i === results.length - 1
let resultHasIncrease = false
let resultHasDecrease = false
let resultContent = ''
Object.keys(result.mainRepoStats).forEach((groupKey) => {
const isBenchmark = groupKey === benchTitle
const mainRepoGroup = result.mainRepoStats[groupKey]
const diffRepoGroup = result.diffRepoStats[groupKey]
const itemKeys = new Set([
...Object.keys(mainRepoGroup),
...Object.keys(diffRepoGroup),
])
let groupTable = tableHead
let mainRepoTotal = 0
let diffRepoTotal = 0
let totalChange = 0
itemKeys.forEach((itemKey) => {
const prettyType = itemKey.match(/(length|duration)/i) ? 'ms' : 'bytes'
const isGzipItem = itemKey.endsWith('gzip')
const mainItemVal = mainRepoGroup[itemKey]
const diffItemVal = diffRepoGroup[itemKey]
const useRawValue = isBenchmark && prettyType !== 'ms'
const mainItemStr = useRawValue
? mainItemVal
: prettify(mainItemVal, prettyType)
const diffItemStr = useRawValue
? diffItemVal
: prettify(diffItemVal, prettyType)
let change = '✓'
// Don't show gzip values for serverless as they aren't
// deterministic currently
if (groupKey.startsWith('Serverless') && isGzipItem) return
// otherwise only show gzip values
else if (!isGzipItem && !groupKey.match(gzipIgnoreRegex)) return
if (
!itemKey.startsWith('buildDuration') ||
(isBenchmark && itemKey.match(/req\/sec/))
) {
if (typeof mainItemVal === 'number') mainRepoTotal += mainItemVal
if (typeof diffItemVal === 'number') diffRepoTotal += diffItemVal
}
// calculate the change
if (mainItemVal !== diffItemVal) {
if (
typeof mainItemVal === 'number' &&
typeof diffItemVal === 'number'
) {
change = round(diffItemVal - mainItemVal, 2)
// check if there is still a change after rounding
if (change !== 0) {
const absChange = Math.abs(change)
const warnIfNegative = isBenchmark && itemKey.match(/req\/sec/)
const warn = warnIfNegative
? change < 0
? '⚠️ '
: ''
: change > 0
? '⚠️ '
: ''
change = `${warn}${change < 0 ? '-' : '+'}${
useRawValue ? absChange : prettify(absChange, prettyType)
}`
}
} else {
change = 'N/A'
}
}
groupTable += `| ${
isBenchmark ? itemKey : shortenLabel(itemKey)
} | ${mainItemStr} | ${diffItemStr} | ${change} |\n`
})
let groupTotalChange = ''
totalChange = diffRepoTotal - mainRepoTotal
if (totalChange !== 0) {
if (totalChange < 0) {
resultHasDecrease = true
groupTotalChange = ` Overall decrease ${isBenchmark ? '⚠️' : '✓'}`
} else {
if (
(groupKey !== 'General' && totalChange > 5) ||
totalChange > twoMB
) {
resultHasIncrease = true
}
groupTotalChange = ` Overall increase ${isBenchmark ? '✓' : '⚠️'}`
}
}
if (groupKey !== 'General' && groupKey !== benchTitle) {
let totalChangeSign = ''
if (totalChange === 0) {
totalChange = '✓'
} else {
totalChangeSign = totalChange < 0 ? '-' : '⚠️ +'
}
totalChange = `${totalChangeSign}${
typeof totalChange === 'number'
? prettify(Math.abs(totalChange))
: totalChange
}`
groupTable += `| Overall change | ${prettyBytes(
round(mainRepoTotal, 2)
)} | ${prettyBytes(round(diffRepoTotal, 2))} | ${totalChange} |\n`
}
if (itemKeys.size > 0) {
resultContent += `<details>\n`
resultContent += `<summary><strong>${groupKey}</strong>${groupTotalChange}</summary>\n\n`
resultContent += groupTable
resultContent += `\n</details>\n\n`
}
})
// add diffs
if (result.diffs) {
const diffHeading = '#### Diffs\n'
let diffContent = diffHeading
Object.keys(result.diffs).forEach((itemKey) => {
const curDiff = result.diffs[itemKey]
diffContent += `<details>\n`
diffContent += `<summary>Diff for <strong>${shortenLabel(
itemKey
)}</strong></summary>\n\n`
if (curDiff.length > 36 * 1000) {
diffContent += 'Diff too large to display'
} else {
diffContent += `\`\`\`diff\n${curDiff}\n\`\`\``
}
diffContent += `\n</details>\n`
})
if (diffContent !== diffHeading) {
resultContent += diffContent
}
}
let increaseDecreaseNote = ''
if (resultHasIncrease) {
increaseDecreaseNote = ' (Increase detected ⚠️)'
} else if (resultHasDecrease) {
increaseDecreaseNote = ' (Decrease detected ✓)'
}
comment += `<details>\n`
comment += `<summary><strong>${result.title}</strong>${increaseDecreaseNote}</summary>\n\n<br/>\n\n`
comment += resultContent
comment += '</details>\n'
if (!isLastResult) {
comment += `<hr/>\n`
}
}
if (process.env.LOCAL_STATS) {
const statsPath = path.resolve('pr-stats.md')
await fs.writeFile(statsPath, comment)
console.log(`Output PR stats to ${statsPath}`)
} else {
logger('\n--stats start--\n', comment, '\n--stats end--\n')
}
if (
actionInfo.customCommentEndpoint ||
(actionInfo.githubToken && actionInfo.commentEndpoint)
) {
logger(`Posting results to ${actionInfo.commentEndpoint}`)
const body = {
body: comment,
...(!actionInfo.githubToken
? {
isRelease: actionInfo.isRelease,
commitId: actionInfo.commitId,
issueId: actionInfo.issueId,
}
: {}),
}
if (actionInfo.customCommentEndpoint) {
logger(`Using body ${JSON.stringify({ ...body, body: 'OMITTED' })}`)
}
try {
const res = await fetch(actionInfo.commentEndpoint, {
method: 'POST',
headers: {
...(actionInfo.githubToken
? {
Authorization: `bearer ${actionInfo.githubToken}`,
}
: {
'content-type': 'application/json',
}),
},
body: JSON.stringify(body),
})
if (!res.ok) {
logger.error(`Failed to post results ${res.status}`)
try {
logger.error(await res.text())
} catch (_) {
/* no-op */
}
} else {
logger('Successfully posted results')
}
} catch (err) {
logger.error(`Error occurred posting results`, err)
}
} else {
logger(
`Not posting results`,
actionInfo.githubToken ? 'No comment endpoint' : 'no GitHub token'
)
}
}

View file

@ -0,0 +1,30 @@
const path = require('path')
const os = require('os')
const fs = require('fs')
const benchTitle = 'Page Load Tests'
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'next-stats'))
const mainRepoDir = path.join(workDir, 'main-repo')
const diffRepoDir = path.join(workDir, 'diff-repo')
const statsAppDir = path.join(workDir, 'stats-app')
const diffingDir = path.join(workDir, 'diff')
const yarnEnvValues = {
YARN_CACHE_FOLDER: path.join(workDir, 'yarn-cache'),
}
const allowedConfigLocations = [
'./',
'.stats-app',
'test/.stats-app',
'.github/.stats-app',
]
module.exports = {
benchTitle,
workDir,
diffingDir,
mainRepoDir,
diffRepoDir,
statsAppDir,
yarnEnvValues,
allowedConfigLocations,
}

View file

@ -0,0 +1,163 @@
const path = require('path')
const fs = require('fs-extra')
const exec = require('./util/exec')
const logger = require('./util/logger')
const runConfigs = require('./run')
const addComment = require('./add-comment')
const actionInfo = require('./prepare/action-info')()
const { mainRepoDir, diffRepoDir } = require('./constants')
const loadStatsConfig = require('./prepare/load-stats-config')
const {
cloneRepo,
checkoutRef,
mergeBranch,
getCommitId,
linkPackages,
getLastStable,
} = require('./prepare/repo-setup')(actionInfo)
const allowedActions = new Set(['synchronize', 'opened'])
if (!allowedActions.has(actionInfo.actionName) && !actionInfo.isRelease) {
logger(
`Not running for ${actionInfo.actionName} event action on repo: ${actionInfo.prRepo} and ref ${actionInfo.prRef}`
)
process.exit(0)
}
;(async () => {
try {
if (await fs.pathExists(path.join(__dirname, '../SKIP_NEXT_STATS.txt'))) {
console.log(
'SKIP_NEXT_STATS.txt file present, exiting stats generation..'
)
process.exit(0)
}
const { stdout: gitName } = await exec(
'git config user.name && git config user.email'
)
console.log('git author result:', gitName)
// clone PR/newer repository/ref first to get settings
if (!actionInfo.skipClone) {
await cloneRepo(actionInfo.prRepo, diffRepoDir)
await checkoutRef(actionInfo.prRef, diffRepoDir)
}
if (actionInfo.isRelease) {
process.env.STATS_IS_RELEASE = 'true'
}
// load stats config from allowed locations
const { statsConfig, relativeStatsAppDir } = loadStatsConfig()
if (actionInfo.isLocal && actionInfo.prRef === statsConfig.mainBranch) {
throw new Error(
`'GITHUB_REF' can not be the same as mainBranch in 'stats-config.js'.\n` +
`This will result in comparing against the same branch`
)
}
if (actionInfo.isLocal) {
// make sure to use local repo location instead of the
// one provided in statsConfig
statsConfig.mainRepo = actionInfo.prRepo
}
// clone main repository/ref
if (!actionInfo.skipClone) {
await cloneRepo(statsConfig.mainRepo, mainRepoDir)
await checkoutRef(statsConfig.mainBranch, mainRepoDir)
}
/* eslint-disable-next-line */
actionInfo.commitId = await getCommitId(diffRepoDir)
let mainNextSwcVersion
if (!actionInfo.skipClone) {
if (actionInfo.isRelease) {
logger('Release detected, resetting mainRepo to last stable tag')
const lastStableTag = await getLastStable(mainRepoDir, actionInfo.prRef)
mainNextSwcVersion = lastStableTag
if (!lastStableTag) throw new Error('failed to get last stable tag')
console.log('using latestStable', lastStableTag)
await checkoutRef(lastStableTag, mainRepoDir)
/* eslint-disable-next-line */
actionInfo.lastStableTag = lastStableTag
/* eslint-disable-next-line */
actionInfo.commitId = await getCommitId(diffRepoDir)
if (!actionInfo.customCommentEndpoint) {
/* eslint-disable-next-line */
actionInfo.commentEndpoint = `https://api.github.com/repos/${statsConfig.mainRepo}/commits/${actionInfo.commitId}/comments`
}
} else if (statsConfig.autoMergeMain) {
logger('Attempting auto merge of main branch')
await mergeBranch(statsConfig.mainBranch, mainRepoDir, diffRepoDir)
}
}
let mainRepoPkgPaths
let diffRepoPkgPaths
// run install/initialBuildCommand
const repoDirs = [mainRepoDir, diffRepoDir]
for (const dir of repoDirs) {
logger(`Running initial build for ${dir}`)
if (!actionInfo.skipClone) {
const usePnpm = await fs.pathExists(path.join(dir, 'pnpm-lock.yaml'))
let buildCommand = `cd ${dir}${
!statsConfig.skipInitialInstall
? usePnpm
? // --no-frozen-lockfile is used here to tolerate lockfile
// changes from merging latest changes
` && pnpm install --no-frozen-lockfile && pnpm run build`
: ' && yarn install --network-timeout 1000000'
: ''
}`
if (statsConfig.initialBuildCommand) {
buildCommand += ` && ${statsConfig.initialBuildCommand}`
}
// allow 5 minutes node_modules install + building all packages
// in case of noisy environment slowing down initial repo build
await exec(buildCommand, false, { timeout: 5 * 60 * 1000 })
}
await fs
.copy(
path.join(__dirname, '../native'),
path.join(dir, 'packages/next-swc/native')
)
.catch(console.error)
logger(`Linking packages in ${dir}`)
const isMainRepo = dir === mainRepoDir
const pkgPaths = await linkPackages({
repoDir: dir,
nextSwcVersion: isMainRepo ? mainNextSwcVersion : undefined,
})
if (isMainRepo) mainRepoPkgPaths = pkgPaths
else diffRepoPkgPaths = pkgPaths
}
// run the configs and post the comment
const results = await runConfigs(statsConfig.configs, {
statsConfig,
mainRepoPkgPaths,
diffRepoPkgPaths,
relativeStatsAppDir,
})
await addComment(results, actionInfo, statsConfig)
logger('finished')
process.exit(0)
} catch (err) {
console.error('Error occurred generating stats:')
console.error(err)
process.exit(1)
}
})()

View file

@ -0,0 +1,99 @@
const path = require('path')
const logger = require('../util/logger')
const { execSync } = require('child_process')
const releaseTypes = new Set(['release', 'published'])
module.exports = function actionInfo() {
let {
ISSUE_ID,
SKIP_CLONE,
GITHUB_REF,
LOCAL_STATS,
GIT_ROOT_DIR,
GITHUB_ACTION,
COMMENT_ENDPOINT,
GITHUB_REPOSITORY,
GITHUB_EVENT_PATH,
PR_STATS_COMMENT_TOKEN,
} = process.env
delete process.env.GITHUB_TOKEN
delete process.env.PR_STATS_COMMENT_TOKEN
// only use custom endpoint if we don't have a token
const commentEndpoint = !PR_STATS_COMMENT_TOKEN && COMMENT_ENDPOINT
if (LOCAL_STATS === 'true') {
const cwd = process.cwd()
const parentDir = path.join(cwd, '../..')
if (!GITHUB_REF) {
// get the current branch name
GITHUB_REF = execSync(`cd "${cwd}" && git rev-parse --abbrev-ref HEAD`)
.toString()
.trim()
}
if (!GIT_ROOT_DIR) {
GIT_ROOT_DIR = path.join(parentDir, '/')
}
if (!GITHUB_REPOSITORY) {
GITHUB_REPOSITORY = path.relative(parentDir, cwd)
}
if (!GITHUB_ACTION) {
GITHUB_ACTION = 'opened'
}
}
const info = {
commentEndpoint,
skipClone: SKIP_CLONE,
actionName: GITHUB_ACTION,
githubToken: PR_STATS_COMMENT_TOKEN,
customCommentEndpoint: !!commentEndpoint,
gitRoot: GIT_ROOT_DIR || 'https://github.com/',
prRepo: GITHUB_REPOSITORY,
prRef: GITHUB_REF,
isLocal: LOCAL_STATS,
commitId: null,
issueId: ISSUE_ID,
isRelease:
GITHUB_REPOSITORY === 'vercel/next.js' &&
(GITHUB_REF || '').includes('canary'),
}
// get comment
if (GITHUB_EVENT_PATH) {
const event = require(GITHUB_EVENT_PATH)
info.actionName = event.action || info.actionName
if (releaseTypes.has(info.actionName)) {
info.isRelease = true
} else {
// since GITHUB_REPOSITORY and REF might not match the fork
// use event data to get repository and ref info
const prData = event['pull_request']
if (prData) {
info.prRepo = prData.head.repo.full_name
info.prRef = prData.head.ref
info.issueId = prData.number
if (!info.commentEndpoint) {
info.commentEndpoint = prData._links.comments || ''
}
// comment endpoint might be under `href`
if (typeof info.commentEndpoint === 'object') {
info.commentEndpoint = info.commentEndpoint.href
}
}
}
}
logger('Got actionInfo:')
logger.json({
...info,
githubToken: PR_STATS_COMMENT_TOKEN ? 'found' : 'missing',
})
return info
}

View file

@ -0,0 +1,44 @@
const path = require('path')
const logger = require('../util/logger')
const { diffRepoDir, allowedConfigLocations } = require('../constants')
// load stats-config
function loadStatsConfig() {
let statsConfig
let relativeStatsAppDir
for (const configPath of allowedConfigLocations) {
try {
relativeStatsAppDir = configPath
statsConfig = require(path.join(
diffRepoDir,
configPath,
'stats-config.js'
))
break
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') {
console.error('Failed to load stats-config at', configPath, err)
}
/* */
}
}
if (!statsConfig) {
throw new Error(
`Failed to locate \`.stats-app\`, allowed locations are: ${allowedConfigLocations.join(
', '
)}`
)
}
logger(
'Got statsConfig at',
path.join(relativeStatsAppDir, 'stats-config.js'),
statsConfig,
'\n'
)
return { statsConfig, relativeStatsAppDir }
}
module.exports = loadStatsConfig

View file

@ -0,0 +1,200 @@
const path = require('path')
const fs = require('fs-extra')
const exec = require('../util/exec')
const { remove } = require('fs-extra')
const logger = require('../util/logger')
const semver = require('semver')
const execa = require('execa')
module.exports = (actionInfo) => {
return {
async cloneRepo(repoPath = '', dest = '') {
await remove(dest)
await exec(`git clone ${actionInfo.gitRoot}${repoPath} ${dest}`)
},
async checkoutRef(ref = '', repoDir = '') {
await exec(`cd ${repoDir} && git fetch && git checkout ${ref}`)
},
async getLastStable(repoDir = '', ref) {
const { stdout } = await exec(`cd ${repoDir} && git tag -l`)
const tags = stdout.trim().split('\n')
let lastStableTag
for (let i = tags.length - 1; i >= 0; i--) {
const curTag = tags[i]
// stable doesn't include `-canary` or `-beta`
if (!curTag.includes('-') && !ref.includes(curTag)) {
if (!lastStableTag || semver.gt(curTag, lastStableTag)) {
lastStableTag = curTag
}
}
}
return lastStableTag
},
async getCommitId(repoDir = '') {
const { stdout } = await exec(`cd ${repoDir} && git rev-parse HEAD`)
return stdout.trim()
},
async resetToRef(ref = '', repoDir = '') {
await exec(`cd ${repoDir} && git reset --hard ${ref}`)
},
async mergeBranch(ref = '', origRepoDir = '', destRepoDir = '') {
await exec(`cd ${destRepoDir} && git remote add upstream ${origRepoDir}`)
await exec(`cd ${destRepoDir} && git fetch upstream`)
try {
await exec(`cd ${destRepoDir} && git merge upstream/${ref}`)
logger('Auto merge of main branch successful')
} catch (err) {
logger.error('Failed to auto merge main branch:', err)
if (err.stdout && err.stdout.includes('CONFLICT')) {
await exec(`cd ${destRepoDir} && git merge --abort`)
logger('aborted auto merge')
}
}
},
async linkPackages({ repoDir, nextSwcVersion }) {
let useTestPack = process.env.NEXT_TEST_PACK
if (useTestPack) {
execa.sync('pnpm', ['turbo', 'run', 'test-pack'], {
cwd: repoDir,
env: { NEXT_SWC_VERSION: nextSwcVersion },
})
const pkgPaths = new Map()
const pkgs = (await fs.readdir(path.join(repoDir, 'packages'))).filter(
(item) => !item.startsWith('.')
)
pkgs.forEach((pkgDirname) => {
const { name } = require(path.join(
repoDir,
'packages',
pkgDirname,
'package.json'
))
pkgPaths.set(
name,
path.join(
repoDir,
'packages',
pkgDirname,
`packed-${pkgDirname}.tgz`
)
)
})
return pkgPaths
} else {
// TODO: remove after next stable release (current v13.1.2)
const pkgPaths = new Map()
const pkgDatas = new Map()
let pkgs
try {
pkgs = await fs.readdir(path.join(repoDir, 'packages'))
} catch (err) {
if (err.code === 'ENOENT') {
require('console').log('no packages to link')
return pkgPaths
}
throw err
}
for (const pkg of pkgs) {
const pkgPath = path.join(repoDir, 'packages', pkg)
const packedPkgPath = path.join(pkgPath, `${pkg}-packed.tgz`)
const pkgDataPath = path.join(pkgPath, 'package.json')
if (!fs.existsSync(pkgDataPath)) {
require('console').log(`Skipping ${pkgDataPath}`)
continue
}
const pkgData = require(pkgDataPath)
const { name } = pkgData
pkgDatas.set(name, {
pkgDataPath,
pkg,
pkgPath,
pkgData,
packedPkgPath,
})
pkgPaths.set(name, packedPkgPath)
}
for (const pkg of pkgDatas.keys()) {
const { pkgDataPath, pkgData } = pkgDatas.get(pkg)
for (const pkg of pkgDatas.keys()) {
const { packedPkgPath } = pkgDatas.get(pkg)
if (!pkgData.dependencies || !pkgData.dependencies[pkg]) continue
pkgData.dependencies[pkg] = packedPkgPath
}
// make sure native binaries are included in local linking
if (pkg === '@next/swc') {
if (!pkgData.files) {
pkgData.files = []
}
pkgData.files.push('native/*')
require('console').log(
'using swc binaries: ',
await exec(`ls ${path.join(path.dirname(pkgDataPath), 'native')}`)
)
}
if (pkg === 'next') {
if (nextSwcVersion) {
Object.assign(pkgData.dependencies, {
'@next/swc-linux-x64-gnu': nextSwcVersion,
})
} else {
if (pkgDatas.get('@next/swc')) {
pkgData.dependencies['@next/swc'] =
pkgDatas.get('@next/swc').packedPkgPath
} else {
pkgData.files.push('native/*')
}
}
}
if (pkgData?.scripts?.prepublishOnly) {
// There's a bug in `pnpm pack` where it will run
// the prepublishOnly script and that will fail.
// See https://github.com/pnpm/pnpm/issues/2941
delete pkgData.scripts.prepublishOnly
}
await fs.writeFile(
pkgDataPath,
JSON.stringify(pkgData, null, 2),
'utf8'
)
}
// wait to pack packages until after dependency paths have been updated
// to the correct versions
await Promise.all(
Array.from(pkgDatas.keys()).map(async (pkgName) => {
const { pkg, pkgPath, pkgData, packedPkgPath } =
pkgDatas.get(pkgName)
// Copied from pnpm source: https://github.com/pnpm/pnpm/blob/5a5512f14c47f4778b8d2b6d957fb12c7ef40127/releasing/plugin-commands-publishing/src/pack.ts#L96
const tmpTarball = path.join(
pkgPath,
`${pkgData.name.replace('@', '').replace('/', '-')}-${
pkgData.version
}.tgz`
)
await execa('pnpm', ['pack'], {
cwd: pkgPath,
})
await fs.copyFile(tmpTarball, packedPkgPath)
})
)
return pkgPaths
}
},
}
}

View file

@ -0,0 +1,32 @@
const exec = require('../util/exec')
const parseField = (stdout = '', field = '') => {
return stdout.split(field).pop().trim().split(/\s/).shift().trim()
}
// benchmark an url
async function benchmarkUrl(
url = '',
options = {
reqTimeout: 60,
concurrency: 50,
numRequests: 2500,
}
) {
const { numRequests, concurrency, reqTimeout } = options
const { stdout } = await exec(
`ab -n ${numRequests} -c ${concurrency} -s ${reqTimeout} "${url}"`
)
const totalTime = parseFloat(parseField(stdout, 'Time taken for tests:'), 10)
const failedRequests = parseInt(parseField(stdout, 'Failed requests:'), 10)
const avgReqPerSec = parseFloat(parseField(stdout, 'Requests per second:'))
return {
totalTime,
avgReqPerSec,
failedRequests,
}
}
module.exports = benchmarkUrl

View file

@ -0,0 +1,116 @@
const path = require('path')
const fs = require('fs-extra')
const exec = require('../util/exec')
const glob = require('../util/glob')
const logger = require('../util/logger')
const { statsAppDir, diffingDir } = require('../constants')
module.exports = async function collectDiffs(
filesToTrack = [],
initial = false
) {
if (initial) {
logger('Setting up directory for diffing')
// set-up diffing directory
await fs.remove(diffingDir)
await fs.mkdirp(diffingDir)
await exec(`cd ${diffingDir} && git init`)
} else {
// remove any previous files in case they won't be overwritten
const toRemove = await glob('!(.git)', { cwd: diffingDir, dot: true })
await Promise.all(
toRemove.map((file) => fs.remove(path.join(diffingDir, file)))
)
}
const diffs = {}
await Promise.all(
filesToTrack.map(async (fileGroup) => {
const { globs } = fileGroup
const curFiles = []
await Promise.all(
globs.map(async (pattern) => {
curFiles.push(...(await glob(pattern, { cwd: statsAppDir })))
})
)
for (let file of curFiles) {
const absPath = path.join(statsAppDir, file)
const diffDest = path.join(diffingDir, file)
await fs.copy(absPath, diffDest)
}
if (curFiles.length > 0) {
const prettierPath = path.join(
__dirname,
'../../node_modules/.bin/prettier'
)
await exec(
`cd "${process.env.LOCAL_STATS ? process.cwd() : diffingDir}" && ` +
`${prettierPath} --write ${curFiles
.map((f) => path.join(diffingDir, f))
.join(' ')}`
)
}
})
)
await exec(`cd ${diffingDir} && git add .`, true)
if (initial) {
await exec(`cd ${diffingDir} && git commit -m 'initial commit'`)
} else {
let { stdout: renamedFiles } = await exec(
`cd ${diffingDir} && git diff --name-status HEAD`
)
renamedFiles = renamedFiles
.trim()
.split('\n')
.filter((line) => line.startsWith('R'))
diffs._renames = []
for (const line of renamedFiles) {
const [, prev, cur] = line.split('\t')
await fs.move(path.join(diffingDir, cur), path.join(diffingDir, prev))
diffs._renames.push({
prev,
cur,
})
}
await exec(`cd ${diffingDir} && git add .`)
let { stdout: changedFiles } = await exec(
`cd ${diffingDir} && git diff --name-only HEAD`
)
changedFiles = changedFiles.trim().split('\n')
for (const file of changedFiles) {
const fileKey = path.basename(file)
const hasFile = await fs.exists(path.join(diffingDir, file))
if (!hasFile) {
diffs[fileKey] = 'deleted'
continue
}
try {
let { stdout } = await exec(
`cd ${diffingDir} && git diff --minimal HEAD ${file}`
)
stdout = (stdout.split(file).pop() || '').trim()
if (stdout.length > 0) {
diffs[fileKey] = stdout
}
} catch (err) {
console.error(`Failed to diff ${file}: ${err.message}`)
diffs[fileKey] = `failed to diff`
}
}
}
return diffs
}

View file

@ -0,0 +1,171 @@
const path = require('path')
const fs = require('fs-extra')
const getPort = require('get-port')
const fetch = require('node-fetch')
const glob = require('../util/glob')
const gzipSize = require('gzip-size')
const logger = require('../util/logger')
const { spawn } = require('../util/exec')
const { parse: urlParse } = require('url')
const benchmarkUrl = require('./benchmark-url')
const { statsAppDir, diffingDir, benchTitle } = require('../constants')
module.exports = async function collectStats(
runConfig = {},
statsConfig = {},
fromDiff = false
) {
const stats = {
[benchTitle]: {},
}
const orderedStats = {
[benchTitle]: {},
}
const curDir = fromDiff ? diffingDir : statsAppDir
const hasPagesToFetch =
Array.isArray(runConfig.pagesToFetch) && runConfig.pagesToFetch.length > 0
const hasPagesToBench =
Array.isArray(runConfig.pagesToBench) && runConfig.pagesToBench.length > 0
if (
!fromDiff &&
statsConfig.appStartCommand &&
(hasPagesToFetch || hasPagesToBench)
) {
const port = await getPort()
const startTime = Date.now()
const child = spawn(statsConfig.appStartCommand, {
cwd: curDir,
env: {
PORT: port,
},
stdio: 'pipe',
})
let exitCode = null
let logStderr = true
let serverReadyResolve
let serverReadyResolved = false
const serverReadyPromise = new Promise((resolve) => {
serverReadyResolve = resolve
})
child.stdout.on('data', (data) => {
if (data.toString().includes('started server') && !serverReadyResolved) {
serverReadyResolved = true
serverReadyResolve()
}
process.stdout.write(data)
})
child.stderr.on('data', (data) => logStderr && process.stderr.write(data))
child.on('exit', (code) => {
if (!serverReadyResolved) {
serverReadyResolve()
serverReadyResolved = true
}
exitCode = code
})
await serverReadyPromise
if (!orderedStats['General']) {
orderedStats['General'] = {}
}
orderedStats['General']['nextStartReadyDuration (ms)'] =
Date.now() - startTime
if (exitCode !== null) {
throw new Error(
`Failed to run \`${statsConfig.appStartCommand}\` process exited with code ${exitCode}`
)
}
if (hasPagesToFetch) {
const fetchedPagesDir = path.join(curDir, 'fetched-pages')
await fs.mkdirp(fetchedPagesDir)
for (let url of runConfig.pagesToFetch) {
url = url.replace('$PORT', port)
const { pathname } = urlParse(url)
try {
const res = await fetch(url)
if (!res.ok) {
throw new Error(`Failed to fetch ${url} got status: ${res.status}`)
}
const responseText = (await res.text()).trim()
let fileName = pathname === '/' ? '/index' : pathname
if (fileName.endsWith('/')) fileName = fileName.slice(0, -1)
logger(
`Writing file to ${path.join(fetchedPagesDir, `${fileName}.html`)}`
)
await fs.writeFile(
path.join(fetchedPagesDir, `${fileName}.html`),
responseText,
'utf8'
)
} catch (err) {
logger.error(err)
}
}
}
if (hasPagesToBench) {
// disable stderr so we don't clobber logs while benchmarking
// any pages that create logs
logStderr = false
for (let url of runConfig.pagesToBench) {
url = url.replace('$PORT', port)
logger(`Benchmarking ${url}`)
const results = await benchmarkUrl(url, runConfig.benchOptions)
logger(`Finished benchmarking ${url}`)
const { pathname: key } = urlParse(url)
stats[benchTitle][`${key} failed reqs`] = results.failedRequests
stats[benchTitle][`${key} total time (seconds)`] = results.totalTime
stats[benchTitle][`${key} avg req/sec`] = results.avgReqPerSec
}
}
child.kill()
}
for (const fileGroup of runConfig.filesToTrack) {
const { name, globs } = fileGroup
const groupStats = {}
const curFiles = new Set()
for (const pattern of globs) {
const results = await glob(pattern, { cwd: curDir, nodir: true })
results.forEach((result) => curFiles.add(result))
}
for (const file of curFiles) {
const fileKey = path.basename(file)
const absPath = path.join(curDir, file)
try {
const fileInfo = await fs.stat(absPath)
groupStats[fileKey] = fileInfo.size
groupStats[`${fileKey} gzip`] = await gzipSize.file(absPath)
} catch (err) {
logger.error('Failed to get file stats', err)
}
}
stats[name] = groupStats
}
for (const fileGroup of runConfig.filesToTrack) {
const { name } = fileGroup
orderedStats[name] = stats[name]
}
if (stats[benchTitle]) {
orderedStats[benchTitle] = stats[benchTitle]
}
return orderedStats
}

View file

@ -0,0 +1,25 @@
const path = require('path')
const fs = require('fs-extra')
// getDirSize recursively gets size of all files in a directory
async function getDirSize(dir, ctx = { size: 0 }) {
let subDirs = await fs.readdir(dir)
subDirs = subDirs.map((d) => path.join(dir, d))
await Promise.all(
subDirs.map(async (curDir) => {
// we use dev builds so the size isn't helpful to track
// here as it's not reflective of full releases
if (curDir.includes('@next/swc')) return
const fileStat = await fs.stat(curDir)
if (fileStat.isDirectory()) {
return getDirSize(curDir, ctx)
}
ctx.size += fileStat.size
})
)
return ctx.size
}
module.exports = getDirSize

View file

@ -0,0 +1,216 @@
const path = require('path')
const fs = require('fs-extra')
const getPort = require('get-port')
const glob = require('../util/glob')
const exec = require('../util/exec')
const logger = require('../util/logger')
const getDirSize = require('./get-dir-size')
const collectStats = require('./collect-stats')
const collectDiffs = require('./collect-diffs')
const { statsAppDir, diffRepoDir, yarnEnvValues } = require('../constants')
async function runConfigs(
configs = [],
{ statsConfig, relativeStatsAppDir, mainRepoPkgPaths, diffRepoPkgPaths },
diffing = false
) {
const results = []
for (const config of configs) {
logger(`Running config: ${config.title}${diffing ? ' (diff)' : ''}`)
let mainRepoStats
let diffRepoStats
let diffs
for (const pkgPaths of [mainRepoPkgPaths, diffRepoPkgPaths]) {
let curStats = {
General: {
buildDuration: null,
buildDurationCached: null,
nodeModulesSize: null,
},
}
// if stats-config is in root of project we're analyzing
// the whole project so copy from each repo
const curStatsAppPath = path.join(diffRepoDir, relativeStatsAppDir)
// clean statsAppDir
await fs.remove(statsAppDir)
await fs.copy(curStatsAppPath, statsAppDir)
logger(`Copying ${curStatsAppPath} ${statsAppDir}`)
// apply config files
for (const configFile of config.configFiles || []) {
const filePath = path.join(statsAppDir, configFile.path)
await fs.writeFile(filePath, configFile.content, 'utf8')
}
// links local builds of the packages and installs dependencies
await linkPkgs(statsAppDir, pkgPaths)
if (!diffing) {
curStats.General.nodeModulesSize = await getDirSize(
path.join(statsAppDir, 'node_modules')
)
}
const buildStart = Date.now()
console.log(
await exec(
`cd ${statsAppDir} && ${statsConfig.appBuildCommand}`,
false,
{
env: yarnEnvValues,
}
)
)
curStats.General.buildDuration = Date.now() - buildStart
// apply renames to get deterministic output names
for (const rename of config.renames) {
const results = await glob(rename.srcGlob, { cwd: statsAppDir })
for (const result of results) {
let dest = rename.removeHash
? result.replace(/(\.|-)[0-9a-f]{16}(\.|-)/g, '$1HASH$2')
: rename.dest
if (result === dest) continue
await fs.move(
path.join(statsAppDir, result),
path.join(statsAppDir, dest)
)
}
}
const collectedStats = await collectStats(config, statsConfig)
for (const key of Object.keys(collectedStats)) {
curStats[key] = Object.assign({}, curStats[key], collectedStats[key])
}
const applyRenames = (renames, stats) => {
if (renames) {
for (const rename of renames) {
let { cur, prev } = rename
cur = path.basename(cur)
prev = path.basename(prev)
Object.keys(stats).forEach((group) => {
if (stats[group][cur]) {
stats[group][prev] = stats[group][cur]
stats[group][prev + ' gzip'] = stats[group][cur + ' gzip']
delete stats[group][cur]
delete stats[group][cur + ' gzip']
}
})
}
}
}
if (mainRepoStats) {
diffRepoStats = curStats
if (!diffing && config.diff !== false) {
for (const groupKey of Object.keys(curStats)) {
if (groupKey === 'General') continue
let changeDetected = config.diff === 'always'
const curDiffs = await collectDiffs(config.filesToTrack)
changeDetected = changeDetected || Object.keys(curDiffs).length > 0
applyRenames(curDiffs._renames, diffRepoStats)
delete curDiffs._renames
if (changeDetected) {
logger('Detected change, running diff')
diffs = await runConfigs(
[
{
...config,
configFiles: config.diffConfigFiles,
},
],
{
statsConfig,
mainRepoPkgPaths,
diffRepoPkgPaths,
relativeStatsAppDir,
},
true
)
delete diffs._renames
break
}
}
}
if (diffing) {
// copy new files and get diff results
return collectDiffs(config.filesToTrack)
}
} else {
// set up diffing folder and copy initial files
await collectDiffs(config.filesToTrack, true)
/* eslint-disable-next-line */
mainRepoStats = curStats
}
const secondBuildStart = Date.now()
console.log(
await exec(
`cd ${statsAppDir} && ${statsConfig.appBuildCommand}`,
false,
{
env: yarnEnvValues,
}
)
)
curStats.General.buildDurationCached = Date.now() - secondBuildStart
}
logger(`Finished running: ${config.title}`)
results.push({
title: config.title,
mainRepoStats,
diffRepoStats,
diffs,
})
}
return results
}
async function linkPkgs(pkgDir = '', pkgPaths) {
await fs.remove(path.join(pkgDir, 'node_modules'))
const pkgJsonPath = path.join(pkgDir, 'package.json')
const pkgData = require(pkgJsonPath)
if (!pkgData.dependencies && !pkgData.devDependencies) return
for (const pkg of pkgPaths.keys()) {
const pkgPath = pkgPaths.get(pkg)
if (pkgData.dependencies && pkgData.dependencies[pkg]) {
pkgData.dependencies[pkg] = pkgPath
} else if (pkgData.devDependencies && pkgData.devDependencies[pkg]) {
pkgData.devDependencies[pkg] = pkgPath
}
}
await fs.writeFile(pkgJsonPath, JSON.stringify(pkgData, null, 2), 'utf8')
await fs.remove(yarnEnvValues.YARN_CACHE_FOLDER)
await exec(
`cd ${pkgDir} && pnpm install --strict-peer-dependencies=false`,
false,
{
env: yarnEnvValues,
}
)
}
module.exports = runConfigs

View file

@ -0,0 +1,38 @@
const logger = require('./logger')
const { promisify } = require('util')
const { exec: execOrig, spawn: spawnOrig } = require('child_process')
const execP = promisify(execOrig)
const env = {
...process.env,
GITHUB_TOKEN: '',
PR_STATS_COMMENT_TOKEN: '',
}
function exec(command, noLog = false, opts = {}) {
if (!noLog) logger(`exec: ${command}`)
return execP(command, {
timeout: 180 * 1000,
...opts,
env: { ...env, ...opts.env },
})
}
exec.spawn = function spawn(command = '', opts = {}) {
logger(`spawn: ${command}`)
const child = spawnOrig('/bin/bash', ['-c', command], {
...opts,
env: {
...env,
...opts.env,
},
stdio: opts.stdio || 'inherit',
})
child.on('exit', (code, signal) => {
logger(`spawn exit (${code}, ${signal}): ${command}`)
})
return child
}
module.exports = exec

View file

@ -0,0 +1,3 @@
const globOrig = require('glob')
const { promisify } = require('util')
module.exports = promisify(globOrig)

View file

@ -0,0 +1,17 @@
function logger(...args) {
console.log(...args)
}
logger.json = (obj) => {
logger('\n', JSON.stringify(obj, null, 2), '\n')
}
logger.error = (...args) => {
console.error(...args)
}
logger.warn = (...args) => {
console.warn(...args)
}
module.exports = logger

45
.github/issue-labeler.yml vendored Normal file
View file

@ -0,0 +1,45 @@
# https://github.com/github/issue-labeler#basic-examples
# Should match the list "Which area(s) of Next.js are affected?" in:
# https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml
'area: app': 'App directory (appDir: true)'
'area: create-next-app': 'CLI (create-next-app)'
'area: data fetching': 'Data fetching (gS(S)P, getInitialProps)'
'area: Edge': 'Middleware / Edge (API routes, runtime)'
'area: ESLint': 'ESLint (eslint-config-next)'
'area: export': 'Static HTML Export (next export)'
'area: Font Optimization': 'Font optimization (@next/font)'
'area: I18n': 'Internationalzation (i18n)'
'area: Jest': 'Jest (next/jest)'
'area: MDX': 'MDX (@next/mdx)'
'area: Metadata': 'Metadata (metadata, generateMetadata, next/head, head.js)'
'area: next/dynamic': 'Dynamic imports (next/dynamic)'
'area: next/image': 'Image optmization (next/image, next/legacy/image)'
'area: next/script': 'Script optimizatzion (next/script)'
'area: package manager': 'Package manager (npm, pnpm, Yarn)'
'area: Routing': 'Routing (next/router, next/navigation, next/link)'
'area: standalone mode': 'Standalone mode (output: "standalone")'
'area: SWC Minify': 'SWC minifier (swcMinify: true)'
'area: SWC transforms': 'SWC transpilation'
'area: Turbopack': 'Turbopack (--turbo)'
'area: TypeScript': 'TypeScript'
# Less used/old/redundant labels
# area: AMP
# area: API routes
# area: Application Code
# area: Codemods
# area: Compiler Performance
# area: Compiler
# area: Concurrent Features
# area: Debugger
# area: Developer Experience
# area: Ecosystem
# area: experimental
# area: Middleware
# area: Reliability
# area: Repository Maintenance
# area: Server Components
# area: Static Generation
# area: styled-jsx
# area: Tracing
# area: URL Imports

65
.github/labeler.json vendored Normal file
View file

@ -0,0 +1,65 @@
{
"labels": {
"area: create-next-app": ["packages/create-next-app/**"],
"area: documentation": ["docs/**", "errors/**"],
"area: examples": ["examples/**"],
"area: next/image": [
"**/*image*",
"**/*image*/**",
"packages/next/src/client/use-intersection.tsx",
"packages/next/src/server/lib/squoosh/",
"packages/next/src/server/serve-static.ts"
],
"area: Font Optimization": ["**/*font*"],
"area: tests": ["test/**", "bench/**"],
"created-by: Chrome Aurora": [
{ "type": "user", "pattern": "atcastle" },
{ "type": "user", "pattern": "devknoll" },
{ "type": "user", "pattern": "housseindjirdeh" },
{ "type": "user", "pattern": "janicklas-ralph" },
{ "type": "user", "pattern": "kara" },
{ "type": "user", "pattern": "kyliau" },
{ "type": "user", "pattern": "spanicker" }
],
"created-by: Next.js team": [
{ "type": "user", "pattern": "acdlite" },
{ "type": "user", "pattern": "balazsorban44" },
{ "type": "user", "pattern": "Brooooooklyn" },
{ "type": "user", "pattern": "feedthejim" },
{ "type": "user", "pattern": "ForsakenHarmony" },
{ "type": "user", "pattern": "gnoff" },
{ "type": "user", "pattern": "hanneslund" },
{ "type": "user", "pattern": "huozhi" },
{ "type": "user", "pattern": "ijjk" },
{ "type": "user", "pattern": "JanKaifer" },
{ "type": "user", "pattern": "kdy1" },
{ "type": "user", "pattern": "kwonoj" },
{ "type": "user", "pattern": "leerob" },
{ "type": "user", "pattern": "padmaia" },
{ "type": "user", "pattern": "sebmarkbage" },
{ "type": "user", "pattern": "shuding" },
{ "type": "user", "pattern": "sokra" },
{ "type": "user", "pattern": "styfle" },
{ "type": "user", "pattern": "timneutkens" },
{ "type": "user", "pattern": "wyattjoh" }
],
"created-by: Next.js docs team": [
{ "type": "user", "pattern": "ismaelrumzan" },
{ "type": "user", "pattern": "MaedahBatool" },
{ "type": "user", "pattern": "molebox" }
],
"type: next": [
"packages/eslint-config-next/**",
"packages/eslint-plugin-next/**",
"packages/font/**",
"packages/next-bundle-analyzer/**",
"packages/next-codemod/**",
"packages/next-env/**",
"packages/next-mdx/**",
"packages/next-swc/**",
"packages/next/**",
"packages/react-dev-overlay/**",
"packages/react-refresh-utils/**"
]
}
}

45
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,45 @@
<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:
## For Contributors
### Improving Documentation or adding/fixing Examples
- The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md
### Fixing a bug
- Related issues linked using `fixes #number`
- Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md
### Adding a feature
- Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md
## For Maintainers
- Minimal description (aim for explaining to someone not on the team to understand the PR)
- When linking to a Slack thread, you might want to share details of the conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic behind a change
### What?
### Why?
### How?
Closes NEXT-
Fixes #
-->

1652
.github/workflows/build_test_deploy.yml vendored Normal file

File diff suppressed because it is too large Load diff

17
.github/workflows/cancel.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Cancel
on:
pull_request_target:
types:
- edited
- synchronize
jobs:
cancel:
name: 'Cancel Previous Runs'
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: styfle/cancel-workflow-action@0.9.1
with:
workflow_id: 444921, 444987
access_token: ${{ github.token }}

21
.github/workflows/issue_labeler.yml vendored Normal file
View file

@ -0,0 +1,21 @@
# https://github.com/github/issue-labeler#create-workflow
name: Label issues - GH Labeler
on:
issues:
types: [opened]
jobs:
triage:
if: |
${{ github.event.label.name == 'template: bug' }}
name: Triage
runs-on: ubuntu-latest
steps:
- uses: github/issue-labeler@v3.0
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
configuration-path: '.github/issue-labeler.yml'
enable-versioned-regex: 0
sync-labels: 0

27
.github/workflows/issue_lock.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: 'Lock Threads'
on:
schedule:
# This runs twice a day: https://crontab.guru/#0_0,12_*_*_*
- cron: '0 0,12 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs:
action:
runs-on: ubuntu-latest
if: github.repository_owner == 'vercel'
steps:
- uses: dessant/lock-threads@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-inactive-days: 30
issue-comment: 'This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.'
pr-inactive-days: 30
log-output: true

14
.github/workflows/issue_on_comment.yml vendored Normal file
View file

@ -0,0 +1,14 @@
name: On issue comment
on:
issue_comment:
types: [created]
jobs:
issue-on-comment:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/issue-on-comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

38
.github/workflows/issue_stale.yml vendored Normal file
View file

@ -0,0 +1,38 @@
name: 'Stale issue handler'
on:
workflow_dispatch:
schedule:
# This runs every day 20 minutes before midnight: https://crontab.guru/#40_23_*_*_*
- cron: '40 23 * * *'
jobs:
stale:
runs-on: ubuntu-latest
if: github.repository_owner == 'vercel'
steps:
- uses: actions/stale@v4
id: stale-no-repro
name: 'Close stale issues with no reproduction'
with:
repo-token: ${{ secrets.STALE_TOKEN }}
only-labels: 'please add a complete reproduction'
close-issue-message: 'This issue has been automatically closed because it received no activity for a month and had no reproduction to investigate. If you think it was closed by accident, please leave a comment. If you are running into a similar issue, please open a new issue with a reproduction. Thank you.'
days-before-issue-close: 1
days-before-issue-stale: 30
days-before-pr-close: -1
days-before-pr-stale: -1
exempt-issue-labels: 'blocked,must,should,keep'
operations-per-run: 300 # 1 operation per 100 issues, the rest is to label/comment/close
- uses: actions/stale@v4
id: stale-no-canary
name: 'Close issues not verified on canary'
with:
repo-token: ${{ secrets.STALE_TOKEN }}
only-labels: 'please verify canary'
close-issue-message: "This issue has been automatically closed because it wasn't verified against next@canary. If you think it was closed by accident, please leave a comment. If you are running into a similar issue, please open a new issue with a reproduction. Thank you."
days-before-issue-close: 1
days-before-issue-stale: 30
days-before-pr-close: -1
days-before-pr-stale: -1
exempt-issue-labels: 'blocked,must,should,keep'
operations-per-run: 300 # 1 operation per 100 issues, the rest is to label/comment/close

17
.github/workflows/issue_validator.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Validate issue
on:
issues:
types: [labeled]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: 'Run issue validator'
run: node ./.github/actions/issue-validator/index.mjs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

31
.github/workflows/notify_release.yml vendored Normal file
View file

@ -0,0 +1,31 @@
# A workflow runs when a release is published, dispatches a new event to the vercel/turbo
# to notify its release. Turbopack, and other integration workflow will subscribe to this event.
name: Notify new Next.js release
on:
release:
types: [published]
jobs:
notify:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v6
id: notify-new-release
with:
result-encoding: string
retries: 3
retry-exempt-status-codes: 400,401
# Default github token cannot dispath events to the remote repo, it should be
# a PAT with access to contenst:read&write + metadata:read.
github-token: ${{ secrets.TURBOPACK_TEST_TOKEN }}
# Note `event_type` and `client_payload` are contract between vercel/turbo,
# if these need to be changed both side should be updated accordingly.
script: |
github.request('POST /repos/{owner}/{repo}/dispatches', {
owner: 'vercel',
repo: 'turbo',
event_type: 'nextjs-release-published',
client_payload: {
version: context.ref
}
})

126
.github/workflows/pull_request_stats.yml vendored Normal file
View file

@ -0,0 +1,126 @@
on:
pull_request:
types: [opened, synchronize]
name: Generate Pull Request Stats
env:
NAPI_CLI_VERSION: 2.14.7
TURBO_VERSION: 1.6.3
RUST_TOOLCHAIN: nightly-2023-03-09
PNPM_VERSION: 7.24.3
jobs:
build-native-dev:
name: Build dev binary for tests
runs-on: ubuntu-latest
steps:
# https://github.com/actions/virtual-environments/issues/1187
- name: tune linux network
run: sudo ethtool -K eth0 tx off rx off
- uses: actions/checkout@v3
with:
fetch-depth: 25
- name: Check non-docs only change
run: echo "DOCS_CHANGE<<EOF" >> $GITHUB_OUTPUT; echo "$(node scripts/run-for-change.js --not --type docs --exec echo 'nope')" >> $GITHUB_OUTPUT; echo 'EOF' >> $GITHUB_OUTPUT
id: docs-change
- name: Cache cargo registry
uses: actions/cache@v3
timeout-minutes: 5
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
with:
path: ~/.cargo/registry
key: stable-ubuntu-latest-node@14-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v3
timeout-minutes: 5
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
with:
path: ~/.cargo/git
key: stable-ubuntu-latest-node@14-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
# We use week in the turbo cache key to keep the cache from infinitely growing
- id: get-week
run: echo "WEEK=$(date +%U)" >> $GITHUB_OUTPUT
- name: Turbo Cache
id: turbo-cache
uses: actions/cache@v3
timeout-minutes: 5
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
with:
path: .turbo
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ steps.get-week.outputs.WEEK }}-${{ github.sha }}
restore-keys: |
turbo-${{ github.job }}-${{ github.ref_name }}-${{ steps.get-week.outputs.WEEK }}-
turbo-${{ github.job }}-canary-${{ steps.get-week.outputs.WEEK }}-
# We use restore-key to pick latest cache.
# We will not get exact match, but doc says
# "If there are multiple partial matches for a restore key, the action returns the most recently created cache."
# So we get latest cache
# - name: Cache built files
# uses: actions/cache@v3
# timeout-minutes: 5
# with:
# path: ./packages/next-target
# key: next-swc-cargo-cache-ubuntu-latest--${{ hashFiles('**/Cargo.lock') }}
# restore-keys: |
# next-swc-cargo-cache-ubuntu-latest
- name: Build in docker
uses: addnab/docker-run-action@v3
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
with:
image: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2022-10-24-x64
options: -e RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }} -e NAPI_CLI_VERSION=${{ env.NAPI_CLI_VERSION }} -e TURBO_VERSION=${{ env.TURBO_VERSION }} -v ${{ env.HOME }}/.cargo/git:/root/.cargo/git -v ${{ env.HOME }}/.cargo/registry:/root/.cargo/registry -v ${{ github.workspace }}:/build -w /build
run: |
set -e &&
rustup toolchain install "${RUST_TOOLCHAIN}" &&
rustup default "${RUST_TOOLCHAIN}" &&
rustup target add x86_64-unknown-linux-gnu &&
npm i -g "@napi-rs/cli@${NAPI_CLI_VERSION}" "turbo@${TURBO_VERSION}" && if [ ! -f $(dirname $(which yarn))/pnpm ]; then ln -s $(which yarn) $(dirname $(which yarn))/pnpm;fi &&
unset CC_x86_64_unknown_linux_gnu && unset CC &&
turbo run build-native --cache-dir=".turbo" -- --target x86_64-unknown-linux-gnu &&
strip packages/next-swc/native/next-swc.*.node
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: next-swc-dev-binary
path: packages/next-swc/native/next-swc.linux-x64-gnu.node
- name: Clear the cargo caches
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
run: |
cargo install cargo-cache --no-default-features --features ci-autoclean
cargo-cache
stats:
name: PR Stats
needs: build-native-dev
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 25
- name: Check non-docs only change
run: echo "DOCS_CHANGE<<EOF" >> $GITHUB_OUTPUT; echo "$(node scripts/run-for-change.js --not --type docs --exec echo 'nope')" >> $GITHUB_OUTPUT; echo 'EOF' >> $GITHUB_OUTPUT
id: docs-change
- uses: actions/download-artifact@v3
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
with:
name: next-swc-dev-binary
path: packages/next-swc/native
- run: cp -r packages/next-swc/native .github/actions/next-stats-action/native
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}
- uses: ./.github/actions/next-stats-action
if: ${{ steps.docs-change.outputs.DOCS_CHANGE == 'nope' }}

52
.github/workflows/test_examples.yml vendored Normal file
View file

@ -0,0 +1,52 @@
# This file duplicates bunch of things from build_test_deploy
on:
workflow_dispatch:
inputs:
is_dispatched:
description: 'Leave this option enabled'
required: true
default: true
type: boolean
schedule:
- cron: '0 */4 * * *'
name: Test examples
env:
PNPM_VERSION: 7.24.3
jobs:
testExamples:
# Don't execute using cron on forks
if: (github.repository == 'vercel/next.js') || (inputs.is_dispatched == true)
name: Test Examples
runs-on: ubuntu-latest
timeout-minutes: 120
env:
NEXT_TELEMETRY_DISABLED: 1
strategy:
fail-fast: false
matrix:
node: [16, 18]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 25
# https://github.com/actions/virtual-environments/issues/1187
- name: tune linux network
run: sudo ethtool -K eth0 tx off rx off
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 16
check-latest: true
- run: npm i -g pnpm@${PNPM_VERSION}
- run: pnpm install
- run: pnpm build
- run: docker run --rm -v $(pwd):/work mcr.microsoft.com/playwright:v1.28.1-focal /bin/bash -c "cd /work && curl -s https://install-node.vercel.app/v${{ matrix.node }} | FORCE=1 bash && node -v && npm i -g pnpm@${PNPM_VERSION} > /dev/null && NEXT_TEST_JOB=1 NEXT_TEST_MODE=start xvfb-run node run-tests.js --type examples >> /proc/1/fd/1"
name: Run test/examples

53
.gitignore vendored Normal file
View file

@ -0,0 +1,53 @@
# build output
dist
.next
target
packages/next/wasm/@next
packages/*/packed-*.tgz
# dependencies
node_modules
package-lock.json
yarn.lock
!/yarn.lock
test/node_modules
.pnpm-store/
# logs & pids
*.log
pids
*.cpuprofile
# coverage
.nyc_output
coverage
# test output
test/**/out*
test/**/next-env.d.ts
.DS_Store
/e2e-tests
test/tmp/**
test/.trace
test/traces
# Editors
**/.idea
**/.#*
.nvmrc
# examples
examples/**/out
examples/**/.env*.local
pr-stats.md
test-timings.json
# Vercel
.vercel
.now
# Cache
*.tsbuildinfo
.swc/
.turbo

4
.husky/pre-commit Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm lint-staged

5
.npmrc Normal file
View file

@ -0,0 +1,5 @@
save-exact = true
tag-version-prefix=""
strict-peer-dependencies = false
auto-install-peers = true
lockfile = true

29
.prettierignore Normal file
View file

@ -0,0 +1,29 @@
node_modules
**/.next/**
**/_next/**
**/dist/**
packages/next/src/bundles/webpack/packages/*.runtime.js
packages/next/src/bundles/webpack/packages/lazy-compilation-*.js
packages/next/src/compiled/**
packages/react-refresh-utils/**/*.js
packages/react-refresh-utils/**/*.d.ts
packages/react-dev-overlay/lib/**
**/__tmp__/**
lerna.json
.github/actions/next-stats-action/.work
.github/actions/issue-validator/index.mjs
packages/next-swc/crates/**/*
packages/next-swc/target/**/*
packages/next-swc/native/**/*
packages/next-codemod/transforms/__testfixtures__/**/*
packages/next-codemod/transforms/__tests__/**/*
packages/next-codemod/**/*.js
packages/next-codemod/**/*.d.ts
packages/next-env/**/*.d.ts
test-timings.json
test/**/out/**
test/development/basic/hmr/components/parse-error.js
bench/nested-deps/pages/**/*
bench/nested-deps/components/**/*
pnpm-lock.yaml
**/convex/_generated/**

13
.prettierignore_staged Normal file
View file

@ -0,0 +1,13 @@
**/.next/**
**/_next/**
**/dist/**
packages/next-swc/crates/**
packages/next/src/compiled/**/*
packages/next/bundles/webpack/packages/*.runtime.js
lerna.json
packages/next-codemod/transforms/__testfixtures__/**/*
packages/next-codemod/transforms/__tests__/**/*
test/development/basic/hmr/components/parse-error.js
pnpm-lock.yaml
.github/actions/issue-validator/index.mjs
**/convex/_generated/**

4
.prettierrc.json Normal file
View file

@ -0,0 +1,4 @@
{
"singleQuote": true,
"semi": false
}

24
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,24 @@
{
"recommendations": [
// Linting / Formatting
"rust-lang.rust-analyzer",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"usernamehw.errorlens",
// Testing
"orta.vscode-jest",
// PR management / Reviewing
"github.vscode-pull-request-github",
// Showing todo comments
"gruntfuggly.todo-tree",
// Collaborating
"ms-vsliveshare.vsliveshare",
// Debugging
"ms-vscode.vscode-js-profile-flame"
]
}

102
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,102 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch app-dir development",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["debug", "dev", "test/e2e/app-dir/app"],
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
},
{
"name": "Launch app-dir build",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["debug", "build", "test/e2e/app-dir/app"],
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
},
{
"name": "Launch app development",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["debug", "dev", "examples/hello-world"],
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
},
{
"name": "Launch app build",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["debug", "build", "examples/hello-world"],
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
},
{
"name": "Launch app production",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["debug", "start", "examples/hello-world"],
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
},
{
"name": "Launch current directory in development",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["debug", "dev", "${fileDirname}"],
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
},
{
"name": "Launch app build trace jaeger",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["clean-trace-jaeger"],
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
},
{
"type": "node",
"request": "attach",
"name": "Attach to existing debugger",
"port": 9229,
"skipFiles": ["<node_internals>/**"],
"env": {
"NEXT_PRIVATE_LOCAL_WEBPACK": "1"
}
}
]
}

61
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,61 @@
{
// Formatting using Prettier by default for all languages
"editor.defaultFormatter": "esbenp.prettier-vscode",
// Formatting using Prettier for JavaScript, overrides VSCode default.
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Formatting using Rust-Analyzer for Rust.
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
},
// Linting using ESLint.
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
// Disable Jest autoRun as otherwise it will start running all tests the first time.
"jest.autoRun": "off",
// Debugging.
"debug.javascript.unmapMissingSources": true,
"files.exclude": {
"**/node_modules": false,
"node_modules": true,
"*[!test]**/node_modules": true
},
// Ensure enough terminal history is preserved when running tests.
"terminal.integrated.scrollback": 10000,
// Configure todo-tree to exclude node_modules, dist, and compiled.
"todo-tree.filtering.excludeGlobs": [
"**/node_modules",
"**/dist",
"**/compiled"
],
// Match TODO-APP in addition to other TODOs.
"todo-tree.general.tags": [
"BUG",
"HACK",
"FIXME",
"TODO",
"XXX",
"[ ]",
"[x]",
"TODO-APP"
],
// Disable TypeScript surveys.
"typescript.surveys.enabled": false,
// Enable file nesting for unit test files.
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"*.ts": "$(capture).test.ts, $(capture).test.tsx",
"*.tsx": "$(capture).test.ts, $(capture).test.tsx"
}
}

53
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,53 @@
## Code of Conduct
### Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
### Our Standards
Examples of behavior that contributes to a positive environment for our community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others private information, such as a physical or email address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
### Enforcement Responsibilities
Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
### Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project team responsible for enforcement at [coc@vercel.com](mailto:coc@vercel.com). All complaints will be reviewed and investigated promptly and fairly.
All project maintainers are obligated to respect the privacy and security of the reporter of any incident.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1,
available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct/][version]
[homepage]: http://contributor-covenant.org
[version]: https://www.contributor-covenant.org/version/2/1

1
UPGRADING.md Normal file
View file

@ -0,0 +1 @@
This document has been moved to [nextjs.org/docs/upgrading](https://nextjs.org/docs/upgrading). It's also available in this repository on [/docs/upgrading.md](/docs/upgrading.md).

182
azure-pipelines.yml Normal file
View file

@ -0,0 +1,182 @@
trigger:
# Only run latest commit for branches:
batch: true
# Do not run Azure CI for docs-only/example-only changes:
paths:
include:
- '*'
exclude:
- bench
- docs
- errors
- examples
# Do not run Azure on `canary`, `main`, or release tags. This unnecessarily
# increases the backlog, and the change was already tested on the PR.
branches:
include:
- '*'
exclude:
- canary
- main
- refs/tags/*
pr:
# Do not run Azure CI for docs-only/example-only changes:
paths:
include:
- '*'
exclude:
- bench
- docs
- errors
- examples
variables:
PNPM_CACHE_FOLDER: $(Pipeline.Workspace)/.pnpm-store
PNPM_VERSION: 7.24.3
NEXT_TELEMETRY_DISABLED: '1'
node_14_version: ^14.19.0
node_16_version: ^16.8.0
stages:
- stage: Test
jobs:
- job: test_integration
pool:
vmImage: 'windows-2019'
steps:
- task: NodeTool@0
inputs:
versionSpec: $(node_14_version)
displayName: 'Install Node.js'
- bash: |
node scripts/run-for-change.js --not --type docs --exec echo "##vso[task.setvariable variable=isDocsOnly]No"
displayName: 'Check Docs Only Change'
- script: npm i -g pnpm@$(PNPM_VERSION)
condition: eq(variables['isDocsOnly'], 'No')
- script: pnpm config set store-dir $(PNPM_CACHE_FOLDER)
condition: eq(variables['isDocsOnly'], 'No')
- script: pnpm store path
condition: eq(variables['isDocsOnly'], 'No')
- script: pnpm install && pnpm run build
condition: eq(variables['isDocsOnly'], 'No')
displayName: 'Install and build'
- script: npx playwright@1.28.1 install chromium
condition: eq(variables['isDocsOnly'], 'No')
- script: |
node run-tests.js -c 1 test/integration/production/test/index.test.js test/integration/css-client-nav/test/index.test.js test/integration/rewrites-has-condition/test/index.test.js
condition: eq(variables['isDocsOnly'], 'No')
displayName: 'Run tests'
- job: test_unit
pool:
vmImage: 'windows-2019'
steps:
- script: |
wmic datafile where name="C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe" get Version /value
displayName: 'List Chrome version'
- task: NodeTool@0
inputs:
versionSpec: $(node_14_version)
displayName: 'Install Node.js'
- bash: |
node scripts/run-for-change.js --not --type docs --exec echo "##vso[task.setvariable variable=isDocsOnly]No"
displayName: 'Check Docs Only Change'
- script: npm i -g pnpm@$(PNPM_VERSION)
condition: eq(variables['isDocsOnly'], 'No')
- script: pnpm config set store-dir $(PNPM_CACHE_FOLDER)
condition: eq(variables['isDocsOnly'], 'No')
- script: pnpm store path
condition: eq(variables['isDocsOnly'], 'No')
- script: pnpm install && pnpm run build
condition: eq(variables['isDocsOnly'], 'No')
displayName: 'Install and build'
- script: node run-tests.js --type unit
condition: eq(variables['isDocsOnly'], 'No')
displayName: 'Run tests'
# - job: test_e2e_dev
# pool:
# vmImage: 'windows-2019'
# steps:
# - task: NodeTool@0
# inputs:
# versionSpec: $(node_16_version)
# displayName: 'Install Node.js'
# - bash: |
# node scripts/run-for-change.js --not --type docs --exec echo "##vso[task.setvariable variable=isDocsOnly]No"
# displayName: 'Check Docs Only Change'
# - script: npm i -g pnpm@$(PNPM_VERSION)
# condition: eq(variables['isDocsOnly'], 'No')
# - script: pnpm config set store-dir $(PNPM_CACHE_FOLDER)
# condition: eq(variables['isDocsOnly'], 'No')
# - script: pnpm store path
# condition: eq(variables['isDocsOnly'], 'No')
# - script: pnpm install && pnpm run build
# condition: eq(variables['isDocsOnly'], 'No')
# displayName: 'Install and build'
# - script: npx playwright@1.28.1 install chromium
# condition: eq(variables['isDocsOnly'], 'No')
# - script: |
# node run-tests.js -c 1 --debug test/e2e/app-dir/app/index.test.ts
# condition: eq(variables['isDocsOnly'], 'No')
# displayName: 'Run tests (E2E Development)'
# env:
# NEXT_TEST_MODE: 'dev'
# - job: test_e2e_prod
# pool:
# vmImage: 'windows-2019'
# steps:
# - task: NodeTool@0
# inputs:
# versionSpec: $(node_16_version)
# displayName: 'Install Node.js'
# - bash: |
# node scripts/run-for-change.js --not --type docs --exec echo "##vso[task.setvariable variable=isDocsOnly]No"
# displayName: 'Check Docs Only Change'
# - script: npm i -g pnpm@$(PNPM_VERSION)
# condition: eq(variables['isDocsOnly'], 'No')
# - script: pnpm config set store-dir $(PNPM_CACHE_FOLDER)
# condition: eq(variables['isDocsOnly'], 'No')
# - script: pnpm store path
# condition: eq(variables['isDocsOnly'], 'No')
# - script: pnpm install && pnpm run build
# condition: eq(variables['isDocsOnly'], 'No')
# displayName: 'Install and build'
# - script: npx playwright@1.28.1 install chromium
# condition: eq(variables['isDocsOnly'], 'No')
# - script: |
# node run-tests.js -c 1 --debug test/e2e/app-dir/app/index.test.ts
# condition: eq(variables['isDocsOnly'], 'No')
# displayName: 'Run tests (E2E Production)'
# env:
# NEXT_TEST_MODE: 'start'

View file

@ -0,0 +1,10 @@
import * as React from 'react'
export default function Root({ children }) {
return (
<html>
<head></head>
<body>{children}</body>
</html>
)
}

View file

@ -0,0 +1,5 @@
import * as React from 'react'
export default function page() {
return <div>hello</div>
}

View file

@ -0,0 +1,5 @@
module.exports = {
experimental: {
appDir: true,
},
}

View file

@ -0,0 +1,14 @@
{
"name": "stats-app",
"private": true,
"license": "MIT",
"dependencies": {
"webpack-bundle-analyzer": "^4.6.1",
"webpack-stats-plugin": "^1.1.0"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}

View file

@ -0,0 +1,9 @@
import * as React from 'react'
export default function page() {
return <div> hello world </div>
}
export async function getServerSideProps() {
return {}
}

View file

@ -0,0 +1,7 @@
{
"name": "next-minimal-server",
"description": "Minimal server for Next.js for benchmarking/perf analysis purposes.",
"scripts": {
"start": "node start.js"
}
}

View file

@ -0,0 +1,39 @@
process.env.NODE_ENV = 'production'
require('../../test/lib/react-channel-require-hook')
console.time('next-cold-start')
const NextServer = require('next/dist/server/next-server').default
const path = require('path')
const appDir = path.join(__dirname, 'benchmark-app')
const distDir = '.next'
const compiledConfig = require(path.join(
appDir,
distDir,
'required-server-files.json'
)).config
process.chdir(appDir)
const nextServer = new NextServer({
conf: compiledConfig,
dir: appDir,
distDir,
minimalMode: true,
customServer: false,
})
const requestHandler = nextServer.getRequestHandler()
require('http')
.createServer((req, res) => {
console.time('next-request')
return requestHandler(req, res).finally(() => {
console.timeEnd('next-request')
})
})
.listen(3000, () => {
console.timeEnd('next-cold-start')
})

2
bench/nested-deps/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
components/*
CPU*

253
bench/nested-deps/bench.mjs Normal file
View file

@ -0,0 +1,253 @@
import { execSync, spawn } from 'child_process'
import { join } from 'path'
import { fileURLToPath } from 'url'
import fetch from 'node-fetch'
import {
existsSync,
readFileSync,
writeFileSync,
unlinkSync,
promises as fs,
} from 'fs'
import prettyMs from 'pretty-ms'
import treeKill from 'tree-kill'
const ROOT_DIR = join(fileURLToPath(import.meta.url), '..', '..', '..')
const CWD = join(ROOT_DIR, 'bench', 'nested-deps')
const NEXT_BIN = join(ROOT_DIR, 'packages', 'next', 'dist', 'bin', 'next')
const [, , command = 'all'] = process.argv
async function killApp(instance) {
await new Promise((resolve, reject) => {
treeKill(instance.pid, (err) => {
if (err) {
if (
process.platform === 'win32' &&
typeof err.message === 'string' &&
(err.message.includes(`no running instance of the task`) ||
err.message.includes(`not found`))
) {
// Windows throws an error if the process is already stopped
//
// Command failed: taskkill /pid 6924 /T /F
// ERROR: The process with PID 6924 (child process of PID 6736) could not be terminated.
// Reason: There is no running instance of the task.
return resolve()
}
return reject(err)
}
resolve()
})
})
}
class File {
constructor(path) {
this.path = path
this.originalContent = existsSync(this.path)
? readFileSync(this.path, 'utf8')
: null
}
write(content) {
if (!this.originalContent) {
this.originalContent = content
}
writeFileSync(this.path, content, 'utf8')
}
replace(pattern, newValue) {
const currentContent = readFileSync(this.path, 'utf8')
if (pattern instanceof RegExp) {
if (!pattern.test(currentContent)) {
throw new Error(
`Failed to replace content.\n\nPattern: ${pattern.toString()}\n\nContent: ${currentContent}`
)
}
} else if (typeof pattern === 'string') {
if (!currentContent.includes(pattern)) {
throw new Error(
`Failed to replace content.\n\nPattern: ${pattern}\n\nContent: ${currentContent}`
)
}
} else {
throw new Error(`Unknown replacement attempt type: ${pattern}`)
}
const newContent = currentContent.replace(pattern, newValue)
this.write(newContent)
}
prepend(line) {
const currentContent = readFileSync(this.path, 'utf8')
this.write(line + '\n' + currentContent)
}
delete() {
unlinkSync(this.path)
}
restore() {
this.write(this.originalContent)
}
}
function runNextCommandDev(argv, opts = {}) {
const env = {
...process.env,
NODE_ENV: undefined,
__NEXT_TEST_MODE: 'true',
FORCE_COLOR: 3,
...opts.env,
}
const nodeArgs = opts.nodeArgs || []
return new Promise((resolve, reject) => {
const instance = spawn(NEXT_BIN, [...nodeArgs, ...argv], {
cwd: CWD,
env,
})
let didResolve = false
function handleStdout(data) {
const message = data.toString()
const bootupMarkers = {
dev: /compiled .*successfully/i,
start: /started server/i,
}
if (
(opts.bootupMarker && opts.bootupMarker.test(message)) ||
bootupMarkers[opts.nextStart ? 'start' : 'dev'].test(message)
) {
if (!didResolve) {
didResolve = true
resolve(instance)
instance.removeListener('data', handleStdout)
}
}
if (typeof opts.onStdout === 'function') {
opts.onStdout(message)
}
if (opts.stdout !== false) {
process.stdout.write(message)
}
}
function handleStderr(data) {
const message = data.toString()
if (typeof opts.onStderr === 'function') {
opts.onStderr(message)
}
if (opts.stderr !== false) {
process.stderr.write(message)
}
}
instance.stdout.on('data', handleStdout)
instance.stderr.on('data', handleStderr)
instance.on('close', () => {
instance.stdout.removeListener('data', handleStdout)
instance.stderr.removeListener('data', handleStderr)
if (!didResolve) {
didResolve = true
resolve()
}
})
instance.on('error', (err) => {
reject(err)
})
})
}
function waitFor(millis) {
return new Promise((resolve) => setTimeout(resolve, millis))
}
await fs.rm('.next', { recursive: true }).catch(() => {})
const file = new File(join(CWD, 'pages/index.jsx'))
const results = []
try {
if (command === 'dev' || command === 'all') {
const instance = await runNextCommandDev(['dev', '--port', '3000'])
function waitForCompiled() {
return new Promise((resolve) => {
function waitForOnData(data) {
const message = data.toString()
const compiledRegex =
/compiled client and server successfully in (\d*[.]?\d+)\s*(m?s) \((\d+) modules\)/gm
const matched = compiledRegex.exec(message)
if (matched) {
resolve({
'time (ms)': (matched[2] === 's' ? 1000 : 1) * Number(matched[1]),
modules: Number(matched[3]),
})
instance.stdout.removeListener('data', waitForOnData)
}
}
instance.stdout.on('data', waitForOnData)
})
}
const [res, initial] = await Promise.all([
fetch('http://localhost:3000/'),
waitForCompiled(),
])
if (res.status !== 200) {
throw new Error('Fetching / failed')
}
results.push(initial)
file.prepend('// First edit')
results.push(await waitForCompiled())
await waitFor(1000)
file.prepend('// Second edit')
results.push(await waitForCompiled())
await waitFor(1000)
file.prepend('// Third edit')
results.push(await waitForCompiled())
console.table(results)
await killApp(instance)
}
if (command === 'build' || command === 'all') {
// ignore error
await fs.rm('.next', { recursive: true, force: true }).catch(() => {})
execSync(`node ${NEXT_BIN} build ./bench/nested-deps`, {
cwd: ROOT_DIR,
stdio: 'inherit',
env: {
...process.env,
TRACE_TARGET: 'jaeger',
},
})
const traceString = await fs.readFile(join(CWD, '.next', 'trace'), 'utf8')
const traces = traceString
.split('\n')
.filter((line) => line)
.map((line) => JSON.parse(line))
const { duration } = traces.pop().find(({ name }) => name === 'next-build')
console.info('next build duration: ', prettyMs(duration / 1000))
}
} finally {
file.restore()
}

182
bench/nested-deps/fuzzponent.js Executable file
View file

@ -0,0 +1,182 @@
#!/usr/bin/env node
const path = require('path')
const fs = require('fs')
const getSequenceGenerator = require('random-seed')
const generate = require('@babel/generator').default
const t = require('@babel/types')
const MIN_COMPONENT_NAME_LEN = 18
const MAX_COMPONENT_NAME_LEN = 24
const MIN_CHILDREN = 4
const MAX_CHILDREN = 80
const arrayUntil = (len) => [...Array(len)].map((_, i) => i)
const generateFunctionalComponentModule = (componentName, children = []) => {
const body = [
generateImport('React', 'react'),
...children.map((childName) => generateImport(childName, `./${childName}`)),
t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(componentName),
t.arrowFunctionExpression(
[],
t.parenthesizedExpression(
generateJSXElement(
'div',
children.map((childName) => generateJSXElement(childName))
)
)
)
),
]),
t.exportDefaultDeclaration(t.identifier(componentName)),
]
return t.program(body, [], 'module')
}
const generateJSXElement = (componentName, children = null) =>
t.JSXElement(
t.JSXOpeningElement(t.JSXIdentifier(componentName), [], !children),
children ? t.JSXClosingElement(t.JSXIdentifier(componentName)) : null,
children || [],
!children
)
const generateImport = (componentName, requireString) =>
t.importDeclaration(
[t.importDefaultSpecifier(t.identifier(componentName))],
t.stringLiteral(requireString)
)
const validFirstChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const validOtherChars = validFirstChars.toLowerCase()
function generateComponentName(seqGenerator, opts) {
const numOtherChars = seqGenerator.intBetween(opts.minLen, opts.maxLen)
const firstChar = validFirstChars[seqGenerator.range(validFirstChars.length)]
const otherChars = arrayUntil(numOtherChars).map(
() => validOtherChars[seqGenerator.range(validOtherChars.length)]
)
return `${firstChar}${otherChars.join('')}`
}
function* generateModules(name, remainingDepth, seqGenerator, opts) {
const filename = `${name}.${opts.extension}`
let ast
if (name === 'index') {
name = 'RootComponent'
}
if (remainingDepth === 0) {
ast = generateFunctionalComponentModule(name)
} else {
const numChildren = seqGenerator.intBetween(opts.minChild, opts.maxChild)
const children = arrayUntil(numChildren).map(() =>
generateComponentName(seqGenerator, opts)
)
ast = generateFunctionalComponentModule(name, children)
for (const child of children) {
yield* generateModules(child, remainingDepth - 1, seqGenerator, opts)
}
}
yield {
filename,
content: generate(ast).code,
}
}
function generateFuzzponents(outdir, seed, depth, opts) {
const seqGenerator = getSequenceGenerator(seed)
const filenames = new Set()
for (const { filename, content } of generateModules(
'index',
depth,
seqGenerator,
opts
)) {
if (filenames.has(filename)) {
throw new Error(
`Seed "${seed}" generates output with filename collisions.`
)
} else {
filenames.add(filename)
}
const fpath = path.join(outdir, filename)
fs.writeFileSync(fpath, `// ${filename}\n\n${content}`)
}
}
if (require.main === module) {
const { outdir, seed, depth, ...opts } = require('yargs')
.option('depth', {
alias: 'd',
demandOption: true,
describe: 'component hierarchy depth',
type: 'number',
})
.option('seed', {
alias: 's',
demandOption: true,
describe: 'prng seed',
type: 'number',
})
.option('outdir', {
alias: 'o',
demandOption: false,
default: process.cwd(),
describe: 'the directory where components should be written',
type: 'string',
normalize: true,
})
.option('minLen', {
demandOption: false,
default: MIN_COMPONENT_NAME_LEN,
describe: 'the smallest acceptable component name length',
type: 'number',
})
.option('maxLen', {
demandOption: false,
default: MAX_COMPONENT_NAME_LEN,
describe: 'the largest acceptable component name length',
type: 'number',
})
.option('minLen', {
demandOption: false,
default: MIN_COMPONENT_NAME_LEN,
describe: 'the smallest acceptable component name length',
type: 'number',
})
.option('maxLen', {
demandOption: false,
default: MAX_COMPONENT_NAME_LEN,
describe: 'the largest acceptable component name length',
type: 'number',
})
.option('minChild', {
demandOption: false,
default: MIN_CHILDREN,
describe: 'the smallest number of acceptable component children',
type: 'number',
})
.option('maxChild', {
demandOption: false,
default: MAX_CHILDREN,
describe: 'the largest number of acceptable component children',
type: 'number',
})
.option('extension', {
default: 'jsx',
describe: 'extension to use for generated components',
type: 'string',
}).argv
generateFuzzponents(outdir, seed, depth, opts)
}
module.exports = generateFuzzponents

View file

@ -0,0 +1,9 @@
const idx = process.execArgv.indexOf('--cpu-prof')
if (idx >= 0) process.execArgv.splice(idx, 1)
module.exports = {
eslint: {
ignoreDuringBuilds: true,
},
swcMinify: true,
}

View file

@ -0,0 +1,20 @@
{
"scripts": {
"prepare": "rimraf components && mkdir components && node ./fuzzponent.js -d 2 -s 206 -o components",
"dev": "cross-env NEXT_PRIVATE_LOCAL_WEBPACK=1 node ../../node_modules/next/dist/bin/next dev",
"build": "cross-env NEXT_PRIVATE_LOCAL_WEBPACK=1 node ../../node_modules/next/dist/bin/next build",
"start": "cross-env NEXT_PRIVATE_LOCAL_WEBPACK=1 node ../../node_modules/next/dist/bin/next start",
"dev-nocache": "rimraf .next && yarn dev",
"dev-cpuprofile-nocache": "rimraf .next && cross-env NEXT_PRIVATE_LOCAL_WEBPACK=1 node --cpu-prof ../../node_modules/next/dist/bin/next",
"build-nocache": "rimraf .next && yarn build"
},
"devDependencies": {
"@babel/types": "7.18.0",
"@babel/generator": "7.18.0",
"random-seed": "0.3.0",
"cross-env": "^7.0.3",
"pretty-ms": "^7.0.1",
"rimraf": "^3.0.2",
"yargs": "16.2.0"
}
}

View file

@ -0,0 +1,5 @@
import Comp from '../components/index.jsx'
export default function Home() {
return <Comp />
}

1
bench/readdir/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
fixtures

View file

@ -0,0 +1,4 @@
# Uses https://github.com/divmain/fuzzponent
mkdir fixtures
cd fixtures
fuzzponent -d 2 -s 20

24
bench/readdir/glob.js Normal file
View file

@ -0,0 +1,24 @@
import { join } from 'path'
import { promisify } from 'util'
import globMod from 'glob'
const glob = promisify(globMod)
const resolveDataDir = join(__dirname, 'fixtures', '**/*')
async function test() {
const time = process.hrtime()
await glob(resolveDataDir)
const hrtime = process.hrtime(time)
const nanoseconds = hrtime[0] * 1e9 + hrtime[1]
const milliseconds = nanoseconds / 1e6
console.log(milliseconds)
}
async function run() {
for (let i = 0; i < 50; i++) {
await test()
}
}
run()

View file

@ -0,0 +1,21 @@
import { join } from 'path'
import { recursiveReadDir } from 'next/dist/lib/recursive-readdir'
const resolveDataDir = join(__dirname, 'fixtures')
async function test() {
const time = process.hrtime()
await recursiveReadDir(resolveDataDir, /\.js$/)
const hrtime = process.hrtime(time)
const nanoseconds = hrtime[0] * 1e9 + hrtime[1]
const milliseconds = nanoseconds / 1e6
console.log(milliseconds)
}
async function run() {
for (let i = 0; i < 50; i++) {
await test()
}
}
run()

View file

@ -0,0 +1,59 @@
import { join } from 'path'
import { ensureDir, outputFile, remove } from 'fs-extra'
import recursiveCopyNpm from 'recursive-copy'
import { recursiveCopy as recursiveCopyCustom } from 'next/dist/lib/recursive-copy'
const fixturesDir = join(__dirname, 'fixtures')
const srcDir = join(fixturesDir, 'src')
const destDir = join(fixturesDir, 'dest')
const createSrcFolder = async () => {
await ensureDir(srcDir)
const files = new Array(100)
.fill(undefined)
.map((_, i) =>
join(srcDir, `folder${i % 5}`, `folder${i + (1 % 5)}`, `file${i}`)
)
await Promise.all(files.map((file) => outputFile(file, 'hello')))
}
async function run(fn) {
async function test() {
const start = process.hrtime()
await fn(srcDir, destDir)
const timer = process.hrtime(start)
const ms = (timer[0] * 1e9 + timer[1]) / 1e6
return ms
}
const ts = []
for (let i = 0; i < 10; i++) {
const t = await test()
await remove(destDir)
ts.push(t)
}
const sum = ts.reduce((a, b) => a + b)
const nb = ts.length
const avg = sum / nb
console.log({ sum, nb, avg })
}
async function main() {
await createSrcFolder()
console.log('test recursive-copy npm module')
await run(recursiveCopyNpm)
console.log('test recursive-copy custom implementation')
await run(recursiveCopyCustom)
await remove(fixturesDir)
}
main()

1
bench/recursive-delete/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
fixtures-*

View file

@ -0,0 +1,15 @@
import { join } from 'path'
import { recursiveDelete } from 'next/dist/lib/recursive-delete'
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`)
async function test() {
const time = process.hrtime()
await recursiveDelete(resolveDataDir)
const hrtime = process.hrtime(time)
const nanoseconds = hrtime[0] * 1e9 + hrtime[1]
const milliseconds = nanoseconds / 1e6
console.log(milliseconds)
}
test()

View file

@ -0,0 +1,18 @@
import { join } from 'path'
import { promisify } from 'util'
import rimrafMod from 'rimraf'
const rimraf = promisify(rimrafMod)
const resolveDataDir = join(__dirname, `fixtures-${process.argv[2]}`, '**/*')
async function test() {
const time = process.hrtime()
await rimraf(resolveDataDir)
const hrtime = process.hrtime(time)
const nanoseconds = hrtime[0] * 1e9 + hrtime[1]
const milliseconds = nanoseconds / 1e6
console.log(milliseconds)
}
test()

69
bench/recursive-delete/run.sh Executable file
View file

@ -0,0 +1,69 @@
# Uses https://github.com/divmain/fuzzponent
mkdir fixtures-1
cd fixtures-1
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 1"
node rimraf.js 1
mkdir fixtures-2
cd fixtures-2
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 2"
node rimraf.js 2
mkdir fixtures-3
cd fixtures-3
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 3"
node rimraf.js 3
mkdir fixtures-4
cd fixtures-4
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 4"
node rimraf.js 4
mkdir fixtures-5
cd fixtures-5
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "rimraf 5"
node rimraf.js 5
echo "-----------"
cd fixtures-1
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 1"
node recursive-delete.js 1
cd fixtures-2
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 2"
node recursive-delete.js 2
cd fixtures-3
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 3"
node recursive-delete.js 3
cd fixtures-4
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 4"
node recursive-delete.js 4
cd fixtures-5
fuzzponent -d 2 -s 20 > output.txt
cd ..
echo "recursive delete 5"
node recursive-delete.js 5
rm -r fixtures-1 fixtures-2 fixtures-3 fixtures-4 fixtures-5

View file

@ -0,0 +1,14 @@
{
"name": "next-bench",
"scripts": {
"build": "next build",
"start": "NODE_ENV=production npm run build && NODE_ENV=production next start",
"bench:stateless": "ab -c1 -n3000 http://0.0.0.0:3000/stateless",
"bench:stateless-big": "ab -c1 -n500 http://0.0.0.0:3000/stateless-big",
"bench:recursive-copy": "node recursive-copy/run"
},
"dependencies": {
"fs-extra": "10.0.0",
"recursive-copy": "2.0.11"
}
}

View file

@ -0,0 +1,13 @@
import React from 'react'
export default () => {
return <ul>{items()}</ul>
}
const items = () => {
var out = new Array(10000)
for (let i = 0; i < out.length; i++) {
out[i] = <li key={i}>This is row {i + 1}</li>
}
return out
}

Some files were not shown because too many files have changed in this diff Show more