Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This is the main Continuous Integration (CI) pipeline for the the stellarwp/plugin-framework package.
# Continuous Integration (CI) pipeline.
#
# Any time code is pushed to one of the main branches or a PR is opened, this pipeline should be
# run to ensure everything still works as designed and meets our coding standards.
Expand All @@ -19,16 +19,52 @@ concurrency:

jobs:

# Check coding standards (PHP_CodeSniffer, PHP-CS-Fixer, Shellcheck)
coding-standards:
name: PHPCS
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Configure PHP environment
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring
coverage: none

- uses: ramsey/composer-install@v2

- name: Run PHPCS
run: composer test:standards

# Static Code Analysis (PHPStan)
static-code-analysis:
name: PHPStan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Configure PHP environment
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, intl
coverage: none

- uses: ramsey/composer-install@v2

- name: Run PHPStan
run: composer test:analysis

# Execute all PHPUnit tests.
phpunit:
name: PHPUnit (PHP ${{ matrix.php-versions }}, WP ${{ matrix.wp-versions }})
name: PHPUnit (PHP ${{ matrix.php-versions }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Run on all versions of PHP supported by WordPress.
php-versions: ['8.0', '8.1', '8.2', '8.3']
wp-versions: ['latest']

services:
mysql:
Expand All @@ -40,7 +76,7 @@ jobs:
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=10s --health-retries=10

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Configure PHP environment
uses: shivammathur/setup-php@v2
Expand Down
49 changes: 49 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# This workflow automates the release process: when a branch matching "release/vX.Y.Z" is merged
# into "main", automatically create a new **draft** release with information about the release.
name: Release

# Only execute when a release branch has been merged into "main".
on:
pull_request:
types:
- closed
branches:
- main

jobs:

# Automatically prepare a release following a successful merge into "main".
publish-release:
if: github.event.pull_request.merged == true
name: Release to Packagist
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Determine release version
id: parse-version
env:
# Parse the version number from a branch name based on semver.
# Reference and examples of matched patterns: https://regexr.com/6jfqu
pattern: '(?:^|\/)v?\.?\K(\d+\.\d+\.\d+(-[0-9A-Za-z-]+(?:\.\d+)?)?(\+(?:\.?[0-9A-Za-z-]+)+)?)$'
run: |
version=$(grep -oP "${{ env.pattern }}" <<< "${{ github.event.pull_request.head.ref }}")
echo "::set-output name=version::$version"
echo "Parsed version: '${version}'"

- name: Create draft release
id: publish
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ steps.parse-version.outputs.version }}"
commit: main
name: ${{ github.event.pull_request.title }}
body: ${{ github.event.pull_request.body }}
draft: true
prerelease: ${{ contains(steps.publish.outputs.version, '-') }}

- name: Release details
run: |
echo "Draft release created: ${{ steps.publish.outputs.html_url }}"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ composer.lock
.php-cs-fixer.php
phpcs.xml
phpunit.xml
phpstan.neon

# Cache files.
.php_cs.cache
Expand Down
29 changes: 29 additions & 0 deletions .phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<ruleset name="Coding standards">
<!--
Usage instructions: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage
Annotated ruleset: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml
-->

<!-- What to scan: -->
<file>./src</file>
<file>./tests</file>

<rule ref="PSR12" />

<!-- Show progresss & use colors. -->
<arg value="sp"/>
<arg name="colors"/>

<!-- Enables parallel processing when available for faster results. -->
<arg name="parallel" value="8"/>

<!-- Strip the file paths down to the relevant bit and only apply to .php files. -->
<arg name="basepath" value="./"/>
<arg name="extensions" value="php"/>

<!-- PHPUnit bootstap can do different things. -->
<rule ref="PSR1.Files.SideEffects.FoundWithSymbols">
<exclude-pattern>tests/bootstrap.php</exclude-pattern>
</rule>
</ruleset>
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Installation
-----------
It is recommended to [install the composer package](https://packagist.org/packages/renventura/wp-package-parser).

```sh
composer require renventura/wp-package-parser
```

Basic usage
-----------
### Extract plugin metadata:
Expand Down
17 changes: 16 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"erusev/parsedown": "^1.7"
},
"require-dev": {
"phpunit/phpunit": "^9.6"
"phpunit/phpunit": "^9.6",
"phpstan/phpstan": "^1.11",
"squizlabs/php_codesniffer": "^3.10"
},
"autoload": {
"psr-4": {
Expand All @@ -25,18 +27,31 @@
}
},
"scripts": {
"fix:standards": [
"./vendor/bin/phpcbf ./src ./tests"
],
"test": [
"@test:all"
],
"test:all": [
"@test:analysis",
"@test:standards",
"@test:unit"
],
"test:analysis": [
"./vendor/bin/phpstan analyse -c phpstan.neon.dist --memory-limit=768M"
],
"test:standards": [
"./vendor/bin/phpcs ./src ./tests"
],
"test:unit": [
"./vendor/bin/phpunit --testdox --verbose --color=always"
]
},
"scripts-descriptions": {
"test:all": "Run all automated tests.",
"test:analysis": "Perform static code analysis.",
"test:standards": "Check coding standards.",
"test:unit": "Run all of the PHPUnit test suites."
}
}
11 changes: 11 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Configuration for PHPStan
# https://phpstan.org/config-reference

