pressship 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -109,6 +109,24 @@ Get help for any command:
109
109
  pressship <command> --help
110
110
  ```
111
111
 
112
+ ## WP-CLI Package
113
+
114
+ Pressship can also be installed as a WP-CLI package:
115
+
116
+ ```bash
117
+ wp package install f/pressship
118
+ ```
119
+
120
+ That adds a `wp ship` command:
121
+
122
+ ```bash
123
+ wp ship verify ./my-plugin
124
+ wp ship pack ./my-plugin
125
+ wp ship publish ./my-plugin --dry-run
126
+ ```
127
+
128
+ The WP-CLI package is intentionally a thin PHP bridge. It forwards arguments to the Node.js Pressship package through `npx`, so the publishing logic stays in one place. Node.js 20+ and npm/npx are still required.
129
+
112
130
  ## Authentication
113
131
 
114
132
  ```bash
package/composer.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "f/pressship",
3
+ "type": "wp-cli-package",
4
+ "description": "Run Pressship from WP-CLI by forwarding to the Node.js Pressship package.",
5
+ "homepage": "https://pressship.org",
6
+ "license": "MIT",
7
+ "require": {
8
+ "php": ">=7.4",
9
+ "wp-cli/wp-cli": "^2.8"
10
+ },
11
+ "autoload": {
12
+ "classmap": [
13
+ "wp-cli/src/"
14
+ ],
15
+ "files": [
16
+ "wp-cli/pressship-command.php"
17
+ ]
18
+ },
19
+ "extra": {
20
+ "commands": [
21
+ "ship"
22
+ ]
23
+ },
24
+ "support": {
25
+ "issues": "https://github.com/f/pressship/issues",
26
+ "source": "https://github.com/f/pressship"
27
+ }
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pressship",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Submit and release WordPress.org plugins from the command line.",
5
5
  "homepage": "https://pressship.org",
