├── .editorconfig
├── .eslintrc.js
├── .github
└── workflows
│ ├── default-branch-migration.yml
│ ├── props-bot.yml
│ └── test.yml
├── .gitignore
├── .jshintrc
├── .npmpackagejsonlintrc.json
├── .nvmrc
├── .prettierrc.js
├── CONTRIBUTING.md
├── LICENSE-MIT
├── README.md
├── RELEASING.md
├── lib
├── map_old_to_new_file_path.js
├── patch.js
├── regex.js
└── trac.js
├── package-lock.json
├── package.json
├── tasks
└── patch_wordpress.js
└── test
├── .eslintrc.js
├── expected
├── custom_options
├── default_options
├── patch_wordpress_1.diff
├── patch_wordpress_2.diff
├── patch_wordpress_3.diff
├── patch_wordpress_4.diff
├── patch_wordpress_5.diff
├── patch_wordpress_6.diff
└── patch_wordpress_7.diff
├── fixtures
├── 23988.html
├── 23989.html
├── 23994.html
├── 26602.2.diff
├── core.git.diff
├── core.git.index.diff
├── core.svn.diff
├── core.svn.index.diff
├── core.svn.trunk.diff
├── develop.git.diff
├── develop.git.index.diff
├── develop.git.wp-config-sample.diff
├── develop.svn.diff
├── develop.svn.index.diff
├── develop.svn.wp-config-sample.diff
├── git.diff.ab.diff
├── patch_wordpress_1.diff
├── patch_wordpress_2.diff
├── patch_wordpress_3.diff
├── patch_wordpress_4.diff
├── patch_wordpress_5.diff
├── patch_wordpress_6.diff
├── patch_wordpress_7.diff
├── tests.develop.git.diff
└── tests.develop.svn.diff
├── patch_wordpress_test.js
├── patches.js
└── regex.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 |
4 | # WordPress Coding Standards
5 | # https://make.wordpress.org/core/handbook/coding-standards/
6 |
7 | root = true
8 |
9 | [*]
10 | charset = utf-8
11 | end_of_line = lf
12 | insert_final_newline = true
13 | trim_trailing_whitespace = true
14 | indent_style = tab
15 |
16 | [*.yml]
17 | indent_style = space
18 | indent_size = 2
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | es6: true,
5 | node: true,
6 | },
7 | extends: 'plugin:@wordpress/eslint-plugin/recommended',
8 | rules: {
9 | 'one-var': [ 'error', 'never' ],
10 | 'prefer-arrow-callback': [ 'error' ],
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/.github/workflows/default-branch-migration.yml:
--------------------------------------------------------------------------------
1 | name: Default Branch Migration
2 | on: [push]
3 | jobs:
4 | migrate_branch:
5 | name: Migrate Branch
6 | runs-on: ubuntu-latest
7 | steps:
8 | - name: Migrate
9 | uses: liyanchang/default-branch-migration@v1.0.1
10 | with:
11 | # GitHub will fill in this template with the correct token
12 | # You don't need to edit this line
13 | github_token: ${{ secrets.GITHUB_TOKEN }}
14 | # TODO: Change this to the default branch you want to migrate away from
15 | previous_default: master
16 | # TODO: Change this to the default branch you want to migrate away to
17 | new_default: trunk
18 |
--------------------------------------------------------------------------------
/.github/workflows/props-bot.yml:
--------------------------------------------------------------------------------
1 | name: Props Bot
2 |
3 | on:
4 | # This event runs anytime a PR is (re)opened, updated, marked ready for review, or labeled.
5 | # GitHub does not allow filtering the `labeled` event by a specific label.
6 | # However, the logic below will short-circuit the workflow when the `props-bot` label is not the one being added.
7 | # Note: The pull_request_target event is used instead of pull_request because this workflow needs permission to comment
8 | # on the pull request. Because this event grants extra permissions to `GITHUB_TOKEN`, any code changes within the PR
9 | # should be considered untrusted. See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
10 | pull_request_target:
11 | types:
12 | - opened
13 | - synchronize
14 | - reopened
15 | - labeled
16 | - ready_for_review
17 | # This event runs anytime a comment is added or deleted.
18 | # You cannot filter this event for PR comments only.
19 | # However, the logic below does short-circuit the workflow for issues.
20 | issue_comment:
21 | type:
22 | - created
23 | # This event will run everytime a new PR review is initially submitted.
24 | pull_request_review:
25 | types:
26 | - submitted
27 | # This event runs anytime a PR review comment is created or deleted.
28 | pull_request_review_comment:
29 | types:
30 | - created
31 |
32 | # Cancels all previous workflow runs for pull requests that have not completed.
33 | concurrency:
34 | # The concurrency group contains the workflow name and the branch name for pull requests
35 | # or the commit hash for any other events.
36 | group: ${{ github.workflow }}-${{ contains( fromJSON( '["pull_request_target", "pull_request_review", "pull_request_review_comment"]' ), github.event_name ) && github.head_ref || github.sha }}
37 | cancel-in-progress: true
38 |
39 | # Disable permissions for all available scopes by default.
40 | # Any needed permissions should be configured at the job level.
41 | permissions: {}
42 |
43 | jobs:
44 | # Compiles a list of props for a pull request.
45 | #
46 | # Performs the following steps:
47 | # - Collects a list of contributor props and leaves a comment.
48 | # - Removes the props-bot label, if necessary.
49 | props-bot:
50 | name: Generate a list of props
51 | runs-on: ubuntu-latest
52 | permissions:
53 | # The action needs permission `write` permission for PRs in order to add a comment.
54 | pull-requests: write
55 | contents: read
56 | timeout-minutes: 20
57 | # The job will run when pull requests are open, ready for review and:
58 | #
59 | # - A comment is added to the pull request.
60 | # - A review is created or commented on.
61 | # - The pull request is opened, synchronized, marked ready for review, or reopened.
62 | # - The `props-bot` label is added to the pull request.
63 | if: |
64 | (
65 | github.event_name == 'issue_comment' && github.event.issue.pull_request ||
66 | contains( fromJSON( '["pull_request_review", "pull_request_review_comment"]' ), github.event_name ) ||
67 | github.event_name == 'pull_request_target' && github.event.action != 'labeled' ||
68 | 'props-bot' == github.event.label.name
69 | ) &&
70 | ( ! github.event.pull_request.draft && github.event.pull_request.state == 'open' || ! github.event.issue.draft && github.event.issue.state == 'open' )
71 |
72 | steps:
73 | - name: Gather a list of contributors
74 | uses: WordPress/props-bot-action@trunk
75 |
76 | - name: Remove the props-bot label
77 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
78 | if: ${{ github.event.action == 'labeled' && 'props-bot' == github.event.label.name }}
79 | with:
80 | retries: 2
81 | retry-exempt-status-codes: 418
82 | script: |
83 | github.rest.issues.removeLabel({
84 | owner: context.repo.owner,
85 | repo: context.repo.repo,
86 | issue_number: '${{ github.event.number }}',
87 | name: 'props-bot'
88 | });
89 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Unit Tests
2 |
3 | on:
4 | pull_request:
5 | paths-ignore:
6 | - '**.md'
7 | push:
8 | branches: [master]
9 | paths-ignore:
10 | - '**.md'
11 |
12 | jobs:
13 | test-js:
14 | name: JavaScript
15 |
16 | runs-on: ubuntu-latest
17 |
18 | strategy:
19 | matrix:
20 | node-version:
21 | - 20
22 | - 21
23 |
24 | steps:
25 | - name: Checkout repository
26 | uses: actions/checkout@v2
27 |
28 | - name: Use Node.js ${{ matrix.node-version }}
29 | uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
30 | with:
31 | node-version: ${{ matrix.node-version }}
32 | check-latest: true
33 |
34 | - name: Install NPM dependencies and build
35 | run: npm ci
36 |
37 | - name: Run tests
38 | run: npm run test
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | tmp
4 | yarn.lock
5 | coverage
6 | .nyc_output
7 | yarn-error.log
8 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "validthis": true,
3 | "laxcomma" : true,
4 | "laxbreak" : true,
5 | "eqeqeq" : false,
6 | "eqnull" : true,
7 | "debug" : true,
8 | "devel" : true,
9 | "curly" : true,
10 | "boss" : true,
11 | "expr" : true,
12 | "node" : true,
13 | "asi" : true,
14 | "indent" : 4
15 | }
16 |
--------------------------------------------------------------------------------
/.npmpackagejsonlintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@wordpress/npm-package-json-lint-config",
3 | "rules": {
4 | "valid-values-license": [ "error", [ "MIT" ] ],
5 | "description-format": [
6 | "error",
7 | {
8 | "requireCapitalFirstLetter": true,
9 | "requireEndingPeriod": true
10 | }
11 | ],
12 | "prefer-no-devDependencies": "error",
13 | "require-publishConfig": "error",
14 | "require-repository-directory": "error",
15 | "valid-values-author": [ "error", [ "The WordPress Contributors" ] ],
16 | "valid-values-publishConfig": [
17 | "error",
18 | [
19 | {
20 | "access": "public"
21 | }
22 | ]
23 | ]
24 | },
25 | "overrides": [
26 | {
27 | "patterns": [ "./package.json" ],
28 | "rules": {
29 | "require-publishConfig": "off",
30 | "require-repository-directory": "off",
31 | "prefer-no-devDependencies": "off"
32 | }
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 20
2 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | // Import the default config file and expose it in the project root.
2 | // Useful for editor integrations.
3 | module.exports = require('@wordpress/prettier-config');
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Grunt Patch WordPress
2 |
3 | Welcome! Thanks for your interest in contributing to Grunt Patch WordPress.
4 |
5 | Please feel free to open a ticket for support or with a feature request.
6 |
7 | When filing a bug report, please include the output when the grunt task is run in [debug mode](http://gruntjs.com/using-the-cli#debug-d) by adding ```--debug``` to your command. Please also include the project that you are using and the command that failed.
8 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Aaron Jorbin
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # grunt-patch-wordpress
2 | 
3 |
4 | > Patch your develop-wordpress directory like a boss (also works on other trac based projects)
5 |
6 | ## Getting Started
7 | This plugin requires Grunt `~0.4.5`
8 |
9 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
10 |
11 | ```shell
12 | npm install grunt-patch-wordpress --save-dev
13 | ```
14 |
15 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
16 |
17 | ```js
18 | grunt.loadNpmTasks('grunt-patch-wordpress');
19 | ```
20 |
21 | ## The "patch_wordpress" task
22 | ```js
23 | patch_wordpress{
24 | tracUrl: 'core.trac.wordpress.org'
25 | }
26 | ```
27 |
28 | ## Apply a patch from the command line
29 |
30 | 1. Have a diff or a patch file in your working Directory, then run ```grunt patch```.
31 | If multiple files are found, you'll be asked which one to apply.
32 |
33 | 2. Enter a ticket number, e.g.
34 | * `grunt patch:15705`
35 |
36 | 3. Enter a ticket url, e.g.
37 | * `grunt patch:https://core.trac.wordpress.org/ticket/15705`
38 |
39 | 4. Enter a patch url, e.g.
40 | * `grunt patch:https://core.trac.wordpress.org/attachment/ticket/11817/13711.diff`
41 |
42 | 5. Enter a github url that points to a changeset such as a Pull Request, e.g.
43 | * `grunt patch:https://github.com/aaronjorbin/develop.wordpress/pull/23`
44 |
45 | ## Upload a patch from the command line
46 |
47 | After you've made changes to your local WordPress develop repository, you can upload a patch file directly to a Trac ticket. e.g. given the ticket number is 2907,
48 |
49 | ```bash
50 | grunt upload_patch:2907
51 | ```
52 |
53 | You can also store your WordPress.org credentials in environment variables. Please exercise caution when using this option, as it may cause your credentials to be leaked!
54 |
55 | ```bash
56 | export WPORG_USERNAME=matt
57 | export WPORG_PASSWORD=MyPasswordIsVerySecure12345
58 | grunt uploadPatch:40000
59 | ```
60 |
61 | ## Using the file_mappings option
62 | If you'd like to map old file paths in your patch to new file paths during the patching process, you can pass a file mappings object as an option. Using this option can be helpful when the file paths in the project have been changed since you've created your patch.
63 |
64 | The file mappings object should contain old file paths and the corresponding new file paths. In the Gruntfile.js of your project, this would look like this:
65 |
66 | ```
67 | patch: {
68 | options: {
69 | file_mappings: {
70 | 'old_path1': 'new_path1',
71 | 'old_path2': 'new_path2',
72 | 'old_path3': 'new_path3',
73 | }
74 | }
75 | }
76 | ```
77 | In this example, the patch task will look for 'old_path1', 'old_path2' and 'old_path3' in your patch and replace them during patching with 'new_path1', 'new_path2', and 'new_path3' respectively.
78 |
79 | ## Contributing
80 |
81 | Please follow the [WordPress coding standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/javascript/).
82 |
83 | * Add unit tests and documentation for any new or changed functionality.
84 | * Lint and test your code using `npm run lint` and `npm run test`.
85 |
86 | ## Release History
87 |
88 | - 0.1.0 - Initial Release
89 | - 0.1.1 - Fix bug when only one diff|patch exists in the working directory
90 | - 0.1.2 - Update wording of instructions
91 | - 0.2.0 - Add support for patches generated in more ways. Improve UX by outputing results all the time
92 | - 0.3.0 - Only keep diff when debug flag is passed. Default to selecting newest patch. Make more files patchable. Allow input during patching process incase the shell prompts the user
93 | - 0.4.0 - add upload_patch, add support for github urls
94 | - 0.4.1 - Remove Mocha as a peerdendency
95 | - 0.4.2 - set `cmd-diff` to `diff` for svn
96 | - 1.0.0 - Add filemapping option. Bump minimum node version. Change code style. Update tooling.
97 | - 2.0.0 - Bump minimum node version. Use @wordpress/scripts. Allow Credentials to be stored. Reduce Dependancy on Grunt.
98 | - 3.0.0 - Bump minimum node version to [Node 12](https://github.com/WordPress/grunt-patch-wordpress/pull/89). [Update wp-scripts](https://github.com/WordPress/grunt-patch-wordpress/pull/87) and some general formatting. Use a [custom user agent for requests](https://github.com/WordPress/grunt-patch-wordpress/pull/85).
99 | - 3.0.1 - Add support for more github URL formats. Internal: Use Github Actions instead of Travis.
100 | - 4.0.0 - Bump minimum node version and some dependencies.
101 |
--------------------------------------------------------------------------------
/RELEASING.md:
--------------------------------------------------------------------------------
1 | # Releasing updates
2 |
3 | ## Manual Testing
4 |
5 | Due to the interactive nature of grunt-patch-wordpress, some manual testing is required in order to release a new version. This describes the bare minimum of testing needed to release a new version.
6 |
7 | 1) Open a ticket on WordPress Core Trac for the new version. This ticket will serve as both the test bed and for actually updating grunt-patch-wordpress.
8 | 2) Use `npm link` to test the unreleased version of grunt-patch-wordpress
9 | 3) Create a patch in WordPress to bump grunt-patch-wordpress and upload it using `npm run grunt upload_patch`.
10 | 4) Revert that file.
11 | 5) Use `npm run grunt patch` to check the file you just uploaded
12 |
13 | ## Major, Minor, or Patch
14 |
15 | Major: Something is different
16 | Minor: Something is new
17 | Patch: Something is fixed
18 |
19 | Changing the minimum node version is a major version change
20 |
21 | ## Update the Numbers/Docs
22 |
23 | 1) Bump `package.json`
24 | 2) Update Readme with new version
25 | 3) When pushing to WordPress Core, give props to everyone who contributed to grunt-patch-wordpress
26 |
--------------------------------------------------------------------------------
/lib/map_old_to_new_file_path.js:
--------------------------------------------------------------------------------
1 | const grunt = require( 'grunt' );
2 |
3 | /**
4 | * Replaces file names in the passed filePath with the file names in the fileMappings.
5 | *
6 | * @param {string} filePath The path to the file where the filenames should be replaced.
7 | * @param {Object} fileMappings The file names to replace and the file names they should be replaced with.
8 | *
9 | * @return {void}
10 | */
11 | function mapOldToNewFilePath( filePath, fileMappings ) {
12 | const body = grunt.file.read( filePath );
13 | let newBody;
14 | let oldPath;
15 | for ( oldPath in fileMappings ) {
16 | // Ensure only own properties are looped over.
17 | if ( ! fileMappings.hasOwnProperty( oldPath ) ) {
18 | continue;
19 | }
20 |
21 | // Regex to match the second filename of the diff header.
22 | const headerRegex = new RegExp(
23 | '((diff \\-\\-git .* )(' + oldPath + ')(\\n))',
24 | 'ig'
25 | );
26 |
27 | // Regex to match the old and new file name of the chunks within the diff.
28 | const chunkFilenameRegex = new RegExp(
29 | '((-{3}|\\+{3})( ' + oldPath + '))',
30 | 'ig'
31 | );
32 |
33 | if ( ! body.match( chunkFilenameRegex ) ) {
34 | continue;
35 | }
36 |
37 | const newPath = fileMappings[ oldPath ];
38 |
39 | newBody = body.replace( chunkFilenameRegex, '$2 ' + newPath );
40 | newBody = newBody.replace( headerRegex, '$2' + newPath + '$4' );
41 |
42 | // Logs the mapping.
43 | if ( body !== newBody ) {
44 | grunt.log.writeln(
45 | 'Old file path ' +
46 | oldPath +
47 | ' found in patch. This path has been automatically replaced by ' +
48 | newPath +
49 | '.'
50 | );
51 | }
52 | }
53 |
54 | // newBody only has a value when there was a match.
55 | if ( newBody ) {
56 | grunt.file.write( filePath, newBody );
57 | }
58 | }
59 |
60 | module.exports = mapOldToNewFilePath;
61 |
--------------------------------------------------------------------------------
/lib/patch.js:
--------------------------------------------------------------------------------
1 | // Ensure both arguments are strings and that str begins with starts.
2 | function startsWith( str, starts ) {
3 | return 0 === ( '' + str ).lastIndexOf( '' + starts, 0 );
4 | }
5 |
6 | module.exports = {
7 | isAb( diff ) {
8 | let ab = false;
9 | try {
10 | diff.split( '\n' ).forEach( ( line ) => {
11 | if ( startsWith( line, 'diff --git a/' ) ) {
12 | throw true;
13 | }
14 | if ( startsWith( line, 'Index: trunk/wp-' ) ) {
15 | throw true;
16 | }
17 | } );
18 | } catch ( e ) {
19 | ab = e;
20 | }
21 |
22 | return ab;
23 | },
24 |
25 | /**
26 | * Check to see if we should apply the diff from the src dir
27 | *
28 | * @param {string} diff A string diff
29 | * @return {boolean} true if we should go into src to apply the diff
30 | */
31 | moveToSrc( diff ) {
32 | let src = false;
33 | const wpDashExceptions = [
34 | '.editorconfig',
35 | '.gitignore',
36 | '.jshintrc',
37 | '.travis.yml',
38 | 'Gruntfile.js',
39 | 'package.json',
40 | 'phpunit.xml.dist',
41 | 'wp-cli.yml',
42 | 'wp-config-sample.php',
43 | 'wp-tests-config-sample.php',
44 | ];
45 | const noWpDashExceptions = [
46 | 'index.php',
47 | 'license.txt',
48 | 'readme.html',
49 | 'xmlrpc.php',
50 | ];
51 |
52 | try {
53 | diff.split( '\n' ).forEach( ( line ) => {
54 | // these are often the first line
55 | if (
56 | startsWith( line, 'Index: src/' ) ||
57 | startsWith( line, 'Index: tests/' ) ||
58 | startsWith( line, 'Index: tools/' ) ||
59 | startsWith( line, 'diff --git src' ) ||
60 | startsWith( line, 'diff --git test' ) ||
61 | startsWith( line, 'diff --git tools' ) ||
62 | startsWith( line, 'diff --git a/src' ) ||
63 | startsWith( line, 'diff --git a/test' ) ||
64 | startsWith( line, 'diff --git a/tools' )
65 | ) {
66 | throw false;
67 | }
68 |
69 | wpDashExceptions.forEach( ( exception ) => {
70 | if (
71 | startsWith( line, 'Index: ' + exception ) ||
72 | startsWith( line, 'diff --git ' + exception ) ||
73 | startsWith( line, 'diff --git a/' + exception )
74 | ) {
75 | throw false;
76 | }
77 | } );
78 |
79 | noWpDashExceptions.forEach( ( exception ) => {
80 | if (
81 | startsWith( line, 'Index: ' + exception ) ||
82 | startsWith( line, 'diff --git ' + exception ) ||
83 | startsWith( line, 'diff --git a/' + exception )
84 | ) {
85 | throw true;
86 | }
87 | } );
88 |
89 | if (
90 | startsWith( line, 'Index: wp-' ) ||
91 | startsWith( line, 'Index: trunk/wp-' ) ||
92 | startsWith( line, 'diff --git wp-' ) ||
93 | startsWith( line, 'diff --git a/wp-' )
94 | ) {
95 | throw true;
96 | }
97 | } );
98 | throw true;
99 | } catch ( l ) {
100 | src = l;
101 | }
102 | return src;
103 | },
104 | };
105 |
--------------------------------------------------------------------------------
/lib/regex.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | patchAttachments( html ) {
3 | return html.match(
4 | /
\s*([^<]+)/g
5 | );
6 | },
7 |
8 | urlsFromAttachmentList( html ) {
9 | return html.match( /href="([^"]+)"/ );
10 | },
11 |
12 | longMatches( html ) {
13 | return html.match( //g );
14 | },
15 |
16 | possiblePatches( longMatches ) {
17 | return longMatches
18 | .map( ( match ) => {
19 | if ( match.match( /(patch|diff)"/ ) ) {
20 | return (
21 | match
22 | // Remove any HTML tags.
23 | .replace( /<\/?[^>]+>/g, '' )
24 | // Collapse consecutive whitespace characters into one space.
25 | .replace( /\s+/g, ' ' )
26 | .trim()
27 | );
28 | }
29 | return false;
30 | } )
31 | .filter( Boolean );
32 | },
33 |
34 | localFileClean( file ) {
35 | return file.replace( '?', '' ).replace( /\s/g, '' );
36 | },
37 |
38 | githubConvert( url ) {
39 | const matches = url.match(
40 | /(?:github\.com|patch-diff.githubusercontent.com\/raw)\/((?:[^\/]+\/){2}pull\/[0-9]*)/
41 | );
42 | if ( matches ) {
43 | return `https://patch-diff.githubusercontent.com/raw/${ matches[ 1 ] }.diff`;
44 | }
45 | return false;
46 | },
47 | };
48 |
--------------------------------------------------------------------------------
/lib/trac.js:
--------------------------------------------------------------------------------
1 | const url = require( 'url' );
2 | const grunt = require( 'grunt' );
3 |
4 | module.exports = {
5 | convertToRaw( parsedUrl ) {
6 | grunt.log.debug( 'convertToRaw: ' + JSON.stringify( parsedUrl ) );
7 | parsedUrl.pathname = parsedUrl.pathname.replace(
8 | /attachment/,
9 | 'raw-attachment'
10 | );
11 | grunt.log.debug( 'converted_from_raw: ' + url.format( parsedUrl ) );
12 | return url.format( parsedUrl );
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grunt-patch-wordpress",
3 | "version": "4.0.0",
4 | "description": "Patch your core WordPress.",
5 | "author": "The WordPress Contributors",
6 | "license": "MIT",
7 | "keywords": [
8 | "gruntplugin"
9 | ],
10 | "homepage": "https://github.com/wordpress/grunt-patch-wordpress",
11 | "repository": {
12 | "type": "git",
13 | "url": "git://github.com/wordpress/grunt-patch-wordpress.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/wordpress/grunt-patch-wordpress/issues"
17 | },
18 | "engines": {
19 | "node": ">=20.10.0",
20 | "npm": ">=10.2.3"
21 | },
22 | "main": "Gruntfile.js",
23 | "jest": {
24 | "testMatch": [
25 | "**/test/**/*.js"
26 | ],
27 | "testPathIgnorePatterns": [
28 | ".eslintrc.js"
29 | ]
30 | },
31 | "npmPackageJsonLintConfig": {
32 | "extends": "@wordpress/npm-package-json-lint-config",
33 | "rules": {
34 | "valid-values-license": [
35 | "error",
36 | [
37 | "MIT"
38 | ]
39 | ]
40 | }
41 | },
42 | "dependencies": {
43 | "grunt": "^1.0.3",
44 | "inquirer": "^5.1.0",
45 | "request": "^2.83.0",
46 | "xmlrpc": "^1.3.2"
47 | },
48 | "devDependencies": {
49 | "@wordpress/scripts": "^30.10.0",
50 | "concurrently": "^8.2.2"
51 | },
52 | "scripts": {
53 | "check-engines": "wp-scripts check-engines",
54 | "check-licenses": "wp-scripts check-licenses --prod",
55 | "test:coverage": "wp-scripts test-unit-js --coverage",
56 | "test:help": "wp-scripts test-unit-js --help",
57 | "test:unit": "wp-scripts test-unit-js",
58 | "test:watch": "wp-scripts test-unit-js --watch",
59 | "test": "concurrently \"npm run check-engines\" \"npm run check-licenses\" \"npm run lint\" \"npm run test:unit\"",
60 | "lint": "concurrently \"npm run lint:js\" \"npm run lint:pkg-json\"",
61 | "lint:js": "wp-scripts lint-js",
62 | "lint:fix": "wp-scripts lint-js --fix",
63 | "lint:pkg-json": "wp-scripts lint-pkg-json"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tasks/patch_wordpress.js:
--------------------------------------------------------------------------------
1 | /*
2 | * grunt-patch-wordpress
3 | * https://github.com/WordPress/grunt-patch-wordpress
4 | * Based on https://gist.github.com/markjaquith/4219135
5 | *
6 | *
7 | * Copyright (c) 2013 Aaron Jorbin
8 | * Licensed under the MIT license.
9 | */
10 |
11 | const request = require( 'request' );
12 | const exec = require( 'child_process' ).exec;
13 | const execSync = require( 'child_process' ).execSync;
14 | const spawn = require( 'child_process' ).spawn;
15 | const inquirer = require( 'inquirer' );
16 | const url = require( 'url' );
17 | const fs = require( 'fs' );
18 | const trac = require( '../lib/trac.js' );
19 | const patch = require( '../lib/patch.js' );
20 | const regex = require( '../lib/regex.js' );
21 | const xmlrpc = require( 'xmlrpc' );
22 | const mapOldToNewFilePath = require( '../lib/map_old_to_new_file_path.js' );
23 |
24 | module.exports = function ( grunt ) {
25 | let tempFile = 'wppatch.diff';
26 | const defaults = {
27 | tracUrl: 'core.trac.wordpress.org',
28 | };
29 |
30 | function isSvn() {
31 | return fs.existsSync( '.svn' );
32 | }
33 |
34 | function workingDir() {
35 | return process.cwd();
36 | }
37 |
38 | function applyPatch( patchUrl, done, options ) {
39 | grunt.verbose.write( patchUrl );
40 | const parsedUrl = url.parse( patchUrl );
41 |
42 | // What to do when either our patch is ready
43 | grunt.event.once( 'fileReady', ( level, moveToSrc ) => {
44 | const patchOptions = {};
45 | const patchArgs = [];
46 |
47 | // Set patch process to use the existing I/O streams, which will output
48 | // the command's results and allow for user input on patch error
49 | patchOptions.stdio = 'inherit';
50 |
51 | // Decide if we need to be in src
52 | if ( moveToSrc ) {
53 | patchOptions.cwd = workingDir() + '/src';
54 | tempFile = workingDir() + '/' + tempFile;
55 | }
56 |
57 | // Set the patch command's arguments
58 | patchArgs.push( '-p' + level );
59 | patchArgs.push( '--input=' + tempFile );
60 |
61 | grunt.log.debug(
62 | 'patch options: ' + JSON.stringify( patchOptions )
63 | );
64 | grunt.log.debug(
65 | 'patch arguments: ' + JSON.stringify( patchArgs )
66 | );
67 | grunt.log.debug( 'patch tempFile: ' + JSON.stringify( tempFile ) );
68 |
69 | // Maps old file paths in patches to new file paths.
70 | if ( options.file_mappings ) {
71 | mapOldToNewFilePath( tempFile, options.file_mappings );
72 | }
73 |
74 | const patchProcess = spawn( 'patch', patchArgs, patchOptions );
75 |
76 | patchProcess.on( 'exit', ( code, signal ) => {
77 | if ( signal ) {
78 | grunt.log.debug( 'error signal: ' + signal );
79 | }
80 |
81 | // if debug is enabled, don't delete the file
82 | if ( grunt.option( 'debug' ) ) {
83 | grunt.log.debug( 'File Saved' );
84 | } else {
85 | grunt.file.delete( tempFile );
86 | }
87 |
88 | done( code );
89 | } );
90 | } );
91 |
92 | // or we know we have failed
93 | grunt.event.once( 'fileFail', ( msg ) => {
94 | if ( 'string' === typeof msg ) {
95 | grunt.log.errorlns( msg );
96 | }
97 |
98 | done( false );
99 | } );
100 |
101 | // if patchUrl is a github url
102 | if ( regex.githubConvert( patchUrl ) ) {
103 | const diffUrl = regex.githubConvert( patchUrl );
104 | grunt.log.debug( 'github url detected: ' + diffUrl );
105 |
106 | getPatch( diffUrl, options );
107 |
108 | // if patchUrl is a full url and is a raw-attachement, just apply it
109 | } else if (
110 | parsedUrl.hostname === options.tracUrl &&
111 | parsedUrl.pathname.match( /raw-attachment/ )
112 | ) {
113 | getPatch( patchUrl, options );
114 |
115 | // if patchUrl is full url and is an attachment, convert it to a raw attachment
116 | } else if (
117 | parsedUrl.hostname === options.tracUrl &&
118 | parsedUrl.pathname.match( /attachment/ ) &&
119 | parsedUrl.pathname.match( /(patch|diff)/ )
120 | ) {
121 | getPatch( trac.convertToRaw( parsedUrl, options ) );
122 |
123 | // if patchUrl is just a ticket number, get a list of patches on that ticket and allow user to choose one
124 | } else if (
125 | parsedUrl.hostname === options.tracUrl &&
126 | parsedUrl.pathname.match( /ticket/ )
127 | ) {
128 | getPatchFromTicket( patchUrl, options );
129 |
130 | // if we just enter a number, assume it is a ticket number
131 | } else if (
132 | null === parsedUrl.hostname &&
133 | ! parsedUrl.pathname.match( /\./ )
134 | ) {
135 | getPatchFromTicketNumber( patchUrl, options );
136 |
137 | // if patchUrl is a local file, just use that
138 | } else if ( null === parsedUrl.hostname ) {
139 | getLocalPatch( patchUrl, options );
140 |
141 | // We've failed in our mission
142 | } else {
143 | grunt.event.emit(
144 | 'fileFile',
145 | 'All matching failed. Please enter a ticket url, ticket number, patch url'
146 | );
147 | }
148 | }
149 |
150 | function getPatchFromTicketNumber( patchUrl, options ) {
151 | grunt.log.debug( 'getPatchFromTicketNumber: ' + patchUrl );
152 | getPatchFromTicket(
153 | 'https://' +
154 | options.tracUrl +
155 | '/attachment/ticket/' +
156 | patchUrl +
157 | '/',
158 | options
159 | );
160 | }
161 |
162 | function getPatchFromTicket( patchUrl, options ) {
163 | let matches;
164 | let longMatches;
165 | let matchUrl;
166 | let possiblePatches;
167 |
168 | grunt.log.debug( 'getPatchFromTicket: ' + patchUrl );
169 |
170 | const requestOptions = {
171 | url: patchUrl,
172 | headers: {
173 | 'User-Agent':
174 | 'grunt-patch-wordpress; https://github.com/WordPress/grunt-patch-wordpress',
175 | },
176 | };
177 | request( requestOptions, ( error, response, body ) => {
178 | if ( ! error && 200 === response.statusCode ) {
179 | matches = regex.patchAttachments( body );
180 | grunt.log.debug( 'matches: ' + JSON.stringify( matches ) );
181 |
182 | if ( null === matches ) {
183 | grunt.event.emit(
184 | 'fileFail',
185 | patchUrl + '\ncontains no attachments'
186 | );
187 | } else if ( 1 === matches.length ) {
188 | matchUrl =
189 | options.tracUrl +
190 | regex.urlsFromAttachmentList( matches[ 0 ] )[ 1 ];
191 | getPatch(
192 | trac.convertToRaw( url.parse( 'https://' + matchUrl ) ),
193 | options
194 | );
195 | } else {
196 | longMatches = regex.longMatches( body );
197 | possiblePatches = regex.possiblePatches( longMatches );
198 |
199 | grunt.log.debug(
200 | 'possiblePatches: ' + JSON.stringify( possiblePatches )
201 | );
202 | grunt.log.debug(
203 | 'longMatches: ' + JSON.stringify( longMatches )
204 | );
205 | inquirer
206 | .prompt( [
207 | {
208 | type: 'list',
209 | name: 'patch_name',
210 | message: 'Please select a patch to apply',
211 | choices: possiblePatches,
212 |
213 | // preselect the most recent patch
214 | default: possiblePatches.length - 1,
215 | },
216 | ] )
217 | .then( ( answers ) => {
218 | grunt.log.debug(
219 | 'answers:' + JSON.stringify( answers )
220 | );
221 | matchUrl =
222 | options.tracUrl +
223 | regex.urlsFromAttachmentList(
224 | matches[
225 | possiblePatches.indexOf(
226 | answers.patch_name
227 | )
228 | ]
229 | )[ 1 ];
230 | getPatch(
231 | trac.convertToRaw(
232 | url.parse( 'https://' + matchUrl )
233 | ),
234 | options
235 | );
236 | } );
237 | }
238 | } else {
239 | // something went wrong
240 | grunt.event.emit(
241 | 'fileFail',
242 | 'getPatchFromTicket fail \n status: ' + response.statusCode
243 | );
244 | }
245 | } );
246 |
247 | grunt.event.emit( 'fileFile', 'method not available yet' );
248 | }
249 |
250 | function getLocalPatch( patchUrl ) {
251 | const body = grunt.file.read( patchUrl );
252 | const level = patch.isAb( body ) ? 1 : 0;
253 | const moveToSrc = patch.moveToSrc( body );
254 |
255 | grunt.file.copy( patchUrl, tempFile );
256 | grunt.event.emit( 'fileReady', level, moveToSrc );
257 | }
258 |
259 | function getPatch( patchUrl ) {
260 | grunt.log.debug( 'getting patch: ' + patchUrl );
261 |
262 | const requestOptions = {
263 | url: patchUrl,
264 | headers: {
265 | 'User-Agent':
266 | 'grunt-patch-wordpress; https://github.com/WordPress/grunt-patch-wordpress',
267 | },
268 | };
269 | request( requestOptions, ( error, response, body ) => {
270 | if ( ! error && 200 === response.statusCode ) {
271 | const level = patch.isAb( body ) ? 1 : 0;
272 | const moveToSrc = patch.moveToSrc( body );
273 |
274 | grunt.file.write( tempFile, body );
275 | grunt.event.emit( 'fileReady', level, moveToSrc );
276 | } else {
277 | // something went wrong
278 | grunt.event.emit(
279 | 'fileFail',
280 | 'getPatch_fail \n status: ' + response.statusCode
281 | );
282 | }
283 | } );
284 | }
285 |
286 | function fileFail( done, msg ) {
287 | grunt.log.errorlns( 'Nothing to patch.' );
288 | grunt.log.errorlns( '' );
289 | grunt.log.errorlns( '' );
290 | grunt.log.errorlns( 'To use this command, please:' );
291 | grunt.log.errorlns( '' );
292 | grunt.log.errorlns(
293 | '1) have a diff or patch in your WordPress Directory'
294 | );
295 | grunt.log.errorlns( '' );
296 | grunt.log.errorlns(
297 | '2) enter a ticket number, e.g. grunt patch:15705'
298 | );
299 | grunt.log.errorlns( '' );
300 | grunt.log.errorlns(
301 | '3) enter a ticket url, e.g. grunt patch:https://core.trac.wordpress.org/ticket/15705'
302 | );
303 | grunt.log.errorlns( '' );
304 | grunt.log.errorlns(
305 | '4) enter a patch url, e.g. grunt patch:https://core.trac.wordpress.org/attachment/ticket/11817/13711.diff'
306 | );
307 | grunt.log.errorlns( '' );
308 |
309 | if ( 'string' === typeof msg ) {
310 | grunt.verbose.errorlns( 'msg: ' + msg );
311 | }
312 |
313 | done( false );
314 | }
315 |
316 | function localFile( error, result, code, done, options ) {
317 | if ( ! error ) {
318 | const files = result
319 | .split( '\n' )
320 | .filter(
321 | ( file ) =>
322 | file.includes( 'patch' ) || file.includes( 'diff' )
323 | );
324 | grunt.log.debug( 'files: ' + JSON.stringify( files ) );
325 |
326 | if ( 0 === files.length ) {
327 | fileFail( done );
328 | } else if ( 1 === files.length ) {
329 | applyPatch( regex.localFileClean( files[ 0 ] ), done, options );
330 | } else {
331 | inquirer
332 | .prompt( [
333 | {
334 | type: 'list',
335 | name: 'file',
336 | message: 'Please select a file to apply',
337 | choices: files,
338 | },
339 | ] )
340 | .then( ( answers ) => {
341 | const file = regex.localFileClean( answers.file );
342 | applyPatch( file, done, options );
343 | } );
344 | }
345 | } else {
346 | fileFail( done, 'local file fail' );
347 | }
348 | }
349 |
350 | grunt.registerTask(
351 | 'patch_wordpress',
352 | 'Patch your develop-wordpress directory like a boss',
353 | function ( ticket, afterProtocal ) {
354 | const done = this.async();
355 | const options = this.options( defaults );
356 |
357 | // since URLs contain a : which is the seperator for grunt, we
358 | // need to reassemble the url.
359 | if ( 'undefined' !== typeof afterProtocal ) {
360 | ticket = ticket + ':' + afterProtocal;
361 | }
362 |
363 | grunt.log.debug( 'ticket: ' + ticket );
364 | grunt.log.debug( 'options: ' + JSON.stringify( options ) );
365 |
366 | if ( 'undefined' === typeof ticket ) {
367 | // look for diffs and patches in the root of the checkout and
368 | // prompt using inquirer to pick one
369 |
370 | const fileFinderCommand = isSvn()
371 | ? 'svn status '
372 | : 'git ls-files --other --exclude-standard';
373 |
374 | exec( fileFinderCommand, ( error, result, code ) => {
375 | localFile( error, result, code, done, options );
376 | } );
377 | } else {
378 | applyPatch( ticket, done, options );
379 | }
380 | }
381 | );
382 |
383 | grunt.registerTask(
384 | 'upload_patch',
385 | 'Upload the current diff of your develop-wordpress directory to Trac',
386 | function ( ticketNumber ) {
387 | const done = this.async();
388 | const options = this.options( defaults );
389 |
390 | grunt.log.debug( 'ticketNumber: ' + ticketNumber );
391 | grunt.log.debug( 'options: ' + JSON.stringify( options ) );
392 |
393 | ticketNumber = parseInt( ticketNumber, 10 );
394 | if ( 'number' !== typeof ticketNumber ) {
395 | grunt.fail.warn(
396 | 'A ticket number is required to upload a patch.'
397 | );
398 | }
399 |
400 | const uploadPatchWithCredentials = function ( username, password ) {
401 | const diffCommand = isSvn()
402 | ? 'svn diff --diff-cmd diff'
403 | : 'git diff HEAD';
404 |
405 | if ( ! isSvn() ) {
406 | execSync( 'git add .' );
407 | }
408 |
409 | exec( diffCommand, ( error, result ) => {
410 | const client = xmlrpc.createSecureClient( {
411 | hostname: options.tracUrl,
412 | port: 443,
413 | path: '/login/xmlrpc',
414 | basic_auth: {
415 | // eslint-disable-line camelcase
416 | user: username,
417 | pass: password,
418 | },
419 | } );
420 | client.methodCall(
421 | 'ticket.putAttachment',
422 | [
423 | ticketNumber,
424 | ticketNumber + '.diff',
425 | '', // description. empty for now.
426 | new Buffer.from(
427 | new Buffer.from( result ).toString( 'base64' ),
428 | 'base64'
429 | ),
430 | false, // never overwrite the old file
431 | ],
432 | ( err ) => {
433 | if ( ! isSvn() ) {
434 | exec( 'git reset' );
435 | }
436 |
437 | if ( null === err ) {
438 | grunt.log.writeln( 'Uploaded patch.' );
439 | done();
440 | } else {
441 | grunt.fail.warn(
442 | 'Something went wrong when attempting to upload the patch. Please confirm your credentials and the ticket number. ' +
443 | err
444 | );
445 | }
446 | }
447 | );
448 | } );
449 | };
450 | if ( process.env.WPORG_USERNAME && process.env.WPORG_PASSWORD ) {
451 | uploadPatchWithCredentials(
452 | process.env.WPORG_USERNAME,
453 | process.env.WPORG_PASSWORD
454 | );
455 | } else {
456 | inquirer
457 | .prompt( [
458 | {
459 | type: 'input',
460 | name: 'username',
461 | message: 'Enter your WordPress.org username',
462 | },
463 | {
464 | type: 'password',
465 | name: 'password',
466 | message: 'Enter your WordPress.org password',
467 | },
468 | ] )
469 | .then( ( answers ) => {
470 | uploadPatchWithCredentials(
471 | answers.username,
472 | answers.password
473 | );
474 | } );
475 | }
476 | }
477 | );
478 | };
479 |
--------------------------------------------------------------------------------
/test/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true,
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/test/expected/custom_options:
--------------------------------------------------------------------------------
1 | Testing: 1 2 3 !!!
--------------------------------------------------------------------------------
/test/expected/default_options:
--------------------------------------------------------------------------------
1 | Testing, 1 2 3.
--------------------------------------------------------------------------------
/test/expected/patch_wordpress_1.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/color-picker.js src/js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/js/_enqueues/lib/color-picker.js
4 | +++ src/js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/expected/patch_wordpress_2.diff:
--------------------------------------------------------------------------------
1 | diff --git src/js/_enqueues/lib/color-picker.js src/js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/js/_enqueues/lib/color-picker.js
4 | +++ src/js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/expected/patch_wordpress_3.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/wp-admin/js/nice-file.js
4 | +++ src/wp-admin/js/nice-file.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/expected/patch_wordpress_4.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/color-picker.js src/js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/js/_enqueues/lib/color-picker.js
4 | +++ src/js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
14 | index a3bca29df8..52eb36036e 100644
15 | --- src/wp-admin/js/nice-file.js
16 | +++ src/wp-admin/js/nice-file.js
17 | @@ -1,6 +1,6 @@
18 | /* global wpColorPickerL10n */
19 | ( function( $, undef ) {
20 | -
21 | +// Very fancy patch file.
22 | var ColorPicker,
23 | _before = '',
24 | _after = '',
25 |
--------------------------------------------------------------------------------
/test/expected/patch_wordpress_5.diff:
--------------------------------------------------------------------------------
1 | diff --git src/js/_enqueues/lib/color-picker.js src/js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/js/_enqueues/lib/color-picker.js
4 | +++ src/js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
14 | index a3bca29df8..52eb36036e 100644
15 | --- src/wp-admin/js/nice-file.js
16 | +++ src/wp-admin/js/nice-file.js
17 | @@ -1,6 +1,6 @@
18 | /* global wpColorPickerL10n */
19 | ( function( $, undef ) {
20 | -
21 | +// Very fancy patch file.
22 | var ColorPicker,
23 | _before = '',
24 | _after = '',
25 |
--------------------------------------------------------------------------------
/test/expected/patch_wordpress_6.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/color-picker.js src/js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/js/_enqueues/lib/color-picker.js
4 | +++ src/js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 | diff --git src/js/_enqueues/lib/color-picker.js src/js/_enqueues/lib/color-picker.js
14 | index a3bca29df8..52eb36036e 100644
15 | --- src/js/_enqueues/lib/color-picker.js
16 | +++ src/js/_enqueues/lib/color-picker.js
17 | @@ -1,6 +1,6 @@
18 | /* global wpColorPickerL10n */
19 | ( function( $, undef ) {
20 | -
21 | +// Very fancy patch file.
22 | var ColorPicker,
23 | _before = '',
24 | _after = '',
25 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
26 | index a3bca29df8..52eb36036e 100644
27 | --- src/wp-admin/js/nice-file.js
28 | +++ src/wp-admin/js/nice-file.js
29 | @@ -1,6 +1,6 @@
30 | /* global wpColorPickerL10n */
31 | ( function( $, undef ) {
32 | -
33 | +// Very fancy patch file.
34 | var ColorPicker,
35 | _before = '',
36 | _after = '',
37 |
--------------------------------------------------------------------------------
/test/expected/patch_wordpress_7.diff:
--------------------------------------------------------------------------------
1 | diff --git wp-admin/js/color-picker.js js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- js/_enqueues/lib/color-picker.js
4 | +++ js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/fixtures/23988.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Ticket #23988 – Attachments
14 | – WordPress Trac
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
94 |
108 |
122 |
123 |
124 |
125 |
126 |
Context Navigation
127 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
Attachments (4)
137 |
168 |
169 |
170 |
171 |
172 |
206 |
218 |
219 |
220 |
221 |
222 |
223 |
227 |
232 |
238 |
239 |
269 |
270 |
--------------------------------------------------------------------------------
/test/fixtures/23989.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Ticket #23989 – Attachments
14 | – WordPress Trac
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
94 |
108 |
122 |
123 |
124 |
125 |
126 |
Context Navigation
127 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
Attachments (1)
137 |
138 |
139 | -
140 | long-button-text.png
141 | (89.3 KB) -
142 | added by MikeHansenMe 10 months ago.
143 |
144 | -
145 | long button text
146 |
147 |
148 |
149 | Download all attachments as: .zip
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
191 |
203 |
204 |
205 |
206 |
207 |
208 |
212 |
217 |
223 |
224 |
254 |
255 |
--------------------------------------------------------------------------------
/test/fixtures/23994.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Ticket #23994 – Attachments
14 | – WordPress Trac
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
94 |
108 |
122 |
123 |
124 |
125 |
126 |
Context Navigation
127 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
Attachments (1)
137 |
138 |
139 | -
140 | 23994.diff
141 | (659 bytes) -
142 | added by obenland 10 months ago.
143 |
144 |
145 |
146 | Download all attachments as: .zip
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
188 |
200 |
201 |
202 |
203 |
204 |
205 |
209 |
214 |
220 |
221 |
251 |
252 |
--------------------------------------------------------------------------------
/test/fixtures/26602.2.diff:
--------------------------------------------------------------------------------
1 | Index: src/wp-admin/themes.php
2 | ===================================================================
3 | --- src/wp-admin/themes.php (revision 26958)
4 | +++ src/wp-admin/themes.php (working copy)
5 | @@ -192,7 +192,7 @@
6 | */
7 |
8 | foreach ( $themes as $theme ) : ?>
9 | -
10 | +
11 |
12 |
13 |

14 | @@ -200,11 +200,11 @@
15 |
16 |
17 |
18 | -
19 | +
20 |
21 |
22 |
23 | -
24 | +
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/test/fixtures/core.git.diff:
--------------------------------------------------------------------------------
1 | diff --git wp-load.php wp-load.php
2 | index fb85953..18ed0f6 100644
3 | --- wp-load.php
4 | +++ wp-load.php
5 | @@ -1,4 +1,6 @@
6 |
24 |
25 | -
⚄
26 | +
27 | <# if ( data.type === 'uploaded' ) { #>
28 |
29 | <# } else if ( data.type === 'default' ) { #>
30 | @@ -917,7 +917,7 @@ final class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control
31 |
32 |
33 |
34 | -
⚄
35 | +
36 | <# if ( data.type === 'uploaded' ) { #>
37 |
38 | <# } else if ( data.type === 'default' ) { #>
39 |
--------------------------------------------------------------------------------
/test/fixtures/patch_wordpress_1.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/color-picker.js src/wp-admin/js/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/wp-admin/js/color-picker.js
4 | +++ src/wp-admin/js/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/fixtures/patch_wordpress_2.diff:
--------------------------------------------------------------------------------
1 | diff --git src/js/_enqueues/lib/color-picker.js src/js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/js/_enqueues/lib/color-picker.js
4 | +++ src/js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/fixtures/patch_wordpress_3.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/wp-admin/js/nice-file.js
4 | +++ src/wp-admin/js/nice-file.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/fixtures/patch_wordpress_4.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/color-picker.js src/wp-admin/js/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/wp-admin/js/color-picker.js
4 | +++ src/wp-admin/js/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
14 | index a3bca29df8..52eb36036e 100644
15 | --- src/wp-admin/js/nice-file.js
16 | +++ src/wp-admin/js/nice-file.js
17 | @@ -1,6 +1,6 @@
18 | /* global wpColorPickerL10n */
19 | ( function( $, undef ) {
20 | -
21 | +// Very fancy patch file.
22 | var ColorPicker,
23 | _before = '',
24 | _after = '',
25 |
--------------------------------------------------------------------------------
/test/fixtures/patch_wordpress_5.diff:
--------------------------------------------------------------------------------
1 | diff --git src/js/_enqueues/lib/color-picker.js src/js/_enqueues/lib/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/js/_enqueues/lib/color-picker.js
4 | +++ src/js/_enqueues/lib/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
14 | index a3bca29df8..52eb36036e 100644
15 | --- src/wp-admin/js/nice-file.js
16 | +++ src/wp-admin/js/nice-file.js
17 | @@ -1,6 +1,6 @@
18 | /* global wpColorPickerL10n */
19 | ( function( $, undef ) {
20 | -
21 | +// Very fancy patch file.
22 | var ColorPicker,
23 | _before = '',
24 | _after = '',
25 |
--------------------------------------------------------------------------------
/test/fixtures/patch_wordpress_6.diff:
--------------------------------------------------------------------------------
1 | diff --git src/wp-admin/js/color-picker.js src/wp-admin/js/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- src/wp-admin/js/color-picker.js
4 | +++ src/wp-admin/js/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 | diff --git src/js/_enqueues/lib/color-picker.js src/js/_enqueues/lib/color-picker.js
14 | index a3bca29df8..52eb36036e 100644
15 | --- src/js/_enqueues/lib/color-picker.js
16 | +++ src/js/_enqueues/lib/color-picker.js
17 | @@ -1,6 +1,6 @@
18 | /* global wpColorPickerL10n */
19 | ( function( $, undef ) {
20 | -
21 | +// Very fancy patch file.
22 | var ColorPicker,
23 | _before = '',
24 | _after = '',
25 | diff --git src/wp-admin/js/nice-file.js src/wp-admin/js/nice-file.js
26 | index a3bca29df8..52eb36036e 100644
27 | --- src/wp-admin/js/nice-file.js
28 | +++ src/wp-admin/js/nice-file.js
29 | @@ -1,6 +1,6 @@
30 | /* global wpColorPickerL10n */
31 | ( function( $, undef ) {
32 | -
33 | +// Very fancy patch file.
34 | var ColorPicker,
35 | _before = '',
36 | _after = '',
37 |
--------------------------------------------------------------------------------
/test/fixtures/patch_wordpress_7.diff:
--------------------------------------------------------------------------------
1 | diff --git wp-admin/js/color-picker.js wp-admin/js/color-picker.js
2 | index a3bca29df8..52eb36036e 100644
3 | --- wp-admin/js/color-picker.js
4 | +++ wp-admin/js/color-picker.js
5 | @@ -1,6 +1,6 @@
6 | /* global wpColorPickerL10n */
7 | ( function( $, undef ) {
8 | -
9 | +// Very fancy patch file.
10 | var ColorPicker,
11 | _before = '',
12 | _after = '',
13 |
--------------------------------------------------------------------------------
/test/fixtures/tests.develop.git.diff:
--------------------------------------------------------------------------------
1 | diff --git tests/phpunit/wp-mail-real-test.php tests/phpunit/wp-mail-real-test.php
2 | index a3b4826..de0f2e8 100644
3 | --- tests/phpunit/wp-mail-real-test.php
4 | +++ tests/phpunit/wp-mail-real-test.php
5 | @@ -1,4 +1,6 @@
6 | ";
13 | $headers[] = "BCC: {$bcc}";
14 | wp_mail( '', $subject, $message, $headers );
15 | echo "Test emails sent!\n"
16 | -?>
17 | \ No newline at end of file
18 | +?>
19 |
--------------------------------------------------------------------------------
/test/fixtures/tests.develop.svn.diff:
--------------------------------------------------------------------------------
1 | Index: tests/phpunit/wp-mail-real-test.php
2 | ===================================================================
3 | --- tests/phpunit/wp-mail-real-test.php (revision 27349)
4 | +++ tests/phpunit/wp-mail-real-test.php (working copy)
5 | @@ -1,4 +1,6 @@
6 |
17 | \ No newline at end of file
18 | +?>
19 |
--------------------------------------------------------------------------------
/test/patch_wordpress_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const grunt = require( 'grunt' );
4 | const patch = require( '../lib/patch.js' );
5 | const url = require( 'url' );
6 | const trac = require( '../lib/trac.js' );
7 | const mapOldToNewFilePath = require( '../lib/map_old_to_new_file_path.js' );
8 |
9 | describe( 'grunt_patch_wordpress', () => {
10 | describe( 'initial checks', () => {
11 | it( 'a is a', () => {
12 | expect( 'a' ).toEqual( 'a' );
13 | } );
14 | } );
15 |
16 | it( 'convertToRaw converts urls', () => {
17 | expect(
18 | trac.convertToRaw(
19 | url.parse(
20 | 'https://core.trac.wordpress.org/attachment/ticket/26700/26700.diff'
21 | )
22 | )
23 | ).toEqual(
24 | 'https://core.trac.wordpress.org/raw-attachment/ticket/26700/26700.diff'
25 | );
26 | } );
27 |
28 | describe( 'Level Calculator', () => {
29 | // @TODO: Find alot of patches to use here
30 |
31 | it( '26602.2.diff is 0', () => {
32 | const file = grunt.file.read( 'test/fixtures/26602.2.diff' );
33 | expect( patch.isAb( file ) ).toBe( false );
34 | } );
35 | } );
36 |
37 | describe( 'mapOldToNewFilePath', () => {
38 | const fileMappings = {
39 | 'src/wp-admin/js/color-picker.js':
40 | 'src/js/_enqueues/lib/color-picker.js',
41 | 'wp-admin/js/color-picker.js': 'js/_enqueues/lib/color-picker.js',
42 | };
43 |
44 | describe( 'old to new', () => {
45 | beforeAll( () => {
46 | grunt.file.copy(
47 | './test/fixtures/patch_wordpress_1.diff',
48 | './test/tmp/patch_wordpress_1_copy.diff'
49 | );
50 | mapOldToNewFilePath(
51 | './test/tmp/patch_wordpress_1_copy.diff',
52 | fileMappings
53 | );
54 | } );
55 |
56 | it( 'replaces old file paths with new file paths in the diff', () => {
57 | const expected = grunt.file.read(
58 | './test/expected/patch_wordpress_1.diff'
59 | );
60 | const actual = grunt.file.read(
61 | './test/tmp/patch_wordpress_1_copy.diff'
62 | );
63 |
64 | expect( actual ).toEqual( expected );
65 | } );
66 |
67 | afterAll( () => {
68 | grunt.file.delete( './test/tmp/patch_wordpress_1_copy.diff' );
69 | } );
70 | } );
71 |
72 | describe( 'new stay unchanged', () => {
73 | beforeAll( () => {
74 | grunt.file.copy(
75 | './test/fixtures/patch_wordpress_2.diff',
76 | './test/tmp/patch_wordpress_2_copy.diff'
77 | );
78 | mapOldToNewFilePath(
79 | './test/tmp/patch_wordpress_2_copy.diff',
80 | fileMappings
81 | );
82 | } );
83 |
84 | it( "doesn't replace new file paths", () => {
85 | const expected = grunt.file.read(
86 | './test/expected/patch_wordpress_2.diff'
87 | );
88 | const actual = grunt.file.read(
89 | './test/tmp/patch_wordpress_2_copy.diff'
90 | );
91 |
92 | expect( actual ).toEqual( expected );
93 | } );
94 |
95 | afterAll( () => {
96 | grunt.file.delete( './test/tmp/patch_wordpress_2_copy.diff' );
97 | } );
98 | } );
99 |
100 | describe( 'unknown stay unchanged', () => {
101 | beforeAll( () => {
102 | grunt.file.copy(
103 | './test/fixtures/patch_wordpress_3.diff',
104 | './test/tmp/patch_wordpress_3_copy.diff'
105 | );
106 | mapOldToNewFilePath(
107 | './test/tmp/patch_wordpress_3_copy.diff',
108 | fileMappings
109 | );
110 | } );
111 |
112 | it( "doesn't replace file paths that are not in the file mappings object", () => {
113 | const expected = grunt.file.read(
114 | './test/expected/patch_wordpress_3.diff'
115 | );
116 | const actual = grunt.file.read(
117 | './test/tmp/patch_wordpress_3_copy.diff'
118 | );
119 |
120 | expect( actual ).toEqual( expected );
121 | } );
122 |
123 | afterAll( () => {
124 | grunt.file.delete( './test/tmp/patch_wordpress_3_copy.diff' );
125 | } );
126 | } );
127 |
128 | describe( 'new stay unchanged, old to new', () => {
129 | beforeAll( () => {
130 | grunt.file.copy(
131 | './test/fixtures/patch_wordpress_4.diff',
132 | './test/tmp/patch_wordpress_4_copy.diff'
133 | );
134 | mapOldToNewFilePath(
135 | './test/tmp/patch_wordpress_4_copy.diff',
136 | fileMappings
137 | );
138 | } );
139 |
140 | it(
141 | "replaces old file paths with new file paths but doesn't replace file paths that are not " +
142 | 'in the file mappings object in a diff file with multiple diffs',
143 | () => {
144 | const expected = grunt.file.read(
145 | './test/expected/patch_wordpress_4.diff'
146 | );
147 | const actual = grunt.file.read(
148 | './test/tmp/patch_wordpress_4_copy.diff'
149 | );
150 |
151 | expect( actual ).toEqual( expected );
152 | }
153 | );
154 |
155 | afterAll( () => {
156 | grunt.file.delete( './test/tmp/patch_wordpress_4_copy.diff' );
157 | } );
158 | } );
159 |
160 | describe( 'new and unknown stay unchanged', () => {
161 | beforeAll( () => {
162 | grunt.file.copy(
163 | './test/fixtures/patch_wordpress_5.diff',
164 | './test/tmp/patch_wordpress_5_copy.diff'
165 | );
166 | mapOldToNewFilePath(
167 | './test/tmp/patch_wordpress_5_copy.diff',
168 | fileMappings
169 | );
170 | } );
171 |
172 | it(
173 | "doesn't replaces new file paths and file paths that are not in the file mappings object in a diff file" +
174 | ' with multiple diffs',
175 | () => {
176 | const expected = grunt.file.read(
177 | './test/expected/patch_wordpress_5.diff'
178 | );
179 | const actual = grunt.file.read(
180 | './test/tmp/patch_wordpress_5_copy.diff'
181 | );
182 |
183 | expect( actual ).toEqual( expected );
184 | }
185 | );
186 |
187 | afterAll( () => {
188 | grunt.file.delete( './test/tmp/patch_wordpress_5_copy.diff' );
189 | } );
190 | } );
191 |
192 | describe( 'new and unknown stay unchanged, old to new', () => {
193 | beforeAll( () => {
194 | grunt.file.copy(
195 | './test/fixtures/patch_wordpress_6.diff',
196 | './test/tmp/patch_wordpress_6_copy.diff'
197 | );
198 | mapOldToNewFilePath(
199 | './test/tmp/patch_wordpress_6_copy.diff',
200 | fileMappings
201 | );
202 | } );
203 |
204 | it( 'only replaces old file paths in a diff file with multiple diffs', () => {
205 | const expected = grunt.file.read(
206 | './test/expected/patch_wordpress_6.diff'
207 | );
208 | const actual = grunt.file.read(
209 | './test/tmp/patch_wordpress_6_copy.diff'
210 | );
211 |
212 | expect( actual ).toEqual( expected );
213 | } );
214 |
215 | afterAll( () => {
216 | grunt.file.delete( './test/tmp/patch_wordpress_6_copy.diff' );
217 | } );
218 | } );
219 |
220 | // There is no src folder in core.
221 | describe( 'non-src old to new', () => {
222 | beforeAll( () => {
223 | grunt.file.copy(
224 | './test/fixtures/patch_wordpress_7.diff',
225 | './test/tmp/patch_wordpress_7_copy.diff'
226 | );
227 | mapOldToNewFilePath(
228 | './test/tmp/patch_wordpress_7_copy.diff',
229 | fileMappings
230 | );
231 | } );
232 |
233 | it( 'replaces old file paths with new file paths in a diff with non-src file paths', () => {
234 | const expected = grunt.file.read(
235 | './test/expected/patch_wordpress_7.diff'
236 | );
237 | const actual = grunt.file.read(
238 | './test/tmp/patch_wordpress_7_copy.diff'
239 | );
240 |
241 | expect( actual ).toEqual( expected );
242 | } );
243 |
244 | afterAll( () => {
245 | grunt.file.delete( './test/tmp/patch_wordpress_7_copy.diff' );
246 | } );
247 | } );
248 | } );
249 | } );
250 |
--------------------------------------------------------------------------------
/test/patches.js:
--------------------------------------------------------------------------------
1 | const grunt = require( 'grunt' );
2 | const patch = require( '../lib/patch.js' );
3 | const coreGit = grunt.file.read( 'test/fixtures/core.git.diff' );
4 | const coreSvn = grunt.file.read( 'test/fixtures/core.svn.diff' );
5 | const developGit = grunt.file.read( 'test/fixtures/develop.git.diff' );
6 | const developSvn = grunt.file.read( 'test/fixtures/develop.svn.diff' );
7 | const coreIndexGit = grunt.file.read( 'test/fixtures/core.git.index.diff' );
8 | const coreIndexSvn = grunt.file.read( 'test/fixtures/core.svn.index.diff' );
9 | const developIndexGit = grunt.file.read(
10 | 'test/fixtures/develop.git.index.diff'
11 | );
12 | const developIndexSvn = grunt.file.read(
13 | 'test/fixtures/develop.svn.index.diff'
14 | );
15 | const developSampleGit = grunt.file.read(
16 | 'test/fixtures/develop.git.wp-config-sample.diff'
17 | );
18 | const developSampleSvn = grunt.file.read(
19 | 'test/fixtures/develop.svn.wp-config-sample.diff'
20 | );
21 | const testsSvn = grunt.file.read( 'test/fixtures/tests.develop.svn.diff' );
22 | const testsGit = grunt.file.read( 'test/fixtures/tests.develop.git.diff' );
23 | const abyes = grunt.file.read( 'test/fixtures/git.diff.ab.diff' );
24 | const coreTrunkSvn = grunt.file.read( 'test/fixtures/core.svn.trunk.diff' );
25 |
26 | describe( 'Patch helpers', () => {
27 | it( 'git a/b diffs should not automatticaly trigger moving to src', () => {
28 | expect( patch.moveToSrc( abyes ) ).not.toBe( true );
29 | } );
30 |
31 | it( 'tests diffs should always be applied in the root of the checkout', () => {
32 | expect( patch.moveToSrc( testsGit ) ).not.toBe( true );
33 | expect( patch.moveToSrc( testsSvn ) ).not.toBe( true );
34 | } );
35 |
36 | it( 'dev.git diffs should always be applied in the root of the checkout', () => {
37 | expect( patch.moveToSrc( developGit ) ).not.toBe( true );
38 | expect( patch.moveToSrc( developIndexGit ) ).not.toBe( true );
39 | } );
40 |
41 | it( 'dev.svn diffs should always be applied in the root of the checkout', () => {
42 | expect( patch.moveToSrc( developSvn ) ).not.toBe( true );
43 | expect( patch.moveToSrc( developIndexSvn ) ).not.toBe( true );
44 | } );
45 |
46 | it( 'core.git.wordpress.org diffs should always be applied in the svn folder', () => {
47 | expect( patch.moveToSrc( coreGit ) ).toBe( true );
48 | } );
49 |
50 | it( 'core.svn.wordpress.org diffs should always be applied in the svn folder', () => {
51 | expect( patch.moveToSrc( coreSvn ) ).toBe( true );
52 | } );
53 |
54 | it( 'core.svn.wordpress.org diffs from trunk should always be applied in the src folder', () => {
55 | expect( patch.moveToSrc( coreTrunkSvn ) ).toBe( true );
56 | expect( patch.isAb( coreTrunkSvn ) ).toBe( true );
57 | } );
58 |
59 | it( 'index.php should always be applied in the src folder', () => {
60 | expect( patch.moveToSrc( coreIndexSvn ) ).toBe( true );
61 | expect( patch.moveToSrc( coreIndexGit ) ).toBe( true );
62 | } );
63 |
64 | it( 'wp-config-sample.php should always be applied in the root folder', () => {
65 | expect( patch.moveToSrc( developSampleSvn ) ).not.toBe( true );
66 | expect( patch.moveToSrc( developSampleGit ) ).not.toBe( true );
67 | } );
68 |
69 | it( 'isAb should return true on patches with a/ b/ style', () => {
70 | expect( patch.isAb( abyes ) ).toBe( true );
71 | } );
72 |
73 | it( 'isAb should return false on patches without a/ b/ style', () => {
74 | expect( patch.isAb( developSampleGit ) ).not.toBe( true );
75 | expect( patch.isAb( developSampleSvn ) ).not.toBe( true );
76 | expect( patch.isAb( coreIndexGit ) ).not.toBe( true );
77 | expect( patch.isAb( coreIndexSvn ) ).not.toBe( true );
78 | expect( patch.isAb( coreGit ) ).not.toBe( true );
79 | expect( patch.isAb( coreSvn ) ).not.toBe( true );
80 | expect( patch.isAb( developGit ) ).not.toBe( true );
81 | expect( patch.isAb( developSvn ) ).not.toBe( true );
82 | expect( patch.isAb( developIndexGit ) ).not.toBe( true );
83 | expect( patch.isAb( developIndexSvn ) ).not.toBe( true );
84 | expect( patch.isAb( testsGit ) ).not.toBe( true );
85 | expect( patch.isAb( testsSvn ) ).not.toBe( true );
86 | } );
87 | } );
88 |
--------------------------------------------------------------------------------
/test/regex.js:
--------------------------------------------------------------------------------
1 | const grunt = require( 'grunt' );
2 | const regex = require( '../lib/regex.js' );
3 | const html23988 = grunt.file.read( 'test/fixtures/23988.html' );
4 | const html23989 = grunt.file.read( 'test/fixtures/23989.html' );
5 | const html23994 = grunt.file.read( 'test/fixtures/23994.html' );
6 |
7 | describe( 'regular expressions', () => {
8 | it( 'multiple patches on a ticket with non patches as well', () => {
9 | const matches = regex.patchAttachments( html23988 );
10 | const longMatches = regex.longMatches( html23988 );
11 | const possiblePatches = regex.possiblePatches( longMatches );
12 |
13 | expect( matches.length ).toBe( 2 );
14 | expect( longMatches.length ).toBe( 4 );
15 | expect( possiblePatches ).toEqual( [
16 | 'edit-form-comment.diff (626 bytes) - added by Thaicloud 7 weeks ago.',
17 | '23988-edit-comment.diff (1.1 KB) - added by seanchayes 13 days ago.',
18 | ] );
19 | } );
20 |
21 | it( 'one patch on a ticket', () => {
22 | const matches = regex.patchAttachments( html23994 );
23 |
24 | expect( matches.length ).toBe( 1 );
25 | } );
26 |
27 | it( 'url from a list of attachments', () => {
28 | const matches = regex.patchAttachments( html23994 );
29 | const url =
30 | 'core.trac.wordpress.org' +
31 | regex.urlsFromAttachmentList( matches[ 0 ] )[ 1 ];
32 |
33 | expect( url ).toBe(
34 | 'core.trac.wordpress.org/attachment/ticket/23994/23994.diff'
35 | );
36 | } );
37 |
38 | it( 'no patches on a ticket', () => {
39 | const matches = regex.patchAttachments( html23989 );
40 |
41 | expect( matches ).toBeNull();
42 | } );
43 |
44 | it( 'filenames should be cleaned', () => {
45 | const filename = '? one.diff';
46 |
47 | expect( regex.localFileClean( filename ) ).toEqual( 'one.diff' );
48 | } );
49 |
50 | it.each( [
51 | [ 'https://github.com/WordPress/wordpress-develop/pull/740/', false ], // trailing slash
52 | [ 'https://github.com/WordPress/wordpress-develop/pull/740', false ], // no trailing slash
53 | [
54 | 'https://github.com/WordPress/wordpress-develop/pull/740/checks',
55 | false,
56 | ], // checks
57 | [
58 | 'https://github.com/WordPress/wordpress-develop/pull/740/files',
59 | false,
60 | ], // files
61 | [
62 | 'https://github.com/WordPress/wordpress-develop/pull/740.diff',
63 | false,
64 | ], // already diffed
65 | [
66 | 'https://github.com/WordPress/wordpress-develop/pull/740.patch',
67 | false,
68 | ], // already patched
69 | [
70 | 'https://patch-diff.githubusercontent.com/raw/WordPress/wordpress-develop/pull/740.diff',
71 | false,
72 | ], // already diffed and redirected
73 | [
74 | 'https://patch-diff.githubusercontent.com/raw/WordPress/wordpress-develop/pull/740.patch',
75 | false,
76 | ], // already diffed and redirected with patch
77 | [ 'https://git.com/WordPress/wordpress-develop/pull/740/files', true ], // not github url
78 | ] )( 'github url %s should get normalized', ( url, blank ) => {
79 | const expected =
80 | 'https://patch-diff.githubusercontent.com/raw/WordPress/wordpress-develop/pull/740.diff';
81 |
82 | if ( blank ) {
83 | expect( regex.githubConvert( url ) ).toBe( false );
84 | } else {
85 | expect( regex.githubConvert( url ) ).toEqual( expected );
86 | }
87 | } );
88 | } );
89 |
--------------------------------------------------------------------------------