@webship.co/workspace-joomla 0.0.0-stage → 1.0.7

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
@@ -1,3 +1,145 @@
1
- # Temporary Holding Version
1
+ # @webship.co/workspace-joomla
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Joomla for the [Webship Workspace](https://github.com/webship/workspace) dashboard: a builder
4
+ that makes a real Joomla site in a container, a Joomla CLI tool for the sites it built, the default
5
+ accounts, the [Joomla step pack](https://github.com/webship/joomla-steps) wired into the
6
+ workspace's testing setup, and two AI agents that know all of it.
7
+
8
+ The workspace is container-based (DDEV by default): a Joomla project is a row like any other, so
9
+ the row menus the core draws (start, stop, launch, backup, clone, remove, tests) work on it unchanged.
10
+
11
+ It is made from the reference platform plugin,
12
+ [`@webship.co/workspace-wordpress`](https://github.com/webship/workspace-wordpress).
13
+
14
+ ## Use it
15
+
16
+ ```bash
17
+ cd ~/workspace
18
+ bash core/scripts/plugins.sh --require github:webship/workspace-joomla # npm install into the dashboard
19
+ bash core/scripts/plugins.sh --activate joomla # plugins.joomla in settings.yml
20
+ bash core/scripts/plugins.sh --install joomla # commands, functions, args, agents
21
+ bash core/scripts/plugins.sh --configure joomla # nothing to configure: it has no settings file
22
+ ```
23
+
24
+ The same four steps are buttons on the dashboard's **Settings → Plugins** page. `--install` is
25
+ idempotent. `--uninstall` removes what it placed; an agent you edited stays.
26
+
27
+ The commands land in the sites folders that are in the workspace (`dev`, `test`, `sandboxes`,
28
+ `demos`); the agents land in the AI Agents folder (`ai-agents/`) when the workspace has one, and are
29
+ installed into `~/.claude/agents` from there like any other agent.
30
+
31
+ It needs a Webship Workspace 1.0.7 or later.
32
+
33
+ ## What the package holds
34
+
35
+ | Path | What it is |
36
+ | --- | --- |
37
+ | `commands/cmd-joomla-project.sh` | The builder, in the Build list as **Joomla (latest)**, installed into every sites folder |
38
+ | `commands/cmd-tools-joomla-cli.sh` | The Joomla CLI for one project: what the site is, a command, updates, the default accounts |
39
+ | `scripts/functions/fun-joomla.sh` | The bash functions behind both, sourced by bootstrap once installed; the names the core's tools look for (`set_joomla_users`, `add_joomla_users`, `cancel_joomla_users`, `testing_configure_joomla`) |
40
+ | `scripts/args/arg-joomla.sh`, `arg-joomla-cli.sh` | Their argparse; the Build form draws the builder's flags from the first |
41
+ | `testing/site.feature` | The first feature a Joomla project gets when testing is set up |
42
+ | `agents/joomla-site-builder.md` | The agent that builds and maintains Joomla sites with these commands |
43
+ | `agents/joomla-tester.md` | The agent that writes and runs scenarios with the Joomla step pack |
44
+ | `src/index.ts` | `register(api)`: what the assistant is told about Joomla here |
45
+ | `features/joomla.feature` | Scenarios for the dashboard's own browser suite |
46
+
47
+ The `workspacePlugin` block in `package.json` is the manifest the installer reads.
48
+
49
+ ## The commands
50
+
51
+ Run them from a sites folder. `--help` is safe on both.
52
+
53
+ ### Build a site
54
+
55
+ ```bash
56
+ cd ~/workspace/dev
57
+ bash cmd-joomla-project.sh mysite --install --add-users
58
+ ```
59
+
60
+ | Flag | What it does |
61
+ | --- | --- |
62
+ | `--version <x>` | The release to download: `latest` (the default: the latest stable release), or a number such as `6.2.0` |
63
+ | `--install` | Install the site, with the workspace account as its Super User |
64
+ | `--add-users` | With `--install`: add the default accounts, one per user group |
65
+ | `--sample-data` | With `--install`: add the blog sample data of Joomla, and build the Smart Search index over it |
66
+ | `--php-version <x>` | The PHP of the project container (`8.3`) |
67
+ | `--launch` | Open the site when it is ready |
68
+
69
+ The site answers at `https://mysite.ddev.site`, the administrator at `/administrator`. The container
70
+ tool has no project type for Joomla, so the build runs `ddev config --project-type=php` with the
71
+ docroot `public` and the Node.js of the workspace (24), downloads the full package of the release
72
+ and unpacks it in the container, and installs with Joomla's own command-line installer. The
73
+ installer is given the container's database values (`db` / `db` / `db`), the same in every project,
74
+ and nothing personal. A project of the same name is deleted first.
75
+
76
+ Joomla refuses a password shorter than 12 characters: `--install` stops before it starts when the
77
+ workspace account's is shorter.
78
+
79
+ ### Work on a site
80
+
81
+ ```bash
82
+ bash cmd-tools-joomla-cli.sh mysite # version, address, accounts
83
+ bash cmd-tools-joomla-cli.sh mysite --run "extension:list --type=plugin"
84
+ bash cmd-tools-joomla-cli.sh mysite --run "list" # every command of the Joomla CLI
85
+ bash cmd-tools-joomla-cli.sh mysite --check # look for updates of the core and the extensions
86
+ bash cmd-tools-joomla-cli.sh mysite --update # update the core, clean the cache
87
+ bash cmd-tools-joomla-cli.sh mysite --add-users # the default accounts
88
+ bash cmd-tools-joomla-cli.sh mysite --cancel-users # delete them
89
+ ```
90
+
91
+ ### The default accounts
92
+
93
+ | Account | User group | Handle in the tests | Logs in to |
94
+ | --- | --- | --- | --- |
95
+ | `administrator` | Super Users | `admin` | the administrator and the site |
96
+ | `manager` | Manager | `manager` | the administrator and the site |
97
+ | `editor` | Editor | `editor` | the site |
98
+ | `member` | Registered | `member` | the site |
99
+
100
+ Each has the address `<account>@example.com` and the password of the workspace's other default
101
+ lists. They are for local sites and for tests; the site's own Super User is the workspace
102
+ account and is never written into a test. `bash cmd-tools-add-users.sh mysite joomla` and
103
+ `bash cmd-tools-cancel-users.sh mysite joomla` add and remove the same list.
104
+
105
+ The **Users** menu of a project row does not add them: the dashboard reads the user list of a row
106
+ from the DDEV project type, and a Joomla project is a `php` project, because the container tool has
107
+ no type for Joomla. Use the CLI tool or the two commands above.
108
+
109
+ ### Test a site
110
+
111
+ ```bash
112
+ bash cmd-tools-testing.sh mysite # webship-js, the step pack, the users registry, a first feature
113
+ bash cmd-tools-testing.sh mysite --run # run the suite in the container
114
+ bash cmd-tools-testing.sh mysite --run --path tests/features/site.feature
115
+ ```
116
+
117
+ `cmd-tools-testing.sh` is the workspace's own. For a Joomla project it also adds
118
+ `@webship-js/joomla-steps` to `package.json`, lists its step definitions in `cucumber.js` after
119
+ webship-js's own, writes the users registry (the handles above, overridable with
120
+ `JOOMLA_<HANDLE>_USER` and `JOOMLA_<HANDLE>_PASSWORD`), places `tests/features/site.feature` when the
121
+ project has none, and makes sure the default accounts are on the site. Run it again and it adds what
122
+ is missing and keeps what you changed.
123
+
124
+ ## The agents
125
+
126
+ | Agent | Use it to |
127
+ | --- | --- |
128
+ | `joomla-site-builder` | Build, update, maintain or remove a Joomla site with the commands above, in containers only |
129
+ | `joomla-tester` | Set the testing stack up, look at the site in the Playwright MCP browser first, write scenarios from the pack's steps and run them; it never creates an account in a suite and never writes a platform name into a step phrase |
130
+
131
+ After `--install` they are in the AI Agents folder of the dashboard; **Install** there puts one into
132
+ `~/.claude/agents`, or from the command line:
133
+
134
+ ```bash
135
+ cd ~/workspace/ai-agents
136
+ bash cmd-tools-ai-items.sh joomla-tester --install
137
+ ```
138
+
139
+ ## Develop it
140
+
141
+ ```bash
142
+ npm install # builds dist/ (TypeScript)
143
+ npm run lint
144
+ npm test # the manifest, the commands, the agents, the functions against a scaffolded project
145
+ ```
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: joomla-site-builder
3
+ description: Use this agent to build, maintain, update or remove a Joomla site in the Webship Workspace — a new site from `cmd-joomla-project.sh`, Joomla CLI work through `cmd-tools-joomla-cli.sh` (extensions, configuration, cache, updates, the default accounts), start, stop, backup and remove through the workspace's own tools. It works in containers only and never on the host. Invoke for "build a Joomla site", "install this extension on <site>", "update Joomla on <site>", "add the test accounts", or "remove the Joomla sandbox". For writing and running test scenarios, hand over to `joomla-tester`.
4
+ model: fable
5
+ tools:
6
+ - Bash
7
+ - Read
8
+ - Write
9
+ - Edit
10
+ - Glob
11
+ - Grep
12
+ ---
13
+
14
+ # joomla-site-builder
15
+
16
+ You build and look after Joomla sites in a Webship Workspace (`~/workspace`), a container-based
17
+ workspace (DDEV by default). Everything goes through the `cmd-*.sh` commands of a sites folder
18
+ (`dev/`, `test/`, `sandboxes/`, `demos/`) and through the project's container. The commands come from
19
+ the Joomla plugin (`@webship.co/workspace-joomla`); if a folder has no
20
+ `cmd-joomla-project.sh`, the plugin is not installed there: say so, and name the steps
21
+ (`bash core/scripts/plugins.sh --require @webship.co/workspace-joomla`, `--activate joomla`,
22
+ `--install joomla`) instead of working around it.
23
+
24
+ Read the command before quoting a flag: `bash <command> --help` is always safe.
25
+
26
+ ## Build a site
27
+
28
+ ```bash
29
+ cd ~/workspace/sandboxes # or dev, test, demos
30
+ bash cmd-joomla-project.sh mysite --install --add-users
31
+ ```
32
+
33
+ | Flag | What it does |
34
+ | --- | --- |
35
+ | `--version <x>` | The release to download: `latest` (the default: the latest stable release), or a number such as `6.2.0`. |
36
+ | `--install` | Installs the site, with the workspace account (`account:` in `core/config/settings.yml`) as its Super User. Without it the code is there and the installer waits at the site's address. |
37
+ | `--add-users` | With `--install`: the default accounts, one per user group (`administrator`, `manager`, `editor`, `member`). |
38
+ | `--sample-data` | With `--install`: the blog sample data of Joomla (articles, a menu, modules), and the Smart Search index built over it. |
39
+ | `--php-version <x>` | The PHP of the project container (`8.3` by default; Joomla 6 needs 8.3 or later). |
40
+ | `--launch` | Opens the site when it is ready. |
41
+
42
+ The site answers at `https://<name>.ddev.site`, the administrator at `/administrator`. The code is
43
+ in the `public/` folder of the project. The builder **deletes a project of the same name first**: a
44
+ build is a clean slate, so never point it at a site somebody still needs. The name is a folder, a
45
+ container project and a host name: short, lowercase, letters and digits.
46
+
47
+ Joomla refuses a password shorter than 12 characters. When the workspace account's is shorter the
48
+ builder says so before it starts: do not invent another password, ask for the setting to be changed.
49
+
50
+ ## Work on a site
51
+
52
+ ```bash
53
+ bash cmd-tools-joomla-cli.sh mysite # what it is: version, address, accounts
54
+ bash cmd-tools-joomla-cli.sh mysite --run "extension:list --type=plugin"
55
+ bash cmd-tools-joomla-cli.sh mysite --run "config:get sitename"
56
+ bash cmd-tools-joomla-cli.sh mysite --run "cache:clean"
57
+ bash cmd-tools-joomla-cli.sh mysite --check # look for updates, change nothing
58
+ bash cmd-tools-joomla-cli.sh mysite --update # the core, to the latest release of its line
59
+ bash cmd-tools-joomla-cli.sh mysite --add-users # the default accounts
60
+ bash cmd-tools-joomla-cli.sh mysite --cancel-users # and away again
61
+ ```
62
+
63
+ `--run "list"` prints every command the site's Joomla CLI has. Inside the project folder,
64
+ `ddev exec php public/cli/joomla.php <command>` is the same CLI, and `ddev composer`, `ddev npm`,
65
+ `ddev export-db --file=…`, `ddev import-db --file=…` are the tools for everything else.
66
+
67
+ The rest is the workspace's, the same for every project: `ddev start -y` and `ddev stop` in the
68
+ project (`stop` takes no `-y`), `bash cmd-tools-backup-<folder>.sh <name>`,
69
+ `bash cmd-tools-clone.sh <name> --to <new>`, `bash cmd-tools-remove.sh <name>`,
70
+ `bash cmd-tools-add-users.sh <name> joomla`, `bash cmd-tools-testing.sh <name>` (the testing
71
+ stack, with the Joomla step pack).
72
+
73
+ ## Rules
74
+
75
+ - **Containers only.** Never `php`, `composer`, `npm` or `mysql` on the host for a project.
76
+ - **The database values are the container's.** The installer is given `db` / `db` / `db` on the
77
+ host `db`, the same in every project. Do not put another host, account or password into
78
+ `configuration.php`, and do not copy that file between projects.
79
+ - **The Super User is the workspace account**, never a made-up one. Do not print its password,
80
+ do not write it into a file of the project, and do not put it in a test: the default accounts
81
+ exist for that.
82
+ - **Open-source only.** Extensions come from the Joomla Extensions Directory or a public
83
+ repository, as a package the CLI installs (`extension:install --url=…`). No paid extension, no
84
+ trial, no licence key, and no sign-in to any vendor account.
85
+ - **Remove through the tool.** `bash cmd-tools-remove.sh <name>` takes the containers, the volumes
86
+ and the folder down together; `rm -rf` leaves the containers behind.
87
+ - **One build at a time**, and look at `free -g` before a build on a busy machine. A site you built
88
+ to try something is yours to clear: when the work is done, say what you made and offer to remove
89
+ it. Never delete unasked, and never leave it unmentioned.
90
+ - **Never restart the dashboard** or anything shared (the router, another project) to make your own
91
+ work go through.
92
+ - Say what you ran and what it printed. If a build fails, show the line that failed; do not retry
93
+ with different flags until something passes.
94
+
95
+ ## When something is off
96
+
97
+ | What you see | What it is |
98
+ | --- | --- |
99
+ | `The Joomla <x> package could not be downloaded or unpacked` | No network in the container, or a version that does not exist: `--version latest` proves which. |
100
+ | `Joomla asks for a password of 12 characters or more` | The workspace account's password is too short for Joomla: it is changed in `core/config/settings.yml`, by its owner. |
101
+ | The installer page instead of the site | The build ran without `--install`: finish it in the browser, or build again with `--install`. |
102
+ | `Error displaying the error page` or a database error | The project is stopped (`ddev start -y`), or `configuration.php` was replaced: its database values are `db` / `db` / `db` on the host `db`. |
103
+ | The site search finds nothing | The Smart Search index is empty: `--run "finder:index"`. |
104
+ | **Add the test users** in the row's Users menu adds no Joomla account | The menu reads the DDEV project type, and a Joomla project is a `php` project. Use `bash cmd-tools-joomla-cli.sh <name> --add-users` or `bash cmd-tools-add-users.sh <name> joomla`. |
105
+ | `is not a Joomla project` from the CLI tool | The project's docroot has no `cli/joomla.php`: it was not built by this builder. |
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: joomla-tester
3
+ description: Use this agent to test a Joomla site of the Webship Workspace with webship-js and the Joomla step pack (`@webship-js/joomla-steps`) — set the testing stack up with `cmd-tools-testing.sh`, explore the site in the Playwright MCP browser first, write Gherkin scenarios from the pack's own steps, run them in the project's container and read the report. It logs in by the handles of the users registry, never creates an account in a suite, and never writes a platform name into a step phrase. Invoke for "test this Joomla site", "write scenarios for the manager group", "why does this scenario fail", or "run the suite on <site>". For building or changing the site itself, hand over to `joomla-site-builder`.
4
+ model: fable
5
+ tools:
6
+ - Bash
7
+ - Read
8
+ - Write
9
+ - Edit
10
+ - Glob
11
+ - Grep
12
+ - mcp__playwright__browser_navigate
13
+ - mcp__playwright__browser_snapshot
14
+ - mcp__playwright__browser_click
15
+ - mcp__playwright__browser_type
16
+ - mcp__playwright__browser_evaluate
17
+ - mcp__playwright__browser_tabs
18
+ - mcp__playwright__browser_take_screenshot
19
+ ---
20
+
21
+ # joomla-tester
22
+
23
+ You test Joomla sites in a Webship Workspace (`~/workspace`) with
24
+ [webship-js](https://github.com/webship/webship-js) (Playwright and Cucumber) and its Joomla step
25
+ pack, [`@webship-js/joomla-steps`](https://github.com/webship/joomla-steps). The suite lives in
26
+ the project (`cucumber.js`, `tests/features/`, `tests/step-definitions/`) and runs in the project's
27
+ container.
28
+
29
+ ## Set the stack up
30
+
31
+ ```bash
32
+ cd ~/workspace/test # the sites folder the project is in
33
+ bash cmd-tools-testing.sh mysite # webship-js, the step pack, the users registry, a first feature
34
+ ```
35
+
36
+ For a Joomla project the setup adds the pack to `package.json`, lists its step definitions in
37
+ `cucumber.js` after webship-js's own, writes the users registry and `tests/features/site.feature`,
38
+ and makes sure the default accounts are on the site. It is idempotent: run it again and it adds
39
+ what is missing, and keeps what you changed.
40
+
41
+ ## The order of work
42
+
43
+ 1. **Read the installed steps.** They are the source of truth, not memory:
44
+ ```bash
45
+ ls node_modules/@webship-js/joomla-steps/tests/step-definitions/
46
+ grep -n "^\(Given\|When\|Then\)" node_modules/@webship-js/joomla-steps/tests/step-definitions/joomla.steps.js
47
+ ```
48
+ Each step carries a JSDoc block with examples. webship-js's own steps (status codes, classes,
49
+ landmarks, accessibility) are in `node_modules/webship-js/tests/step-definitions/`.
50
+ 2. **Look at the site in the Playwright MCP browser first**, in a tab of your own: open the page,
51
+ take a snapshot, do the thing by hand once. A scenario written without having seen the page
52
+ asserts what you imagine. Close your tab when you are done; leave other tabs alone.
53
+ 3. **Write the scenario** from steps that exist. Run a dry run before a real one:
54
+ ```bash
55
+ bash cmd-tools-testing.sh mysite --dry-run # every step matches one definition, no browser
56
+ ```
57
+ 4. **Run it**, narrow first, then the whole suite:
58
+ ```bash
59
+ bash cmd-tools-testing.sh mysite --run --path tests/features/site.feature
60
+ bash cmd-tools-testing.sh mysite --run --tags "@critical"
61
+ bash cmd-tools-testing.sh mysite --run
62
+ ```
63
+ 5. **Read the result**: `tests/reports/cucumber_report.html`, the screenshot and the page dump of a
64
+ failed step in `tests/screenshots/`. Report what failed and why, not only that it failed.
65
+
66
+ ## Accounts
67
+
68
+ A scenario logs in by a **handle** of the users registry (`worldParameters.users` in `cucumber.js`).
69
+ The site and the administrator have a login each, and a step for each:
70
+
71
+ ```gherkin
72
+ Given I am a logged in user with the "manager" user # the administrator
73
+ Given I am logged in to the site with the "member" user # the site
74
+ ```
75
+
76
+ | Handle | Account | User group | Logs in to |
77
+ | --- | --- | --- | --- |
78
+ | `admin` | `administrator` | Super Users | the administrator and the site |
79
+ | `manager` | `manager` | Manager | the administrator and the site |
80
+ | `editor` | `editor` | Editor | the site |
81
+ | `member` | `member` | Registered | the site |
82
+
83
+ These are the default accounts (`bash cmd-tools-joomla-cli.sh mysite --add-users`). Override one
84
+ for another environment with `JOOMLA_<HANDLE>_USER` and `JOOMLA_<HANDLE>_PASSWORD`. A step that
85
+ names an account on a list (`the user "manager" should be in the "Manager" group`) takes the
86
+ account's username, not the handle.
87
+
88
+ ## Rules
89
+
90
+ - **Never create an account in a suite.** No `user:add` in a hook, no registration scenario
91
+ that leaves an account behind, no step that adds one. Accounts are configuration: they are on the
92
+ site before the suite runs. If a scenario needs a group the registry does not have, say so and ask
93
+ for the account to be added to the site and to the registry.
94
+ - **Never the workspace account.** The site's own Super User (the workspace account) is not in
95
+ the registry and its password goes in no file. `admin` in the registry is the `administrator`
96
+ default account.
97
+ - **No password in a feature file**, except where a wrong password is the subject of the scenario.
98
+ - **No platform name in a step phrase.** A step says what a person does or sees: `I am on the login
99
+ page`, `I should see the administrator dashboard`, `I go to the administrator "Users" page`. Never
100
+ a phrase with the platform's name in it. The same holds for a custom step you write.
101
+ - **No CSS selector and no address in a scenario when a step of the pack says it.** `the
102
+ administrator "Users" page`, not `/administrator/index.php?option=com_users`.
103
+ - **A custom step is the last resort.** Look in the pack and in webship-js first. If one is really
104
+ missing, write it in `tests/step-definitions/`, with a JSDoc block and examples like the pack's,
105
+ and say that it may belong upstream.
106
+ - **Content a scenario creates, it removes**, or it names it so a later run finds and clears it. A
107
+ suite leaves the site as it found it.
108
+ - **Everything runs in the container.** Never `npx cucumber-js` or `npx playwright` on the host for
109
+ a project.
110
+ - **A failing suite is a result.** Do not tag a scenario `@wip`, raise a timeout or loosen an
111
+ assertion to make a run green. Say what the site did.
112
+
113
+ ## A scenario, the way the pack reads
114
+
115
+ ```gherkin
116
+ Feature: A manager looks after the articles
117
+
118
+ Scenario: The manager opens the list of articles
119
+ Given I am a logged in user with the "manager" user
120
+ When I go to the administrator "Articles" page
121
+ Then the response status code should be 200
122
+ And I should see the administrator menu
123
+ ```
124
+
125
+ Check every phrase against the installed definitions before you run it: the pack moves, and a phrase
126
+ from memory is a guess.
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # workspace-name: Joomla (latest)
4
+
5
+ # Installed by the Joomla plugin (plugins.sh --install joomla); __WORKSPACE__ is the workspace it was installed into.
6
+ #
7
+ # Build a Joomla site in a container: the latest stable release, or the one --version names, at
8
+ # https://<name>.ddev.site. With --install the site is installed with the workspace account as its
9
+ # Super User; with --add-users it also gets the default accounts, one per user group.
10
+
11
+ # Bootstrap.
12
+ # Find the workspace tooling from this script, so a fresh clone needs no setup.
13
+ WORKSPACE_SCRIPTS="${WORKSPACE_SCRIPTS:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../core/scripts" && pwd)}";
14
+ source ${WORKSPACE_SCRIPTS}/bootstrap.sh || exit 1 ;
15
+
16
+ # Load workspace settings.
17
+ eval $(parse_yaml ${WORKSPACE_CONFIG}/workspace.__WORKSPACE__.settings.yml);
18
+
19
+ # Set site version.
20
+ site_version="latest";
21
+
22
+ # Distribution.
23
+ distribution_name="joomla";
24
+ distribution_title="Joomla";
25
+ distribution_webroot="public";
26
+
27
+ ARGPARSE_DESCRIPTION="Build a ${distribution_title} project in __WORKSPACE__"
28
+ # The args file comes with the plugin: core/scripts/plugins/joomla/ is where plugins.sh --install puts it.
29
+ source ${WORKSPACE_SCRIPTS}/plugins/joomla/args/arg-joomla.sh || exit 1 ;
30
+
31
+ shift $#;
32
+
33
+ joomla_build ;
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Installed by the Joomla plugin (plugins.sh --install joomla); __WORKSPACE__ is the workspace it was installed into.
4
+ #
5
+ # The Joomla CLI (cli/joomla.php) for one Joomla project of this workspace, in its container: say
6
+ # what the site is, run a CLI command, update the core, look for updates, add or remove the default
7
+ # accounts. Nothing here runs on the host.
8
+
9
+ # Bootstrap.
10
+ # Find the workspace tooling from this script, so a fresh clone needs no setup.
11
+ WORKSPACE_SCRIPTS="${WORKSPACE_SCRIPTS:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../core/scripts" && pwd)}";
12
+ source ${WORKSPACE_SCRIPTS}/bootstrap.sh || exit 1 ;
13
+
14
+ # Load workspace settings.
15
+ eval $(parse_yaml ${WORKSPACE_CONFIG}/workspace.__WORKSPACE__.settings.yml);
16
+
17
+ # Distribution.
18
+ distribution_name="joomla";
19
+
20
+ ARGPARSE_DESCRIPTION="Run the Joomla CLI on a Joomla project of __WORKSPACE__: status, a command, updates, the default accounts"
21
+ # The args file comes with the plugin: core/scripts/plugins/joomla/ is where plugins.sh --install puts it.
22
+ source ${WORKSPACE_SCRIPTS}/plugins/joomla/args/arg-joomla-cli.sh || exit 1 ;
23
+
24
+ shift $#;
25
+
26
+ joomla_cli_tool ;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Joomla for Webship Workspace: a platform plugin.
3
+ *
4
+ * What the package carries is placed by the installer from the manifest: the builder and the
5
+ * Joomla CLI tool in the sites folders, their functions and argparse under core/scripts/plugins/joomla/,
6
+ * the agents in the AI Agents folder. The dashboard needs nothing drawn for it: the builder is in the
7
+ * Build list because it is a cmd-*-project.sh, the row menus are the core's, the agents are listed
8
+ * like any other. What register() adds is what the assistant is told.
9
+ *
10
+ * Everything the dashboard is asked for goes through `api`; this package requires nothing from the
11
+ * dashboard's own files, so it can be installed from npm and removed without a trace.
12
+ */
13
+ import type { PluginApi } from '@webship.co/workspace-plugin-api';
14
+ /** The plugin's name, which its functions and its user list are named after. */
15
+ export declare const PLATFORM = "joomla";
16
+ /** The commands the installer places in every sites folder. */
17
+ export declare const COMMANDS: string[];
18
+ /** The agents the installer places in the AI Agents folder. */
19
+ export declare const AGENTS: string[];
20
+ /** What the assistant is told about Joomla in this workspace. */
21
+ export declare function assistantContext(): string;
22
+ export declare function register(api: PluginApi): void;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ /**
3
+ * Joomla for Webship Workspace: a platform plugin.
4
+ *
5
+ * What the package carries is placed by the installer from the manifest: the builder and the
6
+ * Joomla CLI tool in the sites folders, their functions and argparse under core/scripts/plugins/joomla/,
7
+ * the agents in the AI Agents folder. The dashboard needs nothing drawn for it: the builder is in the
8
+ * Build list because it is a cmd-*-project.sh, the row menus are the core's, the agents are listed
9
+ * like any other. What register() adds is what the assistant is told.
10
+ *
11
+ * Everything the dashboard is asked for goes through `api`; this package requires nothing from the
12
+ * dashboard's own files, so it can be installed from npm and removed without a trace.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.AGENTS = exports.COMMANDS = exports.PLATFORM = void 0;
16
+ exports.assistantContext = assistantContext;
17
+ exports.register = register;
18
+ /** The plugin's name, which its functions and its user list are named after. */
19
+ exports.PLATFORM = 'joomla';
20
+ /** The commands the installer places in every sites folder. */
21
+ exports.COMMANDS = ['cmd-joomla-project.sh', 'cmd-tools-joomla-cli.sh'];
22
+ /** The agents the installer places in the AI Agents folder. */
23
+ exports.AGENTS = ['joomla-site-builder', 'joomla-tester'];
24
+ /** What the assistant is told about Joomla in this workspace. */
25
+ function assistantContext() {
26
+ return [
27
+ 'Joomla (a plugin, @webship.co/workspace-joomla): a Joomla site is built with',
28
+ '`bash cmd-joomla-project.sh <name> --install --add-users` from a sites folder (dev, test, sandboxes, demos),',
29
+ 'in a container like every other project, at https://<name>.ddev.site (the administrator at /administrator).',
30
+ '`bash cmd-tools-joomla-cli.sh <name>` says what the site is; `--run "<command>"` runs the Joomla CLI (cli/joomla.php) in it,',
31
+ '`--update` updates the core, `--check` looks for updates, `--add-users` adds the default accounts (one per user group).',
32
+ '`bash cmd-tools-add-users.sh <name> joomla` adds the same accounts.',
33
+ '`bash cmd-tools-testing.sh <name>` sets up webship-js with the Joomla step pack; `--run` runs the suite.',
34
+ `For Joomla work, hand over to the agents ${exports.AGENTS.map((a) => `\`${a}\``).join(' and ')}.`,
35
+ 'Never run php, composer, npm or mysql on the host for a project.',
36
+ ].join(' ');
37
+ }
38
+ function register(api) {
39
+ api.addAssistantContext(assistantContext);
40
+ }
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAcH,4CAYC;AAED,4BAEC;AA1BD,gFAAgF;AACnE,QAAA,QAAQ,GAAG,QAAQ,CAAC;AAEjC,+DAA+D;AAClD,QAAA,QAAQ,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,CAAC,CAAC;AAE7E,+DAA+D;AAClD,QAAA,MAAM,GAAG,CAAC,qBAAqB,EAAE,eAAe,CAAC,CAAC;AAE/D,iEAAiE;AACjE,SAAgB,gBAAgB;IAC9B,OAAO;QACL,8EAA8E;QAC9E,8GAA8G;QAC9G,6GAA6G;QAC7G,8HAA8H;QAC9H,yHAAyH;QACzH,qEAAqE;QACrE,0GAA0G;QAC1G,4CAA4C,cAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG;QAC1F,kEAAkE;KACnE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,SAAgB,QAAQ,CAAC,GAAc;IACrC,GAAG,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,17 @@
1
+ Feature: The Joomla plugin on the dashboard
2
+ Once the plugin is activated and installed, the sites folders offer the Joomla builder, the
3
+ AI Agents folder lists the Joomla agents, and the Plugins page lists the plugin with its steps.
4
+
5
+ Scenario: The plugin is listed on the Plugins page
6
+ Given I am on "/settings/plugins"
7
+ Then I should see "Joomla"
8
+ And I should see "@webship.co/workspace-joomla"
9
+
10
+ Scenario: A sites folder offers the Joomla builder
11
+ Given I am on "/dev"
12
+ Then "option[value='cmd-joomla-project.sh']" should be attached
13
+
14
+ Scenario: The AI Agents folder lists the agents the plugin ships
15
+ Given I am on "/ai-agents"
16
+ Then I should see "joomla-site-builder"
17
+ And I should see "joomla-tester"
package/package.json CHANGED
@@ -1,6 +1,75 @@
1
1
  {
2
2
  "name": "@webship.co/workspace-joomla",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.7",
4
+ "description": "Joomla for Webship Workspace: the builder (`cmd-joomla-project.sh`) and the Joomla CLI tool in every sites folder, the default accounts, the Joomla step pack wired into the testing setup, and two AI agents in the AI Agents folder.",
5
+ "main": "dist/src/index.js",
6
+ "types": "dist/src/index.d.ts",
7
+ "license": "ISC",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/webship/workspace-joomla.git"
11
+ },
12
+ "files": [
13
+ "dist/src",
14
+ "agents",
15
+ "commands",
16
+ "features",
17
+ "scripts",
18
+ "testing",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "prepare": "npm run build",
24
+ "test": "npm run build && node --test dist/tests/*.test.js",
25
+ "lint": "tsc -p tsconfig.json --noEmit"
26
+ },
27
+ "workspacePlugin": {
28
+ "name": "joomla",
29
+ "label": "Joomla",
30
+ "commands": {
31
+ "types": [
32
+ "sites"
33
+ ],
34
+ "workspaces": [
35
+ "dev",
36
+ "test",
37
+ "sandboxes",
38
+ "demos"
39
+ ],
40
+ "files": [
41
+ "commands/cmd-joomla-project.sh",
42
+ "commands/cmd-tools-joomla-cli.sh"
43
+ ]
44
+ },
45
+ "scripts": {
46
+ "functions": [
47
+ "scripts/functions/fun-joomla.sh"
48
+ ],
49
+ "args": [
50
+ "scripts/args/arg-joomla.sh",
51
+ "scripts/args/arg-joomla-cli.sh"
52
+ ],
53
+ "machine": [
54
+ "testing/site.feature"
55
+ ]
56
+ },
57
+ "ai": {
58
+ "agents": [
59
+ "agents/joomla-site-builder.md",
60
+ "agents/joomla-tester.md"
61
+ ]
62
+ },
63
+ "features": [
64
+ "features/joomla.feature"
65
+ ]
66
+ },
67
+ "devDependencies": {
68
+ "@types/node": "^24.0.0",
69
+ "@webship.co/workspace-plugin-api": "^1.0.7",
70
+ "typescript": "^5.9.0"
71
+ },
72
+ "publishConfig": {
73
+ "access": "public"
74
+ }
75
+ }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+
3
+ argparse "$@" <<ARGEOF || exit 1
4
+ parser.add_argument('PROJECT_NAME',
5
+ help='The Joomla project in this workspace.')
6
+ parser.add_argument('-r', '--run',
7
+ default="_none_",
8
+ help='A Joomla CLI command to run in the project, without the leading php cli/joomla.php. Example: --run "extension:list --type=plugin"')
9
+ parser.add_argument('-u', '--update',
10
+ action='store_true',
11
+ default=False,
12
+ help='Update Joomla itself to the latest release of its line, and clean the cache.')
13
+ parser.add_argument('-k', '--check',
14
+ action='store_true',
15
+ default=False,
16
+ help='Look for updates of Joomla and of its extensions, and change nothing.')
17
+ parser.add_argument('-a', '--add-users',
18
+ action='store_true',
19
+ default=False,
20
+ help='Add the default accounts, one per user group. An account that is already there is left as it is.')
21
+ parser.add_argument('-c', '--cancel-users',
22
+ action='store_true',
23
+ default=False,
24
+ help='Delete the default accounts.')
25
+ ARGEOF
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+
3
+ argparse "$@" <<ARGEOF || exit 1
4
+ parser.add_argument('PROJECT_NAME',
5
+ help='The name of the project: its folder, its DDEV project and its host name.')
6
+ parser.add_argument('-v', '--version',
7
+ default="${site_version}",
8
+ help='The Joomla release to download: latest, or a version number. Example: --version 6.2.0 [default %(default)s]')
9
+ parser.add_argument('-i', '--install',
10
+ action='store_true',
11
+ default=False,
12
+ help='Install Joomla, with the workspace account as the Super User.')
13
+ parser.add_argument('-a', '--add-users',
14
+ action='store_true',
15
+ default=False,
16
+ help='With --install, add the default accounts: one per user group, the ones the test scenarios log in as.')
17
+ parser.add_argument('-s', '--sample-data',
18
+ action='store_true',
19
+ default=False,
20
+ help='With --install, add the blog sample data of Joomla: articles, a menu and modules.')
21
+ parser.add_argument('-l', '--launch',
22
+ action='store_true',
23
+ default=False,
24
+ help='Open the site in a browser when it is ready.')
25
+ parser.add_argument('--php-version',
26
+ default="8.3",
27
+ choices=['8.5', '8.4', '8.3'],
28
+ help='PHP version for the project container. Example: --php-version 8.4 [default %(default)s]')
29
+ ARGEOF
@@ -0,0 +1,387 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Joomla for the Webship Workspace: build a site, run the Joomla CLI on it, add its default
4
+ # accounts, and wire its step pack into the testing setup.
5
+ #
6
+ # Placed by `plugins.sh --install joomla` in core/scripts/plugins/joomla/functions/, where
7
+ # bootstrap sources it after the core's own functions. Everything runs in the project's container
8
+ # (DDEV by default: `ddev exec php <docroot>/cli/joomla.php …`), never on the host.
9
+ #
10
+ # The container tool has no project type for Joomla, so a Joomla project is a `php` project that
11
+ # carries the Joomla CLI in its docroot; that file is how the functions here recognise one. The
12
+ # installer is given the container's own database values (db / db / db) and nothing personal.
13
+ #
14
+ # Four names are the ones the core's tools look for:
15
+ # set_joomla_users the default accounts (cmd-tools-add-users.sh <project> joomla)
16
+ # add_joomla_users create them with the Joomla CLI (the same tool, and --add-users of the builder)
17
+ # cancel_joomla_users delete them (cmd-tools-cancel-users.sh <project> joomla)
18
+ # testing_configure_joomla the step pack in the testing stack (cmd-tools-testing.sh <project>)
19
+
20
+ # The step pack a Joomla project is tested with, and the release line it is required at.
21
+ readonly JOOMLA_STEPS_PACKAGE='@webship-js/joomla-steps';
22
+ readonly JOOMLA_STEPS_VERSION='^2.1.0';
23
+
24
+ # The release a build falls back on when the latest one cannot be read: the one this plugin was proven on.
25
+ readonly JOOMLA_PROVEN_VERSION='6.2.0';
26
+
27
+ # Joomla refuses a password shorter than this.
28
+ readonly JOOMLA_PASSWORD_LENGTH=12;
29
+
30
+ # The default accounts: one per user group a scenario logs in as. Accounts are configuration,
31
+ # created once on the site; a test suite never creates or deletes one. The role is the Joomla
32
+ # user group, by its title.
33
+ function set_joomla_users() {
34
+ users=(administrator manager editor member);
35
+ local groups=('Super Users' 'Manager' 'Editor' 'Registered') i user ;
36
+ for i in "${!users[@]}" ; do
37
+ user="${users[$i]}" ;
38
+ printf -v "user_${user}_name" '%s' "${user}" ;
39
+ printf -v "user_${user}_mail" '%s' "${user}@example.com" ;
40
+ printf -v "user_${user}_password" '%s' 'dD.123123ddd' ;
41
+ printf -v "user_${user}_role" '%s' "${groups[$i]}" ;
42
+ done
43
+ }
44
+
45
+ # The docroot of a project, from its own container configuration.
46
+ function joomla_docroot() {
47
+ local project_path="$1" docroot ;
48
+ docroot="$(grep -E '^docroot:' "${project_path}/.ddev/config.yaml" 2>/dev/null | head -1 | sed -E 's/^docroot:[[:space:]]*//; s/^"(.*)"$/\1/; s/[[:space:]]*$//')" ;
49
+ printf '%s' "${docroot}" ;
50
+ }
51
+
52
+ # Where the Joomla CLI is, from the project root: <docroot>/cli/joomla.php.
53
+ function joomla_cli_path() {
54
+ local docroot ; docroot="$(joomla_docroot "$1")" ;
55
+ printf '%s' "${docroot:+${docroot}/}cli/joomla.php" ;
56
+ }
57
+
58
+ # Is this folder a Joomla project? The Joomla CLI and the administrator in its docroot say so.
59
+ function joomla_is_project() {
60
+ local project_path="$1" docroot ;
61
+ [ -f "${project_path}/.ddev/config.yaml" ] || return 1 ;
62
+ docroot="$(joomla_docroot "${project_path}")" ;
63
+ [ -f "${project_path}/${docroot:+${docroot}/}cli/joomla.php" ] && [ -d "${project_path}/${docroot:+${docroot}/}administrator" ] ;
64
+ }
65
+
66
+ # Is the site installed? The installer writes configuration.php, and nothing else does.
67
+ function joomla_is_installed() {
68
+ local project_path="$1" docroot ;
69
+ docroot="$(joomla_docroot "${project_path}")" ;
70
+ [ -f "${project_path}/${docroot:+${docroot}/}configuration.php" ] ;
71
+ }
72
+
73
+ # Go to the project a tool was asked about, or say why not.
74
+ function joomla_enter_project() {
75
+ local project_path="${WORKSPACE_ROOT}/${doc_name}/${PROJECT_NAME}";
76
+ if [ ! -d "${project_path}" ] ; then
77
+ echo "No project ${PROJECT_NAME} in ${WORKSPACE_ROOT}/${doc_name}." ;
78
+ return 1 ;
79
+ fi
80
+ if ! joomla_is_project "${project_path}" ; then
81
+ echo "${doc_name}/${PROJECT_NAME} is not a Joomla project (its docroot has no cli/joomla.php)." ;
82
+ return 1 ;
83
+ fi
84
+ cd "${project_path}" || return 1 ;
85
+ }
86
+
87
+ # Run the Joomla CLI in the container of the project the shell is in. Every argument is quoted
88
+ # for the container's shell, so a name with a space ("Super Users") arrives as one argument.
89
+ function joomla_cli() {
90
+ local line arg ;
91
+ line="php $(joomla_cli_path "$(pwd)")" ;
92
+ for arg in "$@" ; do
93
+ line="${line} $(printf '%q' "${arg}")" ;
94
+ done
95
+ ddev exec "${line}" ;
96
+ }
97
+
98
+ # Is there an account of this username on the site?
99
+ function joomla_user_exists() {
100
+ # A row of the list: the number of the account, then its username.
101
+ joomla_cli user:list --no-interaction 2>/dev/null | grep -qE "^[[:space:]]*[0-9]+[[:space:]]+$1[[:space:]]" ;
102
+ }
103
+
104
+ # The number of the latest stable release, read in the container from where the releases are
105
+ # published; the proven release when it cannot be read.
106
+ function joomla_latest_version() {
107
+ local version ;
108
+ version="$(ddev exec "curl -fsSI https://github.com/joomla/joomla-cms/releases/latest" 2>/dev/null \
109
+ | tr -d '\r' | sed -nE 's#^[Ll]ocation:.*/tag/([0-9][0-9A-Za-z.-]*)$#\1#p' | head -1)" ;
110
+ printf '%s' "${version:-${JOOMLA_PROVEN_VERSION}}" ;
111
+ }
112
+
113
+ # Build a Joomla site from nothing: the container, the code, and with --install the site itself.
114
+ function joomla_build() {
115
+ trim_project_name ;
116
+ local base_url="https://${PROJECT_NAME}.ddev.site" ;
117
+ local version="${VERSION:-${site_version:-latest}}" ;
118
+ local php_version="${PHP_VERSION:-${site_php_version:-8.3}}" ;
119
+ local docroot="${distribution_webroot}" ;
120
+ local web="${docroot:+${docroot}/}" ;
121
+
122
+ if [ "${INSTALL}" == 'yes' ] && [ "${#account_pass}" -lt "${JOOMLA_PASSWORD_LENGTH}" ] ; then
123
+ echo "Joomla asks for a password of ${JOOMLA_PASSWORD_LENGTH} characters or more, and the workspace account's is shorter." ;
124
+ echo "Change account: pass in core/config/settings.yml, or build without --install." ;
125
+ exit 1 ;
126
+ fi
127
+
128
+ cd ${WORKSPACE_ROOT}/${doc_name} || exit 1 ;
129
+
130
+ drop_database ;
131
+ rm -rf "${PROJECT_NAME}" ;
132
+ mkdir -p "${PROJECT_NAME}/${docroot}" ;
133
+ cd ${WORKSPACE_ROOT}/${doc_name}/${PROJECT_NAME} || exit 1 ;
134
+
135
+ ddev config --project-type=php --docroot="${docroot}" --project-name=${PROJECT_NAME} \
136
+ --php-version=${php_version} --webserver-type=nginx-fpm --nodejs-version=$(ddev_nodejs_version) || exit 1 ;
137
+ ddev_up start -y || exit 1 ;
138
+
139
+ [ "${version}" == 'latest' ] && version="$(joomla_latest_version)" ;
140
+ local package="https://github.com/joomla/joomla-cms/releases/download/${version}/Joomla_${version}-Stable-Full_Package.zip" ;
141
+ echo "Downloading Joomla ${version}." ;
142
+ ddev exec "curl -fsSL -o /tmp/joomla.zip '${package}' && unzip -q -o /tmp/joomla.zip -d '/var/www/html/${docroot}' && rm -f /tmp/joomla.zip" \
143
+ || { echo "The Joomla ${version} package could not be downloaded or unpacked." ; exit 1 ; } ;
144
+
145
+ if [ "${INSTALL}" == 'yes' ] ; then
146
+ # The container's own database values, the same in every project: nothing personal is written.
147
+ ddev exec "php ${web}installation/joomla.php install --no-interaction \
148
+ --site-name=$(printf '%q' "${doc_name} ${PROJECT_NAME}") \
149
+ --admin-user=$(printf '%q' "${account_name}") --admin-username=$(printf '%q' "${account_name}") \
150
+ --admin-password=$(printf '%q' "${account_pass}") --admin-email=$(printf '%q' "${account_mail}") \
151
+ --db-type=mysqli --db-host=db --db-user=db --db-pass=db --db-name=db --db-prefix=jos_" \
152
+ || { echo "The Joomla installer failed." ; exit 1 ; } ;
153
+
154
+ # The administrator asks every new site to share anonymous statistics, with a notice on each
155
+ # page. A local site answers "never" once.
156
+ ddev mysql -e "UPDATE jos_extensions SET params='{\"mode\":3}' WHERE element='stats' AND folder='system'" ;
157
+
158
+ if [ "${SAMPLE_DATA}" == 'yes' ] ; then
159
+ joomla_sample_data ;
160
+ fi
161
+
162
+ if [ "${ADD_USERS}" == 'yes' ] ; then
163
+ set_joomla_users ;
164
+ add_joomla_users ;
165
+ cd ${WORKSPACE_ROOT}/${doc_name}/${PROJECT_NAME} || exit 1 ;
166
+ fi
167
+
168
+ echo "${doc_name} ${PROJECT_NAME} has been installed: Joomla ${version}.";
169
+ echo "Go to ${base_url}/administrator and log in as ${account_name}";
170
+ else
171
+ [ "${ADD_USERS}" == 'yes' ] && echo "--add-users needs --install: there is no site to add accounts to yet." ;
172
+ [ "${SAMPLE_DATA}" == 'yes' ] && echo "--sample-data needs --install: there is no site to add content to yet." ;
173
+ echo "${doc_name} ${PROJECT_NAME} is ready to install.";
174
+ echo "Go to ${base_url}";
175
+ fi
176
+
177
+ if [ "${LAUNCH}" == 'yes' ] ; then
178
+ ddev launch ;
179
+ fi
180
+
181
+ cd ${WORKSPACE_ROOT}/${doc_name};
182
+ }
183
+
184
+ # The "blog" sample data of Joomla: articles, a menu and the modules that show them. Joomla
185
+ # offers it through the administrator only, so the container logs in as the workspace account,
186
+ # the way a browser would, and asks for each of its four steps in order; then the Smart Search
187
+ # index is built, which the sample data leaves empty. The password travels in the container's
188
+ # environment for that one command and is written nowhere.
189
+ function joomla_sample_data() {
190
+ echo "Adding the blog sample data." ;
191
+ ddev exec "JOOMLA_USER=$(printf '%q' "${account_name}") JOOMLA_PASSWORD=$(printf '%q' "${account_pass}") bash -s" <<'SAMPLEEOF' || { echo " The sample data could not be added; the site itself is installed." ; return 1 ; } ;
192
+ set -e
193
+ site="${DDEV_PRIMARY_URL%/}"
194
+ jar="$(mktemp)"
195
+ trap 'rm -f "${jar}"' EXIT
196
+ admin="${site}/administrator/index.php"
197
+ login_token="$(curl -ksL -c "${jar}" "${admin}" | grep -oP '(?<=name=")[a-f0-9]{32}(?=" value="1")' | head -1)"
198
+ curl -ksL -o /dev/null -b "${jar}" -c "${jar}" "${admin}" \
199
+ --data-urlencode "username=${JOOMLA_USER}" --data-urlencode "passwd=${JOOMLA_PASSWORD}" \
200
+ --data-urlencode "option=com_login" --data-urlencode "task=login" \
201
+ --data-urlencode "return=aW5kZXgucGhw" --data-urlencode "${login_token}=1"
202
+ # A token of the session that is now open: the one of the login form is stale by now.
203
+ token="$(curl -ksL -b "${jar}" -c "${jar}" "${admin}" | grep -oP '(?<=csrf.token":")[a-f0-9]{32}' | head -1)"
204
+ [ -n "${token}" ] || { echo " The administrator did not open a session." ; exit 1 ; }
205
+ # In order: the second step makes the menu the third one attaches the modules to.
206
+ for step in 1 2 3 4 ; do
207
+ curl -ksL -b "${jar}" -c "${jar}" -o /dev/null \
208
+ "${admin}?option=com_ajax&group=sampledata&type=blog&plugin=SampledataApplyStep${step}&format=json&${token}=1"
209
+ done
210
+ SAMPLEEOF
211
+ joomla_cli finder:index --no-interaction ;
212
+ }
213
+
214
+ # Create the default accounts with the Joomla CLI. An account that is already there is left as it is.
215
+ # The list is loaded by the caller (set_joomla_users): the core's add_users, the builder, the CLI tool.
216
+ function add_joomla_users() {
217
+ joomla_enter_project || return 1 ;
218
+ local user user_name user_mail user_password user_role ;
219
+ for user in "${users[@]}" ; do
220
+ user_name="user_${user}_name"; user_mail="user_${user}_mail";
221
+ user_password="user_${user}_password"; user_role="user_${user}_role";
222
+
223
+ echo " ---------------------------------------------------------------- ";
224
+ echo " User name: ${!user_name}";
225
+ echo " User mail: ${!user_mail}";
226
+ echo " User password: ${!user_password}";
227
+ echo " User role: ${!user_role}";
228
+ echo " ================================================================= ";
229
+
230
+ if joomla_user_exists "${!user_name}" ; then
231
+ echo " ${!user_name} is already there." ;
232
+ else
233
+ joomla_cli user:add --no-interaction --username="${!user_name}" --name="${!user_name^}" \
234
+ --password="${!user_password}" --email="${!user_mail}" --usergroup="${!user_role}" ;
235
+ fi
236
+ done
237
+ cd ${WORKSPACE_ROOT}/${doc_name};
238
+ }
239
+
240
+ # Delete the default accounts.
241
+ function cancel_joomla_users() {
242
+ joomla_enter_project || return 1 ;
243
+ local user user_name ;
244
+ for user in "${users[@]}" ; do
245
+ user_name="user_${user}_name";
246
+ echo " ---------------------------------------------------------------- ";
247
+ echo " User name: ${!user_name}";
248
+ echo " ================================================================= ";
249
+ if joomla_user_exists "${!user_name}" ; then
250
+ joomla_cli user:delete --no-interaction --username="${!user_name}" ;
251
+ else
252
+ echo " ${!user_name} is not there." ;
253
+ fi
254
+ done
255
+ cd ${WORKSPACE_ROOT}/${doc_name};
256
+ }
257
+
258
+ # What cmd-tools-joomla-cli.sh does: the first of --run, --update, --check, --add-users,
259
+ # --cancel-users that was asked for; with none of them, what the site is.
260
+ function joomla_cli_tool() {
261
+ trim_project_name ;
262
+ joomla_enter_project || exit 1 ;
263
+
264
+ if ! ddev describe -j 2>/dev/null | grep -q '"status":"running"' ; then
265
+ ddev start -y || exit 1 ;
266
+ fi
267
+
268
+ if [ ! "${RUN}" == '_none_' ] ; then
269
+ # One string on purpose: --run "extension:list --type=plugin" is a command and its arguments.
270
+ ddev exec "php $(joomla_cli_path "$(pwd)") ${RUN}" ;
271
+ exit $? ;
272
+ fi
273
+
274
+ if [ "${UPDATE}" == 'yes' ] ; then
275
+ joomla_cli core:update --no-interaction && joomla_cli cache:clean --no-interaction ;
276
+ elif [ "${CHECK}" == 'yes' ] ; then
277
+ joomla_cli core:check-updates --no-interaction ;
278
+ joomla_cli update:extensions:check --no-interaction ;
279
+ elif [ "${ADD_USERS}" == 'yes' ] ; then
280
+ set_joomla_users ;
281
+ add_joomla_users ;
282
+ elif [ "${CANCEL_USERS}" == 'yes' ] ; then
283
+ set_joomla_users ;
284
+ cancel_joomla_users ;
285
+ else
286
+ echo "${doc_name}/${PROJECT_NAME}: $(joomla_cli --version 2>/dev/null | head -1) at https://${PROJECT_NAME}.ddev.site" ;
287
+ if joomla_is_installed "$(pwd)" ; then
288
+ echo "" ; echo "Accounts:" ; joomla_cli user:list --no-interaction ;
289
+ else
290
+ echo "The site is not installed yet: open its address, or build it again with --install." ;
291
+ fi
292
+ fi
293
+ cd ${WORKSPACE_ROOT}/${doc_name};
294
+ }
295
+
296
+ # The step pack in the testing stack of a Joomla project. The core's testing_configure calls
297
+ # this in the project folder once webship-js is scaffolded and before the dependencies are
298
+ # installed; for a project that is not Joomla it changes nothing.
299
+ #
300
+ # It adds the pack to package.json, lists its step definitions in cucumber.js after webship-js's
301
+ # own, gives cucumber.js the users registry of the default accounts (a handle a scenario reads,
302
+ # mapped to an account; never the workspace account), and writes a first feature when the project
303
+ # has none of its own. Every part is skipped when it is already there, so a second run adds what
304
+ # the first missed and never resets a suite.
305
+ function testing_configure_joomla() {
306
+ local project_path="$1";
307
+ joomla_is_project "${project_path}" || return 0 ;
308
+ if [ ! -f "${project_path}/cucumber.js" ] || [ ! -f "${project_path}/package.json" ] ; then
309
+ echo " Joomla: cucumber.js is not here yet — run the testing setup again once webship-js is scaffolded." ;
310
+ return 1 ;
311
+ fi
312
+
313
+ echo "Adding the Joomla step pack (${JOOMLA_STEPS_PACKAGE} ${JOOMLA_STEPS_VERSION}).";
314
+ set_joomla_users ;
315
+ local registry="" user user_name user_password handle ;
316
+ for user in "${users[@]}" ; do
317
+ user_name="user_${user}_name"; user_password="user_${user}_password";
318
+ # The pack's features call the Super User "admin".
319
+ handle="${user}" ; [ "${user}" == 'administrator' ] && handle="admin" ;
320
+ registry="${registry}${handle}|${!user_name}|${!user_password}"$'\n' ;
321
+ done
322
+
323
+ python3 - "${project_path}" "${JOOMLA_STEPS_PACKAGE}" "${JOOMLA_STEPS_VERSION}" 'JOOMLA' "${registry}" <<'PYEOF' || return 1
324
+ import json, re, sys
325
+
326
+ project, pack, version, prefix, registry = sys.argv[1:6]
327
+
328
+ # package.json: the pack as a dev dependency, at the release line this plugin was proven on.
329
+ pkg_file = project + '/package.json'
330
+ pkg = json.load(open(pkg_file))
331
+ if pack not in pkg.get('dependencies', {}) and pack not in pkg.get('devDependencies', {}):
332
+ pkg.setdefault('devDependencies', {})[pack] = version
333
+ open(pkg_file, 'w').write(json.dumps(pkg, indent=2) + '\n')
334
+ print(' package.json: %s %s' % (pack, version))
335
+
336
+ # cucumber.js: the pack's step definitions after webship-js's own, and the users registry.
337
+ cucumber_file = project + '/cucumber.js'
338
+ src = open(cucumber_file).read()
339
+ before = src
340
+
341
+ if ('node_modules/%s/' % pack) not in src:
342
+ line = "'node_modules/%s/tests/step-definitions/**/*.js'," % pack
343
+ core = re.search(r"^([ \t]*)'node_modules/webship-js/tests/step-definitions/[^']*',.*$", src, re.M)
344
+ opening = re.search(r"^([ \t]*)require:[ \t]*\[[ \t]*$", src, re.M)
345
+ if core:
346
+ src = src[:core.end()] + '\n' + core.group(1) + line + src[core.end():]
347
+ elif opening:
348
+ src = src[:opening.end()] + '\n' + opening.group(1) + ' ' + line + src[opening.end():]
349
+ else:
350
+ sys.exit(" cucumber.js has no require list this can add to. Add this line to it:\n " + line)
351
+ print(' cucumber.js: the step definitions of %s' % pack)
352
+
353
+ if not re.search(r"^[ \t]*users:[ \t]*\{", src, re.M):
354
+ world = re.search(r"^([ \t]*)worldParameters:[ \t]*\{[ \t]*$", src, re.M)
355
+ if not world:
356
+ sys.exit(" cucumber.js has no worldParameters block to add the users registry to.")
357
+ pad = world.group(1) + ' '
358
+ rows = [r.split('|') for r in registry.splitlines() if r.strip()]
359
+ block = [
360
+ pad + "// The users registry: a handle a scenario reads, mapped to an account of this site (the default",
361
+ pad + "// accounts: cmd-tools-add-users.sh). Override one with %s_<HANDLE>_USER and %s_<HANDLE>_PASSWORD." % (prefix, prefix),
362
+ pad + "users: {",
363
+ ]
364
+ for handle, name, password in rows:
365
+ env = '%s_%s' % (prefix, handle.upper())
366
+ block.append(pad + " %s: { username: process.env.%s_USER || '%s', password: process.env.%s_PASSWORD || '%s' }," % (handle, env, name, env, password))
367
+ block.append(pad + "},")
368
+ src = src[:world.end()] + '\n' + '\n'.join(block) + src[world.end():]
369
+ print(' cucumber.js: the users registry (%s)' % ', '.join(r[0] for r in rows))
370
+
371
+ if src != before:
372
+ open(cucumber_file, 'w').write(src)
373
+ PYEOF
374
+
375
+ # A first feature, when the project has none for the site yet: the front page, the login page,
376
+ # each default account in its group.
377
+ local feature="${WORKSPACE_SCRIPTS}/plugins/joomla/site.feature" ;
378
+ if [ -f "${feature}" ] && [ ! -f "${project_path}/tests/features/site.feature" ] ; then
379
+ mkdir -p "${project_path}/tests/features" && cp "${feature}" "${project_path}/tests/features/site.feature" \
380
+ && echo " tests/features/site.feature: a first feature for the site" ;
381
+ fi
382
+
383
+ # The scenarios log in as the default accounts: make sure an installed site has them.
384
+ if joomla_is_installed "${project_path}" ; then
385
+ ( add_joomla_users > /dev/null ) && echo " the default accounts are on the site (${users[*]})" ;
386
+ fi
387
+ }
@@ -0,0 +1,64 @@
1
+ Feature: The site answers and its accounts work
2
+ As the owner of the site
3
+ I want the front page, the login page and each default account to work
4
+ So that a build that came out broken is caught before anything else is tested
5
+
6
+ # Placed by the workspace's testing setup as a starting point: it is yours to change.
7
+ # The accounts are the default ones (cmd-tools-add-users.sh); a scenario logs in by a handle of
8
+ # the users registry in cucumber.js, so no password is written here.
9
+
10
+ @critical
11
+ Scenario: The front page is served
12
+ Given I am an anonymous user
13
+ And I am on the homepage
14
+ Then the response status code should be 200
15
+ And the page should have a title
16
+
17
+ @critical
18
+ Scenario: The login page is served with its form
19
+ Given I am on the login page
20
+ Then the response status code should be 200
21
+ And I should see the login form
22
+
23
+ Scenario Outline: Each default account is on the site, in the group of its role
24
+ Given I am a logged in user with the "admin" user
25
+ Then the user "<account>" should exist
26
+ And the user "<account>" should be enabled
27
+ And the user "<account>" should be in the "<group>" group
28
+
29
+ Examples:
30
+ | account | group |
31
+ | administrator | Super Users |
32
+ | manager | Manager |
33
+ | editor | Editor |
34
+ | member | Registered |
35
+
36
+ Scenario Outline: An account of the administrator logs in to it
37
+ Given I am a logged in user with the "<handle>" user
38
+ Then I should see the administrator dashboard
39
+ And I should see the administrator menu
40
+
41
+ Examples:
42
+ | handle |
43
+ | admin |
44
+ | manager |
45
+
46
+ Scenario Outline: An account of the site logs in to it
47
+ Given I am logged in to the site with the "<handle>" user
48
+ Then I should be logged in to the site as "<handle>"
49
+
50
+ Examples:
51
+ | handle |
52
+ | editor |
53
+ | member |
54
+
55
+ Scenario: An account is refused a page its group may not open
56
+ Given I am a logged in user with the "manager" user
57
+ When I go to the administrator "Users" page
58
+ Then the response status code should be 403
59
+
60
+ Scenario: An anonymous visitor has no session
61
+ Given I am not logged in
62
+ When I am on the profile page
63
+ Then I should see the login form
64
+ And I should not be logged in to the site