6
6
  "bin": {
@@ -9,7 +9,9 @@
9
9
  "files": [
10
10
  ".claude",
11
11
  "assets",
12
+ "composer.json",
12
13
  "dist",
14
+ "wp-cli",
13
15
  "README.md",
14
16
  "LICENSE"
15
17
  ],
@@ -0,0 +1,24 @@
1
+ <?php
2
+ /**
3
+ * Registers the Pressship WP-CLI bridge command.
4
+ *
5
+ * The implementation intentionally delegates to the Node.js Pressship package
6
+ * instead of duplicating publishing logic in PHP.
7
+ */
8
+
9
+ if ( ! class_exists( 'WP_CLI' ) ) {
10
+ return;
11
+ }
12
+
13
+ if ( ! class_exists( 'Pressship_WP_CLI_Command' ) ) {
14
+ require_once __DIR__ . '/src/Pressship_WP_CLI_Command.php';
15
+ }
16
+
17
+ WP_CLI::add_command(
18
+ 'ship',
19
+ 'Pressship_WP_CLI_Command',
20
+ array(
21
+ 'shortdesc' => 'Run the Pressship WordPress.org plugin publishing CLI.',
22
+ 'when' => 'before_wp_load',
23
+ )
24
+ );
@@ -0,0 +1,171 @@
1
+ <?php
2
+ /**
3
+ * WP-CLI command bridge for Pressship.
4
+ */
5
+
6
+ /**
7
+ * Run Pressship through WP-CLI.
8
+ */
9
+ class Pressship_WP_CLI_Command {
10
+ /**
11
+ * Invoke Pressship.
12
+ *
13
+ * This command forwards all arguments to the Node.js Pressship CLI through npx.
14
+ *
15
+ * ## OPTIONS
16
+ *
17
+ * [<args>...]
18
+ * : Arguments passed through to Pressship.
19
+ *
20
+ * [--<field>=<value>]
21
+ * : Options passed through to Pressship.
22
+ *
23
+ * ## EXAMPLES
24
+ *
25
+ * wp ship verify ./my-plugin
26
+ * wp ship pack ./my-plugin --json
27
+ * wp ship publish ./my-plugin --dry-run
28
+ *
29
+ * @when before_wp_load
30
+ *
31
+ * @param array<int, string> $args Positional arguments.
32
+ * @param array<string, mixed> $assoc_args Associative arguments.
33
+ * @return void
34
+ */
35
+ public function __invoke( $args, $assoc_args ) {
36
+ $command = self::build_command( $args, $assoc_args );
37
+
38
+ $descriptors = array( STDIN, STDOUT, STDERR );
39
+ $process = proc_open( $command, $descriptors, $pipes );
40
+ if ( ! is_resource( $process ) ) {
41
+ WP_CLI::error( 'Could not start Pressship through npx.' );
42
+ }
43
+
44
+ exit( proc_close( $process ) );
45
+ }
46
+
47
+ /**
48
+ * Build the npx command.
49
+ *
50
+ * @param array<int, string> $args Positional arguments.
51
+ * @param array<string, mixed> $assoc_args Associative arguments.
52
+ * @return string
53
+ */
54
+ public static function build_command( $args, $assoc_args ) {
55
+ $npx = getenv( 'PRESSSHIP_NPX' ) ?: self::default_npx_binary();
56
+ $package = getenv( 'PRESSSHIP_NPX_PACKAGE' ) ?: self::default_npx_package();
57
+ $argv = array_merge(
58
+ array( $npx, '--yes', '--prefix', self::npx_prefix_dir(), '--package', $package, 'pressship' ),
59
+ array_values( $args ),
60
+ self::assoc_args_to_argv( $assoc_args )
61
+ );
62
+
63
+ return self::escape_command( $argv );
64
+ }
65
+
66
+ /**
67
+ * Convert WP-CLI associative arguments to Pressship argv flags.
68
+ *
69
+ * @param array<string, mixed> $assoc_args Associative arguments.
70
+ * @return array<int, string>
71
+ */
72
+ public static function assoc_args_to_argv( $assoc_args ) {
73
+ $argv = array();
74
+
75
+ foreach ( $assoc_args as $name => $value ) {
76
+ if ( 'format' === $name && 'json' === $value ) {
77
+ $argv[] = '--json';
78
+ continue;
79
+ }
80
+
81
+ if ( is_array( $value ) ) {
82
+ foreach ( $value as $item ) {
83
+ $argv[] = self::format_assoc_arg( $name, $item );
84
+ }
85
+ continue;
86
+ }
87
+
88
+ $argv[] = self::format_assoc_arg( $name, $value );
89
+ }
90
+
91
+ return $argv;
92
+ }
93
+
94
+ /**
95
+ * Format one WP-CLI associative argument.
96
+ *
97
+ * @param string $name Argument name.
98
+ * @param mixed $value Argument value.
99
+ * @return string
100
+ */
101
+ private static function format_assoc_arg( $name, $value ) {
102
+ if ( false === $value ) {
103
+ return '--no-' . $name;
104
+ }
105
+
106
+ if ( true === $value ) {
107
+ return '--' . $name;
108
+ }
109
+
110
+ return '--' . $name . '=' . (string) $value;
111
+ }
112
+
113
+ /**
114
+ * Escape argv as a shell command.
115
+ *
116
+ * @param array<int, string> $argv Command argv.
117
+ * @return string
118
+ */
119
+ private static function escape_command( $argv ) {
120
+ return implode( ' ', array_map( 'escapeshellarg', $argv ) );
121
+ }
122
+
123
+ /**
124
+ * Default npx binary.
125
+ *
126
+ * @return string
127
+ */
128
+ private static function default_npx_binary() {
129
+ return self::is_windows() ? 'npx.cmd' : 'npx';
130
+ }
131
+
132
+ /**
133
+ * Default npm package spec.
134
+ *
135
+ * @return string
136
+ */
137
+ private static function default_npx_package() {
138
+ $package_json = dirname( __DIR__, 2 ) . '/package.json';
139
+ if ( file_exists( $package_json ) ) {
140
+ $package = json_decode( file_get_contents( $package_json ), true );
141
+ if ( is_array( $package ) && ! empty( $package['version'] ) ) {
142
+ return 'pressship@' . $package['version'];
143
+ }
144
+ }
145
+
146
+ return 'pressship';
147
+ }
148
+
149
+ /**
150
+ * Isolated npm prefix so npx does not resolve a same-named local workspace.
151
+ *
152
+ * @return string
153
+ */
154
+ private static function npx_prefix_dir() {
155
+ $directory = rtrim( sys_get_temp_dir(), DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR . 'pressship-wp-cli-npx';
156
+ if ( ! is_dir( $directory ) ) {
157
+ mkdir( $directory, 0700, true );
158
+ }
159
+
160
+ return $directory;
161
+ }
162
+
163
+ /**
164
+ * Detect Windows without depending on WP-CLI utils.
165
+ *
166
+ * @return bool
167
+ */
168
+ private static function is_windows() {
169
+ return '\\' === DIRECTORY_SEPARATOR;
170
+ }
171
+ }