parameters:
level: 6
bootstrapFiles:
- tests/bootstrap-phpstan.php
paths:
- src
- tests

106 changes: 55 additions & 51 deletions src/Parsers/Parser.php
Original file line number Diff line number Diff line change
@@ -1,65 +1,69 @@
<?php

namespace RenVentura\WPPackageParser\Parsers;

use Parsedown;

/**
* Parser abstraction.
*/
abstract class Parser {

/**
* Header map.
*
* @var array
*/
protected $headerMap = array();
abstract class Parser
{
/**
* Header map.
*
* @var array<string, string>
*/
protected $headerMap = array();

/**
* Parse the file contents to retrieve its metadata.
*
* Searches for metadata for a file, such as a plugin or theme. Each piece of
* metadata must be on its own line. For a field spanning multiple lines, it
* must not have any newlines or only parts of it will be displayed.
*
* @param string $fileContents File contents. Can be safely truncated to 8kiB as that's all WP itself scans.
*
* @return array
*/
protected function parseHeaders( string $fileContents ) : array {
$headers = array();
$headerMap = $this->headerMap;
/**
* Parse the file contents to retrieve its metadata.
*
* Searches for metadata for a file, such as a plugin or theme. Each piece of
* metadata must be on its own line. For a field spanning multiple lines, it
* must not have any newlines or only parts of it will be displayed.
*
* @param string $fileContents File contents. Can be safely truncated to 8kiB as that's all WP itself scans.
*
* @return array<string, string>
*/
protected function parseHeaders(string $fileContents): array
{
$headers = array();
$headerMap = $this->headerMap;

// Support systems that use CR as a line ending.
$fileContents = str_replace( "\r", "\n", $fileContents );
// Support systems that use CR as a line ending.
$fileContents = str_replace("\r", "\n", $fileContents);

foreach ( $headerMap as $field => $prettyName ) {
$found = preg_match( '/^[ \t\/*#@]*' . preg_quote( $prettyName, '/' ) . ':(.*)$/mi', $fileContents, $matches );
if ( ( $found > 0 ) && ! empty( $matches[1] ) ) {
// Strip comment markers and closing PHP tags.
$value = trim( preg_replace( "/\s*(?:\*\/|\?>).*/", '', $matches[1] ) );
$headers[ $field ] = $value;
} else {
$headers[ $field ] = '';
}
}
foreach ($headerMap as $field => $prettyName) {
$found = preg_match('/^[ \t\/*#@]*' . preg_quote($prettyName, '/') . ':(.*)$/mi', $fileContents, $matches);
if (( $found > 0 ) && ! empty($matches[1])) {
// Strip comment markers and closing PHP tags.
$value = trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $matches[1]));
$headers[ $field ] = $value;
} else {
$headers[ $field ] = '';
}
}

return $headers;
}
return $headers;
}


/**
* Transform Markdown markup to HTML.
*
* Tries (in vain) to emulate the transformation that WordPress.org applies to readme.txt files.
*
* @param string $text
*
* @return string
*/
protected function applyMarkdown( string $text ) : string {
// The WP standard for readme files uses some custom markup, like "= H4 headers ="
$text = preg_replace( '@^\s*=\s*(.+?)\s*=\s*$@m', "<h4>$1</h4>\n", $text );
$markdown = new Parsedown();
return $markdown->parse( $text );
}
/**
* Transform Markdown markup to HTML.
*
* Tries (in vain) to emulate the transformation that WordPress.org applies to readme.txt files.
*
* @param string $text
*
* @return string
*/
protected function applyMarkdown(string $text): string
{
// The WP standard for readme files uses some custom markup, like "= H4 headers ="
$text = preg_replace('@^\s*=\s*(.+?)\s*=\s*$@m', "<h4>$1</h4>\n", $text);
$markdown = new Parsedown();
return $markdown->parse($text);
}
}
Loading