Merge branch 'dev' into version/03
# Conflicts: # README.md
This commit is contained in:
26
.github/CLAUDE.md
vendored
26
.github/CLAUDE.md
vendored
@@ -122,13 +122,13 @@ BRIEF: One-line description
|
|||||||
|
|
||||||
### Joomla Version Alignment
|
### Joomla Version Alignment
|
||||||
|
|
||||||
The version in `README.md` **must always match** the `<version>` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically.
|
The version in `README.md` **must always match** the `<version>` tag in `manifest.xml` and the latest entry in `updates.xml`. The `make release` command / release workflow updates all three automatically.
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<!-- In manifest.xml — must match README.md version -->
|
<!-- In manifest.xml — must match README.md version -->
|
||||||
<version>01.02.04</version>
|
<version>01.02.04</version>
|
||||||
|
|
||||||
<!-- In update.xml — prepend a new <update> block for every release.
|
<!-- In updates.xml — prepend a new <update> block for every release.
|
||||||
Note: the backslash in version="4\.[0-9]+" is a literal backslash character
|
Note: the backslash in version="4\.[0-9]+" is a literal backslash character
|
||||||
in the XML attribute value. Joomla's update server treats the value as a
|
in the XML attribute value. Joomla's update server treats the value as a
|
||||||
regular expression, so \. matches a literal dot. -->
|
regular expression, so \. matches a literal dot. -->
|
||||||
@@ -154,7 +154,7 @@ The version in `README.md` **must always match** the `<version>` tag in `manifes
|
|||||||
```
|
```
|
||||||
MokoCassiopeia/
|
MokoCassiopeia/
|
||||||
├── manifest.xml # Joomla installer manifest (root — required)
|
├── manifest.xml # Joomla installer manifest (root — required)
|
||||||
├── update.xml # Update server manifest (root — required, see below)
|
├── updates.xml # Update server manifest (root — required, see below)
|
||||||
├── site/ # Frontend (site) code
|
├── site/ # Frontend (site) code
|
||||||
│ ├── controller.php
|
│ ├── controller.php
|
||||||
│ ├── controllers/
|
│ ├── controllers/
|
||||||
@@ -183,22 +183,22 @@ MokoCassiopeia/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## update.xml — Required in Repo Root
|
## updates.xml — Required in Repo Root
|
||||||
|
|
||||||
`update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension.
|
`updates.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension.
|
||||||
|
|
||||||
The `manifest.xml` must reference it via:
|
The `manifest.xml` must reference it via:
|
||||||
```xml
|
```xml
|
||||||
<updateservers>
|
<updateservers>
|
||||||
<server type="extension" priority="1" name="{{EXTENSION_NAME}}">
|
<server type="extension" priority="1" name="{{EXTENSION_NAME}}">
|
||||||
https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/update.xml
|
https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/updates.xml
|
||||||
</server>
|
</server>
|
||||||
</updateservers>
|
</updateservers>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Rules:**
|
**Rules:**
|
||||||
- Every release must prepend a new `<update>` block at the top of `update.xml` — old entries must be preserved below.
|
- Every release must prepend a new `<update>` block at the top of `updates.xml` — old entries must be preserved below.
|
||||||
- The `<version>` in `update.xml` must exactly match `<version>` in `manifest.xml` and the version in `README.md`.
|
- The `<version>` in `updates.xml` must exactly match `<version>` in `manifest.xml` and the version in `README.md`.
|
||||||
- The `<downloadurl>` must be a publicly accessible direct download link (GitHub Releases asset URL).
|
- The `<downloadurl>` must be a publicly accessible direct download link (GitHub Releases asset URL).
|
||||||
- `<targetplatform name="joomla" version="4\.[0-9]+">` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it.
|
- `<targetplatform name="joomla" version="4\.[0-9]+">` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it.
|
||||||
|
|
||||||
@@ -207,8 +207,8 @@ The `manifest.xml` must reference it via:
|
|||||||
## manifest.xml Rules
|
## manifest.xml Rules
|
||||||
|
|
||||||
- Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`).
|
- Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`).
|
||||||
- `<version>` tag must be kept in sync with `README.md` version and `update.xml`.
|
- `<version>` tag must be kept in sync with `README.md` version and `updates.xml`.
|
||||||
- Must include `<updateservers>` block pointing to this repo's `update.xml`.
|
- Must include `<updateservers>` block pointing to this repo's `updates.xml`.
|
||||||
- Must include `<files folder="site">` and `<administration>` sections.
|
- Must include `<files folder="site">` and `<administration>` sections.
|
||||||
- Joomla 4.x requires `<namespace path="src">Moko\{{EXTENSION_NAME}}</namespace>` for namespaced extensions.
|
- Joomla 4.x requires `<namespace path="src">Moko\{{EXTENSION_NAME}}</namespace>` for namespaced extensions.
|
||||||
|
|
||||||
@@ -286,8 +286,8 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d
|
|||||||
| Change type | Documentation to update |
|
| Change type | Documentation to update |
|
||||||
|-------------|------------------------|
|
|-------------|------------------------|
|
||||||
| New or renamed PHP class/method | PHPDoc block; `docs/api/` entry |
|
| New or renamed PHP class/method | PHPDoc block; `docs/api/` entry |
|
||||||
| New or changed manifest.xml | Update `update.xml` version; bump README.md version |
|
| New or changed manifest.xml | Update `updates.xml` version; bump README.md version |
|
||||||
| New release | Prepend `<update>` block to `update.xml`; update CHANGELOG.md; bump README.md version |
|
| New release | Prepend `<update>` block to `updates.xml`; update CHANGELOG.md; bump README.md version |
|
||||||
| New or changed workflow | `docs/workflows/<workflow-name>.md` |
|
| New or changed workflow | `docs/workflows/<workflow-name>.md` |
|
||||||
| Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block |
|
| Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block |
|
||||||
| **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it |
|
| **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it |
|
||||||
@@ -301,4 +301,4 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d
|
|||||||
- Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files
|
- Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files
|
||||||
- Never hardcode version numbers in body text — update `README.md` and let automation propagate
|
- Never hardcode version numbers in body text — update `README.md` and let automation propagate
|
||||||
- Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN`
|
- Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN`
|
||||||
- Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync
|
- Never let `manifest.xml` version, `updates.xml` version, and `README.md` version go out of sync
|
||||||
|
|||||||
24
.github/CODEOWNERS
vendored
24
.github/CODEOWNERS
vendored
@@ -8,8 +8,26 @@
|
|||||||
# Combined with branch protection (require PR reviews), this prevents
|
# Combined with branch protection (require PR reviews), this prevents
|
||||||
# unauthorized modifications to workflows, configs, and governance files.
|
# unauthorized modifications to workflows, configs, and governance files.
|
||||||
|
|
||||||
# ── Workflows (synced from MokoStandards — must not be manually edited) ──
|
# ── Synced workflows (managed by MokoStandards — do not edit manually) ────
|
||||||
/.github/workflows/ @jmiller-moko
|
/.github/workflows/deploy-dev.yml @jmiller-moko
|
||||||
|
/.github/workflows/deploy-demo.yml @jmiller-moko
|
||||||
|
/.github/workflows/deploy-rs.yml @jmiller-moko
|
||||||
|
/.github/workflows/auto-release.yml @jmiller-moko
|
||||||
|
/.github/workflows/auto-dev-issue.yml @jmiller-moko
|
||||||
|
/.github/workflows/auto-assign.yml @jmiller-moko
|
||||||
|
/.github/workflows/sync-version-on-merge.yml @jmiller-moko
|
||||||
|
/.github/workflows/enterprise-firewall-setup.yml @jmiller-moko
|
||||||
|
/.github/workflows/repository-cleanup.yml @jmiller-moko
|
||||||
|
/.github/workflows/standards-compliance.yml @jmiller-moko
|
||||||
|
/.github/workflows/codeql-analysis.yml @jmiller-moko
|
||||||
|
/.github/workflows/repo_health.yml @jmiller-moko
|
||||||
|
/.github/workflows/ci-joomla.yml @jmiller-moko
|
||||||
|
/.github/workflows/update-server.yml @jmiller-moko
|
||||||
|
/.github/workflows/deploy-manual.yml @jmiller-moko
|
||||||
|
/.github/workflows/ci-dolibarr.yml @jmiller-moko
|
||||||
|
/.github/workflows/publish-to-mokodolimods.yml @jmiller-moko
|
||||||
|
/.github/workflows/changelog-validation.yml @jmiller-moko
|
||||||
|
# Custom workflows in .github/workflows/ not listed above are repo-owned.
|
||||||
|
|
||||||
# ── GitHub configuration ─────────────────────────────────────────────────
|
# ── GitHub configuration ─────────────────────────────────────────────────
|
||||||
/.github/ISSUE_TEMPLATE/ @jmiller-moko
|
/.github/ISSUE_TEMPLATE/ @jmiller-moko
|
||||||
@@ -23,7 +41,7 @@
|
|||||||
/composer.json @jmiller-moko
|
/composer.json @jmiller-moko
|
||||||
/phpstan.neon @jmiller-moko
|
/phpstan.neon @jmiller-moko
|
||||||
/Makefile @jmiller-moko
|
/Makefile @jmiller-moko
|
||||||
/.ftp_ignore @jmiller-moko
|
/.ftpignore @jmiller-moko
|
||||||
/.gitignore @jmiller-moko
|
/.gitignore @jmiller-moko
|
||||||
/.gitattributes @jmiller-moko
|
/.gitattributes @jmiller-moko
|
||||||
/.editorconfig @jmiller-moko
|
/.editorconfig @jmiller-moko
|
||||||
|
|||||||
26
.github/copilot-instructions.md
vendored
26
.github/copilot-instructions.md
vendored
@@ -122,13 +122,13 @@ BRIEF: One-line description
|
|||||||
|
|
||||||
### Joomla Version Alignment
|
### Joomla Version Alignment
|
||||||
|
|
||||||
The version in `README.md` **must always match** the `<version>` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically.
|
The version in `README.md` **must always match** the `<version>` tag in `manifest.xml` and the latest entry in `updates.xml`. The `make release` command / release workflow updates all three automatically.
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<!-- In manifest.xml — must match README.md version -->
|
<!-- In manifest.xml — must match README.md version -->
|
||||||
<version>01.02.04</version>
|
<version>01.02.04</version>
|
||||||
|
|
||||||
<!-- In update.xml — prepend a new <update> block for every release.
|
<!-- In updates.xml — prepend a new <update> block for every release.
|
||||||
Note: the backslash in version="4\.[0-9]+" is a literal backslash character
|
Note: the backslash in version="4\.[0-9]+" is a literal backslash character
|
||||||
in the XML attribute value. Joomla's update server treats the value as a
|
in the XML attribute value. Joomla's update server treats the value as a
|
||||||
regular expression, so \. matches a literal dot. -->
|
regular expression, so \. matches a literal dot. -->
|
||||||
@@ -154,7 +154,7 @@ The version in `README.md` **must always match** the `<version>` tag in `manifes
|
|||||||
```
|
```
|
||||||
MokoCassiopeia/
|
MokoCassiopeia/
|
||||||
├── manifest.xml # Joomla installer manifest (root — required)
|
├── manifest.xml # Joomla installer manifest (root — required)
|
||||||
├── update.xml # Update server manifest (root — required, see below)
|
├── updates.xml # Update server manifest (root — required, see below)
|
||||||
├── site/ # Frontend (site) code
|
├── site/ # Frontend (site) code
|
||||||
│ ├── controller.php
|
│ ├── controller.php
|
||||||
│ ├── controllers/
|
│ ├── controllers/
|
||||||
@@ -183,22 +183,22 @@ MokoCassiopeia/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## update.xml — Required in Repo Root
|
## updates.xml — Required in Repo Root
|
||||||
|
|
||||||
`update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension.
|
`updates.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension.
|
||||||
|
|
||||||
The `manifest.xml` must reference it via:
|
The `manifest.xml` must reference it via:
|
||||||
```xml
|
```xml
|
||||||
<updateservers>
|
<updateservers>
|
||||||
<server type="extension" priority="1" name="{{EXTENSION_NAME}}">
|
<server type="extension" priority="1" name="{{EXTENSION_NAME}}">
|
||||||
https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/update.xml
|
https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/updates.xml
|
||||||
</server>
|
</server>
|
||||||
</updateservers>
|
</updateservers>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Rules:**
|
**Rules:**
|
||||||
- Every release must prepend a new `<update>` block at the top of `update.xml` — old entries must be preserved below.
|
- Every release must prepend a new `<update>` block at the top of `updates.xml` — old entries must be preserved below.
|
||||||
- The `<version>` in `update.xml` must exactly match `<version>` in `manifest.xml` and the version in `README.md`.
|
- The `<version>` in `updates.xml` must exactly match `<version>` in `manifest.xml` and the version in `README.md`.
|
||||||
- The `<downloadurl>` must be a publicly accessible direct download link (GitHub Releases asset URL).
|
- The `<downloadurl>` must be a publicly accessible direct download link (GitHub Releases asset URL).
|
||||||
- `<targetplatform name="joomla" version="4\.[0-9]+">` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it.
|
- `<targetplatform name="joomla" version="4\.[0-9]+">` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it.
|
||||||
|
|
||||||
@@ -207,8 +207,8 @@ The `manifest.xml` must reference it via:
|
|||||||
## manifest.xml Rules
|
## manifest.xml Rules
|
||||||
|
|
||||||
- Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`).
|
- Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`).
|
||||||
- `<version>` tag must be kept in sync with `README.md` version and `update.xml`.
|
- `<version>` tag must be kept in sync with `README.md` version and `updates.xml`.
|
||||||
- Must include `<updateservers>` block pointing to this repo's `update.xml`.
|
- Must include `<updateservers>` block pointing to this repo's `updates.xml`.
|
||||||
- Must include `<files folder="site">` and `<administration>` sections.
|
- Must include `<files folder="site">` and `<administration>` sections.
|
||||||
- Joomla 4.x requires `<namespace path="src">Moko\{{EXTENSION_NAME}}</namespace>` for namespaced extensions.
|
- Joomla 4.x requires `<namespace path="src">Moko\{{EXTENSION_NAME}}</namespace>` for namespaced extensions.
|
||||||
|
|
||||||
@@ -286,8 +286,8 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d
|
|||||||
| Change type | Documentation to update |
|
| Change type | Documentation to update |
|
||||||
|-------------|------------------------|
|
|-------------|------------------------|
|
||||||
| New or renamed PHP class/method | PHPDoc block; `docs/api/` entry |
|
| New or renamed PHP class/method | PHPDoc block; `docs/api/` entry |
|
||||||
| New or changed manifest.xml | Update `update.xml` version; bump README.md version |
|
| New or changed manifest.xml | Update `updates.xml` version; bump README.md version |
|
||||||
| New release | Prepend `<update>` block to `update.xml`; update CHANGELOG.md; bump README.md version |
|
| New release | Prepend `<update>` block to `updates.xml`; update CHANGELOG.md; bump README.md version |
|
||||||
| New or changed workflow | `docs/workflows/<workflow-name>.md` |
|
| New or changed workflow | `docs/workflows/<workflow-name>.md` |
|
||||||
| Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block |
|
| Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block |
|
||||||
| **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it |
|
| **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it |
|
||||||
@@ -301,4 +301,4 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d
|
|||||||
- Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files
|
- Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files
|
||||||
- Never hardcode version numbers in body text — update `README.md` and let automation propagate
|
- Never hardcode version numbers in body text — update `README.md` and let automation propagate
|
||||||
- Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN`
|
- Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN`
|
||||||
- Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync
|
- Never let `manifest.xml` version, `updates.xml` version, and `README.md` version go out of sync
|
||||||
|
|||||||
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -5,7 +5,7 @@
|
|||||||
# INGROUP: MokoStandards.Security
|
# INGROUP: MokoStandards.Security
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /.github/dependabot.yml
|
# PATH: /.github/dependabot.yml
|
||||||
# VERSION: 01.00.00
|
# VERSION: 03.09.03
|
||||||
# BRIEF: Dependabot configuration for automated dependency updates and security patches
|
# BRIEF: Dependabot configuration for automated dependency updates and security patches
|
||||||
# NOTE: Monitors GitHub Actions for vulnerabilities and keeps ecosystem secure
|
# NOTE: Monitors GitHub Actions for vulnerabilities and keeps ecosystem secure
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/auto-assign.yml
vendored
2
.github/workflows/auto-assign.yml
vendored
@@ -6,7 +6,7 @@
|
|||||||
# INGROUP: MokoStandards.Workflows.Shared
|
# INGROUP: MokoStandards.Workflows.Shared
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /.github/workflows/auto-assign.yml
|
# PATH: /.github/workflows/auto-assign.yml
|
||||||
# VERSION: 04.05.11
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Auto-assign jmiller-moko to unassigned issues and PRs every 15 minutes
|
# BRIEF: Auto-assign jmiller-moko to unassigned issues and PRs every 15 minutes
|
||||||
|
|
||||||
name: Auto-Assign Issues & PRs
|
name: Auto-Assign Issues & PRs
|
||||||
|
|||||||
51
.github/workflows/auto-dev-issue.yml
vendored
51
.github/workflows/auto-dev-issue.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.Automation
|
# INGROUP: MokoStandards.Automation
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/auto-dev-issue.yml.template
|
# PATH: /templates/workflows/shared/auto-dev-issue.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow
|
# BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow
|
||||||
# NOTE: Synced via bulk-repo-sync to .github/workflows/auto-dev-issue.yml in all governed repos.
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/auto-dev-issue.yml in all governed repos.
|
||||||
|
|
||||||
@@ -39,7 +39,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >-
|
if: >-
|
||||||
(github.event_name == 'workflow_dispatch') ||
|
(github.event_name == 'workflow_dispatch') ||
|
||||||
(github.event.ref_type == 'branch' && startsWith(github.event.ref, 'rc/'))
|
(github.event.ref_type == 'branch' &&
|
||||||
|
(startsWith(github.event.ref, 'rc/') ||
|
||||||
|
startsWith(github.event.ref, 'alpha/') ||
|
||||||
|
startsWith(github.event.ref, 'beta/')))
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Create tracking issue and sub-issues
|
- name: Create tracking issue and sub-issues
|
||||||
@@ -62,6 +65,16 @@ jobs:
|
|||||||
BRANCH_TYPE="Release Candidate"
|
BRANCH_TYPE="Release Candidate"
|
||||||
LABEL_TYPE="type: release"
|
LABEL_TYPE="type: release"
|
||||||
TITLE_PREFIX="rc"
|
TITLE_PREFIX="rc"
|
||||||
|
elif [[ "$BRANCH" == beta/* ]]; then
|
||||||
|
VERSION="${BRANCH#beta/}"
|
||||||
|
BRANCH_TYPE="Beta"
|
||||||
|
LABEL_TYPE="type: release"
|
||||||
|
TITLE_PREFIX="beta"
|
||||||
|
elif [[ "$BRANCH" == alpha/* ]]; then
|
||||||
|
VERSION="${BRANCH#alpha/}"
|
||||||
|
BRANCH_TYPE="Alpha"
|
||||||
|
LABEL_TYPE="type: release"
|
||||||
|
TITLE_PREFIX="alpha"
|
||||||
else
|
else
|
||||||
VERSION="${BRANCH#dev/}"
|
VERSION="${BRANCH#dev/}"
|
||||||
BRANCH_TYPE="Development"
|
BRANCH_TYPE="Development"
|
||||||
@@ -80,14 +93,20 @@ jobs:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Define sub-issues for the dev workflow ────────────────────────
|
# ── Define sub-issues for the workflow ─────────────────────────
|
||||||
if [[ "$BRANCH" == rc/* ]]; then
|
if [[ "$BRANCH" == rc/* ]]; then
|
||||||
SUB_ISSUES=(
|
SUB_ISSUES=(
|
||||||
"RC Testing|Verify all features work on rc branch|type: test,release-candidate"
|
"RC Testing|Verify all features work on rc branch|type: test,release-candidate"
|
||||||
"Regression Testing|Run full regression suite before merge to main|type: test,release-candidate"
|
"Regression Testing|Run full regression suite before merge|type: test,release-candidate"
|
||||||
"Version Bump|Bump version in README.md and all headers|type: version,release-candidate"
|
"Version Bump|Bump version in README.md and all headers|type: version,release-candidate"
|
||||||
"Changelog Update|Update CHANGELOG.md with release notes|documentation,release-candidate"
|
"Changelog Update|Update CHANGELOG.md with release notes|documentation,release-candidate"
|
||||||
"Merge to Main|Create PR from rc branch to main|type: release,needs-review"
|
"Merge to Version Branch|Create PR to version/XX|type: release,needs-review"
|
||||||
|
)
|
||||||
|
elif [[ "$BRANCH" == alpha/* ]] || [[ "$BRANCH" == beta/* ]]; then
|
||||||
|
SUB_ISSUES=(
|
||||||
|
"Testing|Verify features on ${BRANCH_TYPE} branch|type: test,status: in-progress"
|
||||||
|
"Bug Fixes|Fix issues found during ${BRANCH_TYPE} testing|type: bug,status: pending"
|
||||||
|
"Promote to Next Stage|Create PR to promote to next release stage|type: release,needs-review"
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
SUB_ISSUES=(
|
SUB_ISSUES=(
|
||||||
@@ -156,22 +175,26 @@ jobs:
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── RC: Create or update release-candidate release ──────────────
|
# ── Create or update prerelease for alpha/beta/rc ────────────────
|
||||||
if [[ "$BRANCH" == rc/* ]]; then
|
if [[ "$BRANCH" == rc/* ]] || [[ "$BRANCH" == alpha/* ]] || [[ "$BRANCH" == beta/* ]]; then
|
||||||
RELEASE_TAG="release-candidate"
|
case "$BRANCH_TYPE" in
|
||||||
EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true)
|
Alpha) RELEASE_TAG="alpha" ;;
|
||||||
|
Beta) RELEASE_TAG="beta" ;;
|
||||||
|
"Release Candidate") RELEASE_TAG="release-candidate" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
EXISTING=$(gh release view "$RELEASE_TAG" --json tagName -q .tagName 2>/dev/null || true)
|
||||||
if [ -z "$EXISTING" ]; then
|
if [ -z "$EXISTING" ]; then
|
||||||
gh release create "$RELEASE_TAG" \
|
gh release create "$RELEASE_TAG" \
|
||||||
--title "release-candidate (${VERSION})" \
|
--title "${RELEASE_TAG} (${VERSION})" \
|
||||||
--notes "## Release Candidate ${VERSION}\n\nRC branch: \`${BRANCH}\`\nTracking issue: ${PARENT_URL}" \
|
--notes "## ${BRANCH_TYPE} ${VERSION}\n\nBranch: \`${BRANCH}\`\nTracking issue: ${PARENT_URL}" \
|
||||||
--prerelease \
|
--prerelease \
|
||||||
--target main 2>/dev/null || true
|
--target main 2>/dev/null || true
|
||||||
echo "RC release created: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
|
echo "${BRANCH_TYPE} release created: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
|
||||||
else
|
else
|
||||||
gh release edit "$RELEASE_TAG" \
|
gh release edit "$RELEASE_TAG" \
|
||||||
--title "release-candidate (${VERSION})" --prerelease 2>/dev/null || true
|
--title "${RELEASE_TAG} (${VERSION})" --prerelease 2>/dev/null || true
|
||||||
echo "RC release updated: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
|
echo "${BRANCH_TYPE} release updated: ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
73
.github/workflows/auto-release.yml
vendored
73
.github/workflows/auto-release.yml
vendored
@@ -7,7 +7,7 @@
|
|||||||
# INGROUP: MokoStandards.Release
|
# INGROUP: MokoStandards.Release
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/joomla/auto-release.yml.template
|
# PATH: /templates/workflows/joomla/auto-release.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Joomla build & release — ZIP package, updates.xml, SHA-256 checksum
|
# BRIEF: Joomla build & release — ZIP package, updates.xml, SHA-256 checksum
|
||||||
#
|
#
|
||||||
# +========================================================================+
|
# +========================================================================+
|
||||||
@@ -316,54 +316,47 @@ jobs:
|
|||||||
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/v${VERSION}/${EXT_ELEMENT}-${VERSION}.zip"
|
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/v${VERSION}/${EXT_ELEMENT}-${VERSION}.zip"
|
||||||
INFO_URL="https://github.com/${REPO}/releases/tag/v${VERSION}"
|
INFO_URL="https://github.com/${REPO}/releases/tag/v${VERSION}"
|
||||||
|
|
||||||
# -- Build stable entry ──────────────────────────────────────
|
# -- Build stable entry to temp file ─────────────────────────
|
||||||
STABLE_ENTRY=$(cat <<XMLEOF
|
{
|
||||||
<update>
|
printf '%s\n' ' <update>'
|
||||||
<name>${EXT_NAME}</name>
|
printf '%s\n' " <name>${EXT_NAME}</name>"
|
||||||
<description>${EXT_NAME} update</description>
|
printf '%s\n' " <description>${EXT_NAME} update</description>"
|
||||||
<element>${EXT_ELEMENT}</element>
|
printf '%s\n' " <element>${EXT_ELEMENT}</element>"
|
||||||
<type>${EXT_TYPE}</type>
|
printf '%s\n' " <type>${EXT_TYPE}</type>"
|
||||||
<version>${VERSION}</version>
|
printf '%s\n' " <version>${VERSION}</version>"
|
||||||
$([ -n "$CLIENT_TAG" ] && echo " ${CLIENT_TAG}")
|
[ -n "$CLIENT_TAG" ] && printf '%s\n' " ${CLIENT_TAG}"
|
||||||
$([ -n "$FOLDER_TAG" ] && echo " ${FOLDER_TAG}")
|
[ -n "$FOLDER_TAG" ] && printf '%s\n' " ${FOLDER_TAG}"
|
||||||
<tags>
|
printf '%s\n' ' <tags>'
|
||||||
<tag>stable</tag>
|
printf '%s\n' ' <tag>stable</tag>'
|
||||||
</tags>
|
printf '%s\n' ' </tags>'
|
||||||
<infourl title="${EXT_NAME}">${INFO_URL}</infourl>
|
printf '%s\n' " <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>"
|
||||||
<downloads>
|
printf '%s\n' ' <downloads>'
|
||||||
<downloadurl type="full" format="zip">${DOWNLOAD_URL}</downloadurl>
|
printf '%s\n' " <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>"
|
||||||
</downloads>
|
printf '%s\n' ' </downloads>'
|
||||||
${TARGET_PLATFORM}
|
printf '%s\n' " ${TARGET_PLATFORM}"
|
||||||
$([ -n "$PHP_TAG" ] && echo " ${PHP_TAG}")
|
[ -n "$PHP_TAG" ] && printf '%s\n' " ${PHP_TAG}"
|
||||||
<maintainer>Moko Consulting</maintainer>
|
printf '%s\n' ' <maintainer>Moko Consulting</maintainer>'
|
||||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
printf '%s\n' ' <maintainerurl>https://mokoconsulting.tech</maintainerurl>'
|
||||||
</update>
|
printf '%s\n' ' </update>'
|
||||||
XMLEOF
|
} > /tmp/stable_entry.xml
|
||||||
)
|
|
||||||
|
|
||||||
# -- Write updates.xml preserving dev/rc entries ──────────────
|
# -- Write updates.xml preserving dev/rc entries ──────────────
|
||||||
# Extract existing dev and rc entries if present
|
|
||||||
RC_ENTRY=""
|
RC_ENTRY=""
|
||||||
DEV_ENTRY=""
|
DEV_ENTRY=""
|
||||||
if [ -f "updates.xml" ]; then
|
if [ -f "updates.xml" ]; then
|
||||||
RC_ENTRY=$(python3 -c "
|
printf 'import re\n' > /tmp/extract.py
|
||||||
import re
|
printf 'with open("updates.xml") as f: c = f.read()\n' >> /tmp/extract.py
|
||||||
with open('updates.xml') as f: c = f.read()
|
printf 'import sys; tag = sys.argv[1]\n' >> /tmp/extract.py
|
||||||
m = re.search(r'( <update>.*?<tag>rc</tag>.*?</update>)', c, re.DOTALL)
|
printf 'm = re.search(r"( <update>.*?<tag>" + re.escape(tag) + r"</tag>.*?</update>)", c, re.DOTALL)\n' >> /tmp/extract.py
|
||||||
if m: print(m.group(1))
|
printf 'if m: print(m.group(1))\n' >> /tmp/extract.py
|
||||||
" 2>/dev/null || true)
|
RC_ENTRY=$(python3 /tmp/extract.py rc 2>/dev/null || true)
|
||||||
DEV_ENTRY=$(python3 -c "
|
DEV_ENTRY=$(python3 /tmp/extract.py development 2>/dev/null || true)
|
||||||
import re
|
|
||||||
with open('updates.xml') as f: c = f.read()
|
|
||||||
m = re.search(r'( <update>.*?<tag>development</tag>.*?</update>)', c, re.DOTALL)
|
|
||||||
if m: print(m.group(1))
|
|
||||||
" 2>/dev/null || true)
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{
|
{
|
||||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
||||||
printf '%s\n' '<updates>'
|
printf '%s\n' '<updates>'
|
||||||
echo "$STABLE_ENTRY"
|
cat /tmp/stable_entry.xml
|
||||||
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
|
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
|
||||||
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
|
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
|
||||||
printf '%s\n' '</updates>'
|
printf '%s\n' '</updates>'
|
||||||
@@ -484,7 +477,7 @@ if m: print(m.group(1))
|
|||||||
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ — skipping package"; exit 0; }
|
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ — skipping package"; exit 0; }
|
||||||
|
|
||||||
cd "$SOURCE_DIR"
|
cd "$SOURCE_DIR"
|
||||||
zip -r "/tmp/${PACKAGE_NAME}" .
|
zip -r "/tmp/${PACKAGE_NAME}" . -x '.ftpignore'
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
FILESIZE=$(stat -c%s "/tmp/${PACKAGE_NAME}" 2>/dev/null || stat -f%z "/tmp/${PACKAGE_NAME}" 2>/dev/null || echo "unknown")
|
FILESIZE=$(stat -c%s "/tmp/${PACKAGE_NAME}" 2>/dev/null || stat -f%z "/tmp/${PACKAGE_NAME}" 2>/dev/null || echo "unknown")
|
||||||
|
|||||||
2
.github/workflows/auto-update-sha.yml
vendored
2
.github/workflows/auto-update-sha.yml
vendored
@@ -5,7 +5,7 @@
|
|||||||
# INGROUP: MokoCassiopeia.Automation
|
# INGROUP: MokoCassiopeia.Automation
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoCassiopeia
|
# REPO: https://github.com/mokoconsulting-tech/MokoCassiopeia
|
||||||
# PATH: /.github/workflows/auto-update-sha.yml
|
# PATH: /.github/workflows/auto-update-sha.yml
|
||||||
# VERSION: 01.00.00
|
# VERSION: 03.09.03
|
||||||
# BRIEF: Automatically update SHA-256 hash in updates.xml after release
|
# BRIEF: Automatically update SHA-256 hash in updates.xml after release
|
||||||
# NOTE: Ensures updates.xml stays synchronized with release packages
|
# NOTE: Ensures updates.xml stays synchronized with release packages
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/changelog-validation.yml
vendored
2
.github/workflows/changelog-validation.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.CI
|
# INGROUP: MokoStandards.CI
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/changelog-validation.yml.template
|
# PATH: /templates/workflows/shared/changelog-validation.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Validates CHANGELOG.md format and version consistency
|
# BRIEF: Validates CHANGELOG.md format and version consistency
|
||||||
# NOTE: Deployed to .github/workflows/changelog-validation.yml in governed repos.
|
# NOTE: Deployed to .github/workflows/changelog-validation.yml in governed repos.
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/ci-joomla.yml
vendored
2
.github/workflows/ci-joomla.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.CI
|
# INGROUP: MokoStandards.CI
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/joomla/ci-joomla.yml.template
|
# PATH: /templates/workflows/joomla/ci-joomla.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: CI workflow for Joomla extensions — lint, validate, test
|
# BRIEF: CI workflow for Joomla extensions — lint, validate, test
|
||||||
# NOTE: Deployed to .github/workflows/ci-joomla.yml in governed Joomla extension repos.
|
# NOTE: Deployed to .github/workflows/ci-joomla.yml in governed Joomla extension repos.
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.Security
|
# INGROUP: MokoStandards.Security
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/generic/codeql-analysis.yml.template
|
# PATH: /templates/workflows/generic/codeql-analysis.yml.template
|
||||||
# VERSION: 04.05.00
|
# VERSION: 03.09.03
|
||||||
# BRIEF: CodeQL security scanning workflow (generic — all repo types)
|
# BRIEF: CodeQL security scanning workflow (generic — all repo types)
|
||||||
# NOTE: Deployed to .github/workflows/codeql-analysis.yml in governed repos.
|
# NOTE: Deployed to .github/workflows/codeql-analysis.yml in governed repos.
|
||||||
# CodeQL does not support PHP directly; JavaScript scans JSON/YAML/shell.
|
# CodeQL does not support PHP directly; JavaScript scans JSON/YAML/shell.
|
||||||
|
|||||||
132
.github/workflows/deploy-manual.yml
vendored
Normal file
132
.github/workflows/deploy-manual.yml
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: GitHub.Workflow
|
||||||
|
# INGROUP: MokoStandards.Deploy
|
||||||
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
|
# PATH: /templates/workflows/joomla/deploy-manual.yml.template
|
||||||
|
# VERSION: 04.06.00
|
||||||
|
# BRIEF: Manual SFTP deploy to dev server for Joomla repos
|
||||||
|
# NOTE: Joomla repos use update.xml for distribution. This is for manual
|
||||||
|
# dev server testing only — triggered via workflow_dispatch.
|
||||||
|
|
||||||
|
name: Deploy to Dev (Manual)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
clear_remote:
|
||||||
|
description: 'Delete all remote files before uploading'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
name: SFTP Deploy to Dev
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.31.0
|
||||||
|
with:
|
||||||
|
php-version: '8.2'
|
||||||
|
extensions: json, ssh2
|
||||||
|
tools: composer
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- name: Setup MokoStandards tools
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
|
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 --branch version/04 --quiet \
|
||||||
|
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
|
||||||
|
/tmp/mokostandards 2>/dev/null || true
|
||||||
|
if [ -d "/tmp/mokostandards" ] && [ -f "/tmp/mokostandards/composer.json" ]; then
|
||||||
|
cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check FTP configuration
|
||||||
|
id: check
|
||||||
|
env:
|
||||||
|
HOST: ${{ vars.DEV_FTP_HOST }}
|
||||||
|
PATH_VAR: ${{ vars.DEV_FTP_PATH }}
|
||||||
|
SUFFIX: ${{ vars.DEV_FTP_SUFFIX }}
|
||||||
|
PORT: ${{ vars.DEV_FTP_PORT }}
|
||||||
|
run: |
|
||||||
|
if [ -z "$HOST" ] || [ -z "$PATH_VAR" ]; then
|
||||||
|
echo "DEV_FTP_HOST or DEV_FTP_PATH not configured — cannot deploy"
|
||||||
|
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "host=$HOST" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
REMOTE="${PATH_VAR%/}"
|
||||||
|
[ -n "$SUFFIX" ] && REMOTE="${REMOTE}/${SUFFIX#/}"
|
||||||
|
echo "remote=$REMOTE" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
[ -z "$PORT" ] && PORT="22"
|
||||||
|
echo "port=$PORT" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Deploy via SFTP
|
||||||
|
if: steps.check.outputs.skip != 'true'
|
||||||
|
env:
|
||||||
|
SFTP_KEY: ${{ secrets.DEV_FTP_KEY }}
|
||||||
|
SFTP_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
|
||||||
|
SFTP_USER: ${{ vars.DEV_FTP_USERNAME }}
|
||||||
|
run: |
|
||||||
|
SOURCE_DIR="src"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ — nothing to deploy"; exit 0; }
|
||||||
|
|
||||||
|
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
|
||||||
|
"${{ steps.check.outputs.host }}" "${{ steps.check.outputs.port }}" "$SFTP_USER" "${{ steps.check.outputs.remote }}" \
|
||||||
|
> /tmp/sftp-config.json
|
||||||
|
|
||||||
|
if [ -n "$SFTP_KEY" ]; then
|
||||||
|
echo "$SFTP_KEY" > /tmp/deploy_key
|
||||||
|
chmod 600 /tmp/deploy_key
|
||||||
|
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
|
||||||
|
else
|
||||||
|
printf ',"password":"%s"}' "$SFTP_PASS" >> /tmp/sftp-config.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPLOY_ARGS=(--path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json)
|
||||||
|
[ "${{ inputs.clear_remote }}" = "true" ] && DEPLOY_ARGS+=(--clear-remote)
|
||||||
|
|
||||||
|
PLATFORM=$(php /tmp/mokostandards/api/cli/platform_detect.php --path . 2>/dev/null || true)
|
||||||
|
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards/api/deploy/deploy-joomla.php" ]; then
|
||||||
|
php /tmp/mokostandards/api/deploy/deploy-joomla.php "${DEPLOY_ARGS[@]}"
|
||||||
|
else
|
||||||
|
php /tmp/mokostandards/api/deploy/deploy-sftp.php "${DEPLOY_ARGS[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /tmp/deploy_key /tmp/sftp-config.json
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
if [ "${{ steps.check.outputs.skip }}" = "true" ]; then
|
||||||
|
echo "### Deploy Skipped — FTP not configured" >> $GITHUB_STEP_SUMMARY
|
||||||
|
else
|
||||||
|
echo "### Manual Dev Deploy Complete" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Host | \`${{ steps.check.outputs.host }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Remote | \`${{ steps.check.outputs.remote }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Clear | ${{ inputs.clear_remote }} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
# INGROUP: MokoStandards.Firewall
|
# INGROUP: MokoStandards.Firewall
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/enterprise-firewall-setup.yml.template
|
# PATH: /templates/workflows/shared/enterprise-firewall-setup.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Enterprise firewall configuration — generates outbound allow-rules including SFTP deployment server
|
# BRIEF: Enterprise firewall configuration — generates outbound allow-rules including SFTP deployment server
|
||||||
# NOTE: Reads DEV_FTP_HOST / DEV_FTP_PORT variables to include SFTP egress rules alongside HTTPS rules.
|
# NOTE: Reads DEV_FTP_HOST / DEV_FTP_PORT variables to include SFTP egress rules alongside HTTPS rules.
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -22,7 +22,7 @@
|
|||||||
# INGROUP: MokoCassiopeia.Release
|
# INGROUP: MokoCassiopeia.Release
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoCassiopeia
|
# REPO: https://github.com/mokoconsulting-tech/MokoCassiopeia
|
||||||
# PATH: /.github/workflows/release.yml
|
# PATH: /.github/workflows/release.yml
|
||||||
# VERSION: 01.00.00
|
# VERSION: 03.09.03
|
||||||
# BRIEF: Automated release workflow for MokoCassiopeia Joomla template
|
# BRIEF: Automated release workflow for MokoCassiopeia Joomla template
|
||||||
# NOTE: Creates release packages and publishes to GitHub Releases
|
# NOTE: Creates release packages and publishes to GitHub Releases
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/repo_health.yml
vendored
2
.github/workflows/repo_health.yml
vendored
@@ -10,7 +10,7 @@
|
|||||||
# INGROUP: MokoStandards.Validation
|
# INGROUP: MokoStandards.Validation
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /.github/workflows/repo_health.yml
|
# PATH: /.github/workflows/repo_health.yml
|
||||||
# VERSION: 04.05.00
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts.
|
# BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts.
|
||||||
# NOTE: Field is user-managed.
|
# NOTE: Field is user-managed.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
2
.github/workflows/repository-cleanup.yml
vendored
2
.github/workflows/repository-cleanup.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.Maintenance
|
# INGROUP: MokoStandards.Maintenance
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/repository-cleanup.yml.template
|
# PATH: /templates/workflows/shared/repository-cleanup.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes
|
# BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes
|
||||||
# NOTE: Synced via bulk-repo-sync to .github/workflows/repository-cleanup.yml in all governed repos.
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/repository-cleanup.yml in all governed repos.
|
||||||
# Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch.
|
# Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch.
|
||||||
|
|||||||
2
.github/workflows/standards-compliance.yml
vendored
2
.github/workflows/standards-compliance.yml
vendored
@@ -5,7 +5,7 @@
|
|||||||
# INGROUP: MokoStandards.Compliance
|
# INGROUP: MokoStandards.Compliance
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /.github/workflows/standards-compliance.yml
|
# PATH: /.github/workflows/standards-compliance.yml
|
||||||
# VERSION: 04.05.00
|
# VERSION: 04.06.00
|
||||||
# BRIEF: MokoStandards compliance validation workflow
|
# BRIEF: MokoStandards compliance validation workflow
|
||||||
# NOTE: Validates repository structure, documentation, and coding standards
|
# NOTE: Validates repository structure, documentation, and coding standards
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/sync-version-on-merge.yml
vendored
2
.github/workflows/sync-version-on-merge.yml
vendored
@@ -9,7 +9,7 @@
|
|||||||
# INGROUP: MokoStandards.Automation
|
# INGROUP: MokoStandards.Automation
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/shared/sync-version-on-merge.yml.template
|
# PATH: /templates/workflows/shared/sync-version-on-merge.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Auto-bump patch version on every push to main and propagate to all file headers
|
# BRIEF: Auto-bump patch version on every push to main and propagate to all file headers
|
||||||
# NOTE: Synced via bulk-repo-sync to .github/workflows/sync-version-on-merge.yml in all governed repos.
|
# NOTE: Synced via bulk-repo-sync to .github/workflows/sync-version-on-merge.yml in all governed repos.
|
||||||
# README.md is the single source of truth for the repository version.
|
# README.md is the single source of truth for the repository version.
|
||||||
|
|||||||
236
.github/workflows/update-server.yml
vendored
236
.github/workflows/update-server.yml
vendored
@@ -7,7 +7,7 @@
|
|||||||
# INGROUP: MokoStandards.Joomla
|
# INGROUP: MokoStandards.Joomla
|
||||||
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
# PATH: /templates/workflows/joomla/update-server.yml.template
|
# PATH: /templates/workflows/joomla/update-server.yml.template
|
||||||
# VERSION: 04.05.13
|
# VERSION: 04.06.00
|
||||||
# BRIEF: Update Joomla update server XML feed with stable/rc/dev entries
|
# BRIEF: Update Joomla update server XML feed with stable/rc/dev entries
|
||||||
#
|
#
|
||||||
# Writes updates.xml with multiple <update> entries:
|
# Writes updates.xml with multiple <update> entries:
|
||||||
@@ -23,6 +23,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'dev/**'
|
- 'dev/**'
|
||||||
|
- 'alpha/**'
|
||||||
|
- 'beta/**'
|
||||||
- 'rc/**'
|
- 'rc/**'
|
||||||
paths:
|
paths:
|
||||||
- 'src/**'
|
- 'src/**'
|
||||||
@@ -30,12 +32,14 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
stability:
|
stability:
|
||||||
description: 'Stability tag (development, rc, stable)'
|
description: 'Stability tag'
|
||||||
required: true
|
required: true
|
||||||
default: 'development'
|
default: 'development'
|
||||||
type: choice
|
type: choice
|
||||||
options:
|
options:
|
||||||
- development
|
- development
|
||||||
|
- alpha
|
||||||
|
- beta
|
||||||
- rc
|
- rc
|
||||||
- stable
|
- stable
|
||||||
|
|
||||||
@@ -75,11 +79,29 @@ jobs:
|
|||||||
REPO="${{ github.repository }}"
|
REPO="${{ github.repository }}"
|
||||||
VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null || echo "0.0.0")
|
VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null || echo "0.0.0")
|
||||||
|
|
||||||
|
# Auto-bump patch on alpha/beta/rc branches (not dev — dev bumps manually)
|
||||||
|
if [[ "$BRANCH" != dev/* ]]; then
|
||||||
|
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
BUMPED=$(php /tmp/mokostandards/api/cli/version_bump.php --path . 2>/dev/null || true)
|
||||||
|
if [ -n "$BUMPED" ]; then
|
||||||
|
VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null || echo "$VERSION")
|
||||||
|
git add -A
|
||||||
|
git commit -m "chore(version): auto-bump patch ${VERSION} [skip ci]" \
|
||||||
|
--author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>" 2>/dev/null || true
|
||||||
|
git push 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Determine stability from branch or input
|
# Determine stability from branch or input
|
||||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
STABILITY="${{ inputs.stability }}"
|
STABILITY="${{ inputs.stability }}"
|
||||||
elif [[ "$BRANCH" == rc/* ]]; then
|
elif [[ "$BRANCH" == rc/* ]]; then
|
||||||
STABILITY="rc"
|
STABILITY="rc"
|
||||||
|
elif [[ "$BRANCH" == beta/* ]]; then
|
||||||
|
STABILITY="beta"
|
||||||
|
elif [[ "$BRANCH" == alpha/* ]]; then
|
||||||
|
STABILITY="alpha"
|
||||||
elif [[ "$BRANCH" == dev/* ]]; then
|
elif [[ "$BRANCH" == dev/* ]]; then
|
||||||
STABILITY="development"
|
STABILITY="development"
|
||||||
else
|
else
|
||||||
@@ -116,19 +138,23 @@ jobs:
|
|||||||
|
|
||||||
# Version suffix for non-stable
|
# Version suffix for non-stable
|
||||||
DISPLAY_VERSION="$VERSION"
|
DISPLAY_VERSION="$VERSION"
|
||||||
[ "$STABILITY" = "rc" ] && DISPLAY_VERSION="${VERSION}-rc"
|
case "$STABILITY" in
|
||||||
[ "$STABILITY" = "development" ] && DISPLAY_VERSION="${VERSION}-dev"
|
development) DISPLAY_VERSION="${VERSION}-dev" ;;
|
||||||
|
alpha) DISPLAY_VERSION="${VERSION}-alpha" ;;
|
||||||
|
beta) DISPLAY_VERSION="${VERSION}-beta" ;;
|
||||||
|
rc) DISPLAY_VERSION="${VERSION}-rc" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
MAJOR=$(echo "$VERSION" | awk -F. '{print $1}')
|
MAJOR=$(echo "$VERSION" | awk -F. '{print $1}')
|
||||||
|
|
||||||
# Each stability level has its own release tag
|
# Each stability level has its own release tag
|
||||||
if [ "$STABILITY" = "rc" ]; then
|
case "$STABILITY" in
|
||||||
RELEASE_TAG="release-candidate"
|
development) RELEASE_TAG="development" ;;
|
||||||
elif [ "$STABILITY" = "development" ]; then
|
alpha) RELEASE_TAG="alpha" ;;
|
||||||
RELEASE_TAG="development"
|
beta) RELEASE_TAG="beta" ;;
|
||||||
else
|
rc) RELEASE_TAG="release-candidate" ;;
|
||||||
RELEASE_TAG="v${MAJOR}"
|
*) RELEASE_TAG="v${MAJOR}" ;;
|
||||||
fi
|
esac
|
||||||
|
|
||||||
PACKAGE_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.zip"
|
PACKAGE_NAME="${EXT_ELEMENT}-${DISPLAY_VERSION}.zip"
|
||||||
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
|
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}"
|
||||||
@@ -139,7 +165,7 @@ jobs:
|
|||||||
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||||
if [ -d "$SOURCE_DIR" ]; then
|
if [ -d "$SOURCE_DIR" ]; then
|
||||||
cd "$SOURCE_DIR"
|
cd "$SOURCE_DIR"
|
||||||
zip -r "/tmp/${PACKAGE_NAME}" .
|
zip -r "/tmp/${PACKAGE_NAME}" . -x '.ftpignore'
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
|
SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1)
|
||||||
@@ -157,95 +183,63 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Build the new entry ───────────────────────────────────────
|
# ── Build the new entry ───────────────────────────────────────
|
||||||
NEW_ENTRY=$(cat <<XMLEOF
|
NEW_ENTRY=""
|
||||||
<update>
|
NEW_ENTRY="${NEW_ENTRY} <update>\n"
|
||||||
<name>${EXT_NAME}</name>
|
NEW_ENTRY="${NEW_ENTRY} <name>${EXT_NAME}</name>\n"
|
||||||
<description>${EXT_NAME} (${STABILITY})</description>
|
NEW_ENTRY="${NEW_ENTRY} <description>${EXT_NAME} (${STABILITY})</description>\n"
|
||||||
<element>${EXT_ELEMENT}</element>
|
NEW_ENTRY="${NEW_ENTRY} <element>${EXT_ELEMENT}</element>\n"
|
||||||
<type>${EXT_TYPE}</type>
|
NEW_ENTRY="${NEW_ENTRY} <type>${EXT_TYPE}</type>\n"
|
||||||
<version>${DISPLAY_VERSION}</version>
|
NEW_ENTRY="${NEW_ENTRY} <version>${DISPLAY_VERSION}</version>\n"
|
||||||
$([ -n "$CLIENT_TAG" ] && echo " ${CLIENT_TAG}")
|
[ -n "$CLIENT_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${CLIENT_TAG}\n"
|
||||||
$([ -n "$FOLDER_TAG" ] && echo " ${FOLDER_TAG}")
|
[ -n "$FOLDER_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${FOLDER_TAG}\n"
|
||||||
<tags>
|
NEW_ENTRY="${NEW_ENTRY} <tags>\n"
|
||||||
<tag>${STABILITY}</tag>
|
NEW_ENTRY="${NEW_ENTRY} <tag>${STABILITY}</tag>\n"
|
||||||
</tags>
|
NEW_ENTRY="${NEW_ENTRY} </tags>\n"
|
||||||
<infourl title="${EXT_NAME}">${INFO_URL}</infourl>
|
NEW_ENTRY="${NEW_ENTRY} <infourl title=\"${EXT_NAME}\">${INFO_URL}</infourl>\n"
|
||||||
<downloads>
|
NEW_ENTRY="${NEW_ENTRY} <downloads>\n"
|
||||||
<downloadurl type="full" format="zip">${DOWNLOAD_URL}</downloadurl>
|
NEW_ENTRY="${NEW_ENTRY} <downloadurl type=\"full\" format=\"zip\">${DOWNLOAD_URL}</downloadurl>\n"
|
||||||
</downloads>
|
NEW_ENTRY="${NEW_ENTRY} </downloads>\n"
|
||||||
$([ -n "$SHA256" ] && echo " <sha256>sha256:${SHA256}</sha256>")
|
[ -n "$SHA256" ] && NEW_ENTRY="${NEW_ENTRY} <sha256>sha256:${SHA256}</sha256>\n"
|
||||||
${TARGET_PLATFORM}
|
NEW_ENTRY="${NEW_ENTRY} ${TARGET_PLATFORM}\n"
|
||||||
$([ -n "$PHP_TAG" ] && echo " ${PHP_TAG}")
|
[ -n "$PHP_TAG" ] && NEW_ENTRY="${NEW_ENTRY} ${PHP_TAG}\n"
|
||||||
<maintainer>Moko Consulting</maintainer>
|
NEW_ENTRY="${NEW_ENTRY} <maintainer>Moko Consulting</maintainer>\n"
|
||||||
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
|
NEW_ENTRY="${NEW_ENTRY} <maintainerurl>https://mokoconsulting.tech</maintainerurl>\n"
|
||||||
</update>
|
NEW_ENTRY="${NEW_ENTRY} </update>"
|
||||||
XMLEOF
|
|
||||||
)
|
# ── Write new entry to temp file ───────────────────────────────
|
||||||
|
printf '%b' "$NEW_ENTRY" > /tmp/new_entry.xml
|
||||||
|
|
||||||
# ── Merge into updates.xml ─────────────────────────────────────
|
# ── Merge into updates.xml ─────────────────────────────────────
|
||||||
if [ ! -f "updates.xml" ]; then
|
if [ ! -f "updates.xml" ]; then
|
||||||
# Create fresh
|
|
||||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>' > updates.xml
|
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>' > updates.xml
|
||||||
printf '%s\n' '<updates>' >> updates.xml
|
printf '%s\n' '<updates>' >> updates.xml
|
||||||
echo "$NEW_ENTRY" >> updates.xml
|
cat /tmp/new_entry.xml >> updates.xml
|
||||||
printf '%s\n' '</updates>' >> updates.xml
|
printf '\n%s\n' '</updates>' >> updates.xml
|
||||||
else
|
else
|
||||||
# Remove existing entry for this stability, add new one
|
# Remove existing entry for this stability, insert new one
|
||||||
# Use python for reliable XML manipulation
|
printf 'import re\nstability = "%s"\n' "${STABILITY}" > /tmp/merge_xml.py
|
||||||
python3 -c "
|
printf 'with open("updates.xml") as f: content = f.read()\n' >> /tmp/merge_xml.py
|
||||||
import re, sys
|
printf 'with open("/tmp/new_entry.xml") as f: new_entry = f.read()\n' >> /tmp/merge_xml.py
|
||||||
|
printf 'pattern = r" <update>.*?<tag>" + re.escape(stability) + r"</tag>.*?</update>\\n?"\n' >> /tmp/merge_xml.py
|
||||||
with open('updates.xml', 'r') as f:
|
printf 'content = re.sub(pattern, "", content, flags=re.DOTALL)\n' >> /tmp/merge_xml.py
|
||||||
content = f.read()
|
printf 'content = content.replace("</updates>", new_entry + "\\n</updates>")\n' >> /tmp/merge_xml.py
|
||||||
|
printf 'content = re.sub(r"\\n{3,}", "\\n\\n", content)\n' >> /tmp/merge_xml.py
|
||||||
# Remove existing entry with this stability tag
|
printf 'with open("updates.xml", "w") as f: f.write(content)\n' >> /tmp/merge_xml.py
|
||||||
pattern = r' <update>.*?<tag>${STABILITY}</tag>.*?</update>\n?'
|
python3 /tmp/merge_xml.py 2>/dev/null || {
|
||||||
content = re.sub(pattern, '', content, flags=re.DOTALL)
|
# Fallback: rebuild keeping other stability entries
|
||||||
|
|
||||||
# Insert new entry before </updates>
|
|
||||||
new_entry = '''${NEW_ENTRY}'''
|
|
||||||
content = content.replace('</updates>', new_entry + '\n</updates>')
|
|
||||||
|
|
||||||
# Clean up empty lines
|
|
||||||
content = re.sub(r'\n{3,}', '\n\n', content)
|
|
||||||
|
|
||||||
with open('updates.xml', 'w') as f:
|
|
||||||
f.write(content)
|
|
||||||
" 2>/dev/null || {
|
|
||||||
# Fallback: just rewrite the whole file if python fails
|
|
||||||
# Keep existing stable entry if present
|
|
||||||
STABLE_ENTRY=""
|
|
||||||
if [ "$STABILITY" != "stable" ] && grep -q '<tag>stable</tag>' updates.xml; then
|
|
||||||
STABLE_ENTRY=$(sed -n '/<update>/,/<\/update>/{ /<tag>stable<\/tag>/,/<\/update>/p; /<update>/,/<tag>stable<\/tag>/p }' updates.xml | sort -u)
|
|
||||||
fi
|
|
||||||
RC_ENTRY=""
|
|
||||||
if [ "$STABILITY" != "rc" ] && grep -q '<tag>rc</tag>' updates.xml; then
|
|
||||||
RC_ENTRY=$(python3 -c "
|
|
||||||
import re
|
|
||||||
with open('updates.xml') as f: c = f.read()
|
|
||||||
m = re.search(r'(<update>.*?<tag>rc</tag>.*?</update>)', c, re.DOTALL)
|
|
||||||
if m: print(m.group(1))
|
|
||||||
" 2>/dev/null || true)
|
|
||||||
fi
|
|
||||||
DEV_ENTRY=""
|
|
||||||
if [ "$STABILITY" != "development" ] && grep -q '<tag>development</tag>' updates.xml; then
|
|
||||||
DEV_ENTRY=$(python3 -c "
|
|
||||||
import re
|
|
||||||
with open('updates.xml') as f: c = f.read()
|
|
||||||
m = re.search(r'(<update>.*?<tag>development</tag>.*?</update>)', c, re.DOTALL)
|
|
||||||
if m: print(m.group(1))
|
|
||||||
" 2>/dev/null || true)
|
|
||||||
fi
|
|
||||||
|
|
||||||
{
|
{
|
||||||
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>'
|
||||||
printf '%s\n' '<updates>'
|
printf '%s\n' '<updates>'
|
||||||
[ -n "$STABLE_ENTRY" ] && echo "$STABLE_ENTRY"
|
for TAG in stable rc development; do
|
||||||
[ -n "$RC_ENTRY" ] && echo "$RC_ENTRY"
|
[ "$TAG" = "${STABILITY}" ] && continue
|
||||||
[ -n "$DEV_ENTRY" ] && echo "$DEV_ENTRY"
|
if grep -q "<tag>${TAG}</tag>" updates.xml 2>/dev/null; then
|
||||||
echo "$NEW_ENTRY"
|
sed -n "/<update>/,/<\/update>/{ /<tag>${TAG}<\/tag>/p; }" updates.xml
|
||||||
printf '%s\n' '</updates>'
|
fi
|
||||||
} > updates.xml
|
done
|
||||||
|
cat /tmp/new_entry.xml
|
||||||
|
printf '\n%s\n' '</updates>'
|
||||||
|
} > /tmp/updates_new.xml
|
||||||
|
mv /tmp/updates_new.xml updates.xml
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -259,6 +253,64 @@ if m: print(m.group(1))
|
|||||||
git push
|
git push
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- name: SFTP deploy to dev server
|
||||||
|
if: contains(github.ref, 'dev/')
|
||||||
|
env:
|
||||||
|
DEV_HOST: ${{ vars.DEV_FTP_HOST }}
|
||||||
|
DEV_PATH: ${{ vars.DEV_FTP_PATH }}
|
||||||
|
DEV_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }}
|
||||||
|
DEV_USER: ${{ vars.DEV_FTP_USERNAME }}
|
||||||
|
DEV_PORT: ${{ vars.DEV_FTP_PORT }}
|
||||||
|
DEV_KEY: ${{ secrets.DEV_FTP_KEY }}
|
||||||
|
DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
|
||||||
|
run: |
|
||||||
|
# ── Permission check: admin or maintain role required ──────
|
||||||
|
ACTOR="${{ github.actor }}"
|
||||||
|
REPO="${{ github.repository }}"
|
||||||
|
PERMISSION=$(gh api "repos/${REPO}/collaborators/${ACTOR}/permission" \
|
||||||
|
--jq '.permission' 2>/dev/null || \
|
||||||
|
gh api "repos/${REPO}/collaborators/${ACTOR}" \
|
||||||
|
--jq '.role' 2>/dev/null || echo "read")
|
||||||
|
case "$PERMISSION" in
|
||||||
|
admin|maintain|write) ;;
|
||||||
|
*)
|
||||||
|
echo "Deploy denied: ${ACTOR} has '${PERMISSION}' — requires admin, maintain, or write"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ -z "$DEV_HOST" ] || [ -z "$DEV_PATH" ] && { echo "DEV FTP not configured — skipping SFTP"; exit 0; }
|
||||||
|
|
||||||
|
SOURCE_DIR="src"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
|
||||||
|
[ ! -d "$SOURCE_DIR" ] && exit 0
|
||||||
|
|
||||||
|
PORT="${DEV_PORT:-22}"
|
||||||
|
REMOTE="${DEV_PATH%/}"
|
||||||
|
[ -n "$DEV_SUFFIX" ] && REMOTE="${REMOTE}/${DEV_SUFFIX#/}"
|
||||||
|
|
||||||
|
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
|
||||||
|
"$DEV_HOST" "$PORT" "$DEV_USER" "$REMOTE" > /tmp/sftp-config.json
|
||||||
|
if [ -n "$DEV_KEY" ]; then
|
||||||
|
echo "$DEV_KEY" > /tmp/deploy_key && chmod 600 /tmp/deploy_key
|
||||||
|
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
|
||||||
|
else
|
||||||
|
printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
PLATFORM=$(php /tmp/mokostandards/api/cli/platform_detect.php --path . 2>/dev/null || true)
|
||||||
|
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards/api/deploy/deploy-joomla.php" ]; then
|
||||||
|
php /tmp/mokostandards/api/deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
|
||||||
|
elif [ -f "/tmp/mokostandards/api/deploy/deploy-sftp.php" ]; then
|
||||||
|
php /tmp/mokostandards/api/deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json
|
||||||
|
fi
|
||||||
|
rm -f /tmp/deploy_key /tmp/sftp-config.json
|
||||||
|
echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
echo "## Joomla Update Server" >> $GITHUB_STEP_SUMMARY
|
echo "## Joomla Update Server" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|||||||
16
README.md
16
README.md
@@ -13,20 +13,14 @@
|
|||||||
BRIEF: Documentation for MokoCassiopeia template
|
BRIEF: Documentation for MokoCassiopeia template
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
# MokoCassiopeia Template
|
||||||
[](https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/v03)
|
|
||||||
[](LICENSE)
|
|
||||||
[](https://www.joomla.org)
|
|
||||||
[](https://www.php.net)
|
|
||||||
|
|
||||||
# MokoCassiopeia
|
|
||||||
|
|
||||||
**A Modern, Lightweight Joomla Template Based on Cassiopeia**
|
**A Modern, Lightweight Joomla Template Based on Cassiopeia**
|
||||||
|
|
||||||
](https://img.shields.io/badge/version-03.09.04-green.svg)](https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/v03)
|
[](https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/v03)
|
||||||
: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
|
[](LICENSE)
|
||||||
](https://img.shields.io/badge/Joomla-5.x%20%7C%206.x-blue.svg)](https://www.joomla.org)
|
[](https://www.joomla.org)
|
||||||
](https://img.shields.io/badge/PHP-8.1%2B-blue.svg)](https://www.php.net)
|
[](https://www.php.net)
|
||||||
|
|
||||||
MokoCassiopeia is a modern, lightweight enhancement layer built on top of Joomla's Cassiopeia template. It adds **Font Awesome 7**, **Bootstrap 5** helpers, an automatic **Table of Contents (TOC)** utility, advanced **Dark Mode** theming, and optional integrations for **Google Tag Manager** and **Google Analytics (GA4)**—all while maintaining minimal core template overrides for maximum upgrade compatibility.
|
MokoCassiopeia is a modern, lightweight enhancement layer built on top of Joomla's Cassiopeia template. It adds **Font Awesome 7**, **Bootstrap 5** helpers, an automatic **Table of Contents (TOC)** utility, advanced **Dark Mode** theming, and optional integrations for **Google Tag Manager** and **Google Analytics (GA4)**—all while maintaining minimal core template overrides for maximum upgrade compatibility.
|
||||||
|
|
||||||
|
|||||||
@@ -10,31 +10,62 @@
|
|||||||
/**
|
/**
|
||||||
* Default layout override for mod_breadcrumbs.
|
* Default layout override for mod_breadcrumbs.
|
||||||
* Bootstrap 5 breadcrumb with schema.org BreadcrumbList markup.
|
* Bootstrap 5 breadcrumb with schema.org BreadcrumbList markup.
|
||||||
|
* Respects showHome, showLast, homeText module settings.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defined('_JEXEC') or die;
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
|
use Joomla\CMS\Router\Route;
|
||||||
|
use Joomla\CMS\Uri\Uri;
|
||||||
|
|
||||||
Factory::getApplication()->getLanguage()->load('mod_breadcrumbs', JPATH_SITE);
|
Factory::getApplication()->getLanguage()->load('mod_breadcrumbs', JPATH_SITE);
|
||||||
|
|
||||||
$suffix = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_COMPAT, 'UTF-8');
|
$suffix = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_COMPAT, 'UTF-8');
|
||||||
$headerTag = htmlspecialchars($params->get('header_tag', 'h3'), ENT_COMPAT, 'UTF-8');
|
$headerTag = htmlspecialchars($params->get('header_tag', 'h3'), ENT_COMPAT, 'UTF-8');
|
||||||
$headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'UTF-8');
|
$headerClass = htmlspecialchars($params->get('header_class', ''), ENT_COMPAT, 'UTF-8');
|
||||||
|
$showHome = $params->get('showHome', 1);
|
||||||
|
$showLast = $params->get('showLast', 1);
|
||||||
|
$homeText = $params->get('homeText', '') ?: Text::_('MOD_BREADCRUMBS_HOME');
|
||||||
|
|
||||||
|
// Build filtered list respecting module settings
|
||||||
|
$items = [];
|
||||||
|
$count = count($list);
|
||||||
|
|
||||||
|
foreach ($list as $key => $item) {
|
||||||
|
// Skip Home item if showHome is off
|
||||||
|
if ($key === 0 && !$showHome) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace Home text if custom homeText is set
|
||||||
|
if ($key === 0 && $showHome) {
|
||||||
|
$item->name = $homeText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip last item if showLast is off
|
||||||
|
if ($key === $count - 1 && !$showLast) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items[] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<nav class="mod-breadcrumbs<?php echo $suffix ? ' ' . $suffix : ''; ?>" aria-label="<?php echo Text::_('MOD_BREADCRUMBS_HERE'); ?>">
|
<nav class="mod-breadcrumbs<?php echo $suffix ? ' ' . $suffix : ''; ?>" aria-label="<?php echo Text::_('MOD_BREADCRUMBS_HERE'); ?>">
|
||||||
<?php if ($module->showtitle) : ?>
|
<?php if ($module->showtitle) : ?>
|
||||||
<<?php echo $headerTag; ?> class="mod-breadcrumbs__title<?php echo $headerClass ? ' ' . $headerClass : ''; ?>"><?php echo $module->title; ?></<?php echo $headerTag; ?>>
|
<<?php echo $headerTag; ?> class="mod-breadcrumbs__title<?php echo $headerClass ? ' ' . $headerClass : ''; ?>"><?php echo $module->title; ?></<?php echo $headerTag; ?>>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<ol class="breadcrumb" itemscope itemtype="https://schema.org/BreadcrumbList">
|
<ol class="breadcrumb" itemscope itemtype="https://schema.org/BreadcrumbList">
|
||||||
<?php foreach ($list as $key => $item) : ?>
|
<?php foreach ($items as $key => $item) : ?>
|
||||||
<?php
|
<?php $isLast = ($key === array_key_last($items)); ?>
|
||||||
$isLast = ($key === array_key_last($list));
|
|
||||||
?>
|
|
||||||
<li class="breadcrumb-item<?php echo $isLast ? ' active' : ''; ?>" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"
|
<li class="breadcrumb-item<?php echo $isLast ? ' active' : ''; ?>" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"
|
||||||
<?php echo $isLast ? ' aria-current="page"' : ''; ?>>
|
<?php echo $isLast ? ' aria-current="page"' : ''; ?>>
|
||||||
<?php if (!$isLast && $item->link) : ?>
|
<?php if (!$isLast && !empty($item->link)) : ?>
|
||||||
<a href="<?php echo $item->link; ?>" itemprop="item">
|
<a href="<?php echo $item->link; ?>" itemprop="item">
|
||||||
<span itemprop="name"><?php echo $item->name; ?></span>
|
<span itemprop="name"><?php echo $item->name; ?></span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -451,7 +451,7 @@ $wa->useScript('user.js'); // js/user.js
|
|||||||
<button class="search-toggler d-lg-none" type="button" data-bs-toggle="collapse" data-bs-target="#headerSearchCollapse" aria-controls="headerSearchCollapse" aria-expanded="false" aria-label="<?php echo Text::_('JSEARCH_FILTER_SUBMIT'); ?>">
|
<button class="search-toggler d-lg-none" type="button" data-bs-toggle="collapse" data-bs-target="#headerSearchCollapse" aria-controls="headerSearchCollapse" aria-expanded="false" aria-label="<?php echo Text::_('JSEARCH_FILTER_SUBMIT'); ?>">
|
||||||
<span class="fa-solid fa-magnifying-glass" aria-hidden="true"></span>
|
<span class="fa-solid fa-magnifying-glass" aria-hidden="true"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="container-search collapse d-lg-block" id="headerSearchCollapse">
|
<div class="container-search" id="headerSearchCollapse">
|
||||||
<jdoc:include type="modules" name="search" style="none" />
|
<jdoc:include type="modules" name="search" style="none" />
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -18672,10 +18672,14 @@ nav[data-toggle=toc] .nav-link.active+ul{
|
|||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-header .container-search.collapse:not(.show) {
|
.container-header .container-search {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container-header .container-search.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.mod-finder__search.input-group {
|
.mod-finder__search.input-group {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/media/fonts/fredoka-v17-latin-300.woff2
Normal file
BIN
src/media/fonts/fredoka-v17-latin-300.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/fredoka-v17-latin-500.woff2
Normal file
BIN
src/media/fonts/fredoka-v17-latin-500.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/fredoka-v17-latin-600.woff2
Normal file
BIN
src/media/fonts/fredoka-v17-latin-600.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/fredoka-v17-latin-700.woff2
Normal file
BIN
src/media/fonts/fredoka-v17-latin-700.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/fredoka-v17-latin-regular.woff2
Normal file
BIN
src/media/fonts/fredoka-v17-latin-regular.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/media/fonts/osaka-re.woff
Normal file
BIN
src/media/fonts/osaka-re.woff
Normal file
Binary file not shown.
BIN
src/media/fonts/pacifico-v23-latin-regular.woff2
Normal file
BIN
src/media/fonts/pacifico-v23-latin-regular.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-100.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-100.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-100italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-100italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-200.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-200.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-200italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-200italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-300.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-300.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-300italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-300italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-500.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-500.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-500italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-500italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-600.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-600.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-600italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-600italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-700.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-700.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-700italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-700italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-800.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-800.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-800italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-800italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-900.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-900.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-900italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-900italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-italic.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-italic.woff2
Normal file
Binary file not shown.
BIN
src/media/fonts/roboto-v51-latin-regular.woff2
Normal file
BIN
src/media/fonts/roboto-v51-latin-regular.woff2
Normal file
Binary file not shown.
@@ -539,6 +539,20 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle search on mobile via .show class
|
||||||
|
*/
|
||||||
|
function initSearchToggle() {
|
||||||
|
var btn = doc.querySelector(".search-toggler");
|
||||||
|
var target = doc.getElementById("headerSearchCollapse");
|
||||||
|
if (!btn || !target) return;
|
||||||
|
|
||||||
|
btn.addEventListener("click", function () {
|
||||||
|
var isOpen = target.classList.toggle("show");
|
||||||
|
btn.setAttribute("aria-expanded", isOpen ? "true" : "false");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run all template JS initializations
|
* Run all template JS initializations
|
||||||
*/
|
*/
|
||||||
@@ -563,6 +577,7 @@
|
|||||||
// Init features
|
// Init features
|
||||||
initDrawers();
|
initDrawers();
|
||||||
initBackTop();
|
initBackTop();
|
||||||
|
initSearchToggle();
|
||||||
initSidebarAccordion();
|
initSidebarAccordion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
</server>
|
</server>
|
||||||
</updateservers>
|
</updateservers>
|
||||||
<name>MokoCassiopeia</name>
|
<name>MokoCassiopeia</name>
|
||||||
<version>03.09.07</version>
|
<version>03.09.09</version>
|
||||||
<scriptfile>script.php</scriptfile>
|
<scriptfile>script.php</scriptfile>
|
||||||
<creationDate>2026-03-26</creationDate>
|
<creationDate>2026-03-26</creationDate>
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
<author>Jonathan Miller || Moko Consulting</author>
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
<folder>css</folder>
|
<folder>css</folder>
|
||||||
<folder>images</folder>
|
<folder>images</folder>
|
||||||
<folder>fonts</folder>
|
<folder>fonts</folder>
|
||||||
|
<folder>vendor</folder>
|
||||||
</media>
|
</media>
|
||||||
<positions>
|
<positions>
|
||||||
<position>topbar</position>
|
<position>topbar</position>
|
||||||
|
|||||||
24
updates.xml
24
updates.xml
@@ -26,7 +26,7 @@
|
|||||||
<type>template</type>
|
<type>template</type>
|
||||||
<client>site</client>
|
<client>site</client>
|
||||||
|
|
||||||
<version>03.09.04</version>
|
<version>03.09.07</version>
|
||||||
<creationDate>2026-04-07</creationDate>
|
<creationDate>2026-04-07</creationDate>
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
<author>Jonathan Miller || Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
@@ -35,9 +35,9 @@
|
|||||||
<infourl title='MokoCassiopeia'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/v03</infourl>
|
<infourl title='MokoCassiopeia'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/v03</infourl>
|
||||||
|
|
||||||
<downloads>
|
<downloads>
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/v03/mokocassiopeia-03.09.04.zip</downloadurl>
|
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/v03/mokocassiopeia-03.09.07.zip</downloadurl>
|
||||||
</downloads>
|
</downloads>
|
||||||
<sha256>da85bf5a34cafadbae26df199ed36c04438e7dab440d046e0e4117d25510feaf</sha256>
|
<sha256>16a7ac98dd6e26144618a4ba534ea8fae0d115ec8373712743ab6daff0960916</sha256>
|
||||||
|
|
||||||
<tags>
|
<tags>
|
||||||
<tag>stable</tag>
|
<tag>stable</tag>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
<type>template</type>
|
<type>template</type>
|
||||||
<client>site</client>
|
<client>site</client>
|
||||||
|
|
||||||
<version>03.09.06</version>
|
<version>03.09.07</version>
|
||||||
<creationDate>2026-04-07</creationDate>
|
<creationDate>2026-04-07</creationDate>
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
<author>Jonathan Miller || Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
<downloads>
|
<downloads>
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/release-candidate/mokocassiopeia-rc.zip</downloadurl>
|
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/release-candidate/mokocassiopeia-rc.zip</downloadurl>
|
||||||
</downloads>
|
</downloads>
|
||||||
<sha256>99b868a54466138d22a544d3e489559e7303960922c8eb3a142c504225b0e647</sha256>
|
<sha256>31e660078e728e8c9177b5a2d75efd89fea1fd4e9320d77444ab8fe28d3b354d</sha256>
|
||||||
|
|
||||||
<tags>
|
<tags>
|
||||||
<tag>rc</tag>
|
<tag>rc</tag>
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
<type>template</type>
|
<type>template</type>
|
||||||
<client>site</client>
|
<client>site</client>
|
||||||
|
|
||||||
<version>03.09.07</version>
|
<version>03.09.08</version>
|
||||||
<creationDate>2026-04-07</creationDate>
|
<creationDate>2026-04-07</creationDate>
|
||||||
<author>Jonathan Miller || Moko Consulting</author>
|
<author>Jonathan Miller || Moko Consulting</author>
|
||||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||||
@@ -101,9 +101,9 @@
|
|||||||
<infourl title='MokoCassiopeia Dev'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/development</infourl>
|
<infourl title='MokoCassiopeia Dev'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/development</infourl>
|
||||||
|
|
||||||
<downloads>
|
<downloads>
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/development/mokocassiopeia-dev.zip</downloadurl>
|
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/development/mokocassiopeia-03.09.08-dev.zip</downloadurl>
|
||||||
</downloads>
|
</downloads>
|
||||||
<sha256>b6403918c5f65f4f52b889fbe4bd217c903f0d9c2fcf90f8eb59df1e7b4b7333</sha256>
|
<sha256>ecff187531e65a40ae958ae91fff74da0c8856d1cc13e17a6e3d6905806b189e</sha256>
|
||||||
|
|
||||||
<tags>
|
<tags>
|
||||||
<tag>development</tag>
|
<tag>development</tag>
|
||||||
@@ -134,9 +134,9 @@
|
|||||||
<infourl title='MokoCassiopeia Alpha'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/alpha</infourl>
|
<infourl title='MokoCassiopeia Alpha'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/alpha</infourl>
|
||||||
|
|
||||||
<downloads>
|
<downloads>
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/alpha/mokocassiopeia-alpha.zip</downloadurl>
|
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/alpha/mokocassiopeia-03.09.07-alpha.zip</downloadurl>
|
||||||
</downloads>
|
</downloads>
|
||||||
<sha256>b5f6d073d126f0041ddd475e61bc4eaa050e060e9b51f4fe0e8a348f188c40b2</sha256>
|
<sha256>1a32180f8b26749bf5daf0602262e33464bcb3a042a8ff51ec2844cdeef2f9e5</sha256>
|
||||||
|
|
||||||
<tags>
|
<tags>
|
||||||
<tag>alpha</tag>
|
<tag>alpha</tag>
|
||||||
@@ -167,9 +167,9 @@
|
|||||||
<infourl title='MokoCassiopeia Beta'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/beta</infourl>
|
<infourl title='MokoCassiopeia Beta'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/tag/beta</infourl>
|
||||||
|
|
||||||
<downloads>
|
<downloads>
|
||||||
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/beta/mokocassiopeia-beta.zip</downloadurl>
|
<downloadurl type='full' format='zip'>https://github.com/mokoconsulting-tech/MokoCassiopeia/releases/download/beta/mokocassiopeia-03.09.07-beta.zip</downloadurl>
|
||||||
</downloads>
|
</downloads>
|
||||||
<sha256>b5f6d073d126f0041ddd475e61bc4eaa050e060e9b51f4fe0e8a348f188c40b2</sha256>
|
<sha256>1a32180f8b26749bf5daf0602262e33464bcb3a042a8ff51ec2844cdeef2f9e5</sha256>
|
||||||
|
|
||||||
<tags>
|
<tags>
|
||||||
<tag>beta</tag>
|
<tag>beta</tag>
|
||||||
|
|||||||
Reference in New Issue
Block a user