mirror of
https://github.com/chenasraf/workflows.git
synced 2026-05-18 01:29:00 +00:00
Compare commits
21 Commits
go-release
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| dca08bb6c3 | |||
| 808077ef6b | |||
| c8c1609cba | |||
| ca85c41ef4 | |||
| a69ee802a6 | |||
| 70151d294e | |||
| dd6e138c7a | |||
| 94a677ab82 | |||
| 5755a7bfd8 | |||
| 388711cc86 | |||
| e203813f6f | |||
| 0808232cc6 | |||
| 1df942d283 | |||
| fdc3b6d89f | |||
| f708347ed3 | |||
| 6d06d8bbc5 | |||
| 2a0c1c7c22 | |||
| b61dbc6d15 | |||
| 135a943972 | |||
| ed9ea64941 | |||
| 50c6be783b |
10
.editorconfig
Normal file
10
.editorconfig
Normal file
@@ -0,0 +1,10 @@
|
||||
# EditorConfig for Makefile
|
||||
root = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
89
.github/workflows/homebrew-release.yml
vendored
Normal file
89
.github/workflows/homebrew-release.yml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
# Reusable Homebrew Release Workflow
|
||||
#
|
||||
# Dispatches a homebrew formula update to a tap repo.
|
||||
# Does not include any build steps — suitable for shell-only packages.
|
||||
#
|
||||
# Call from other repos:
|
||||
# jobs:
|
||||
# homebrew:
|
||||
# uses: chenasraf/workflows/.github/workflows/homebrew-release.yml@master
|
||||
# with:
|
||||
# homebrew-tap-repo: owner/homebrew-tap
|
||||
# tag: ${{ needs.release.outputs.tag_name }}
|
||||
# secrets:
|
||||
# REPO_DISPATCH_PAT: ${{ secrets.REPO_DISPATCH_PAT }}
|
||||
|
||||
name: Homebrew Release
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
homebrew-tap-repo:
|
||||
description: 'Homebrew tap repo to dispatch to (e.g., owner/homebrew-tap)'
|
||||
required: true
|
||||
type: string
|
||||
tag:
|
||||
description: 'Release tag to dispatch (e.g., v1.0.0). If empty, uses the latest release tag.'
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
secrets:
|
||||
REPO_DISPATCH_PAT:
|
||||
description: 'PAT for dispatching to homebrew tap repo'
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
release-homebrew:
|
||||
name: Trigger Homebrew Formula Update
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get release info
|
||||
id: release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
tag="${{ inputs.tag }}"
|
||||
if [[ -z "$tag" ]]; then
|
||||
tag=$(gh release view --json tagName -q .tagName)
|
||||
echo "Using latest release tag: $tag"
|
||||
else
|
||||
echo "Using provided tag: $tag"
|
||||
fi
|
||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||
|
||||
body=$(gh release view "$tag" --json body -q .body)
|
||||
echo "body<<EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "$body" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Send dispatch to homebrew-tap
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REPO_DISPATCH_PAT }}
|
||||
run: |
|
||||
tag="${{ steps.release.outputs.tag }}"
|
||||
repo="${{ github.event.repository.name }}"
|
||||
body=$(cat <<'BODY_EOF'
|
||||
${{ steps.release.outputs.body }}
|
||||
BODY_EOF
|
||||
)
|
||||
data=$(jq -n \
|
||||
--arg tag "$tag" \
|
||||
--arg repo "$repo" \
|
||||
--arg body "$body" \
|
||||
'{event_type: "trigger-from-release", client_payload: {tag: $tag, repo: $repo, body: $body}}')
|
||||
echo "Dispatching tag $tag from $repo"
|
||||
echo "Data: $data"
|
||||
curl -X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer $GH_TOKEN" \
|
||||
"https://api.github.com/repos/${{ inputs.homebrew-tap-repo }}/dispatches" \
|
||||
-d "$data"
|
||||
echo "Dispatched tag $tag from $repo"
|
||||
echo "Created job on https://github.com/${{ inputs.homebrew-tap-repo }}/actions"
|
||||
75
.github/workflows/manual-homebrew-release.yml
vendored
Normal file
75
.github/workflows/manual-homebrew-release.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
# Reusable Manual Homebrew Release Workflow
|
||||
#
|
||||
# Call from other repos:
|
||||
# jobs:
|
||||
# homebrew:
|
||||
# uses: chenasraf/workflows/.github/workflows/manual-homebrew-release.yml@master
|
||||
# with:
|
||||
# homebrew-tap-repo: owner/homebrew-tap
|
||||
# secrets:
|
||||
# REPO_DISPATCH_PAT: ${{ secrets.REPO_DISPATCH_PAT }}
|
||||
|
||||
name: Manual Homebrew Release
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
homebrew-tap-repo:
|
||||
description: 'Homebrew tap repo to dispatch to (e.g., owner/homebrew-tap)'
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
REPO_DISPATCH_PAT:
|
||||
description: 'PAT for dispatching to homebrew tap repo'
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
release-homebrew:
|
||||
name: Trigger Homebrew Formula Update
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get latest release info
|
||||
id: latest
|
||||
run: |
|
||||
tag=$(gh release view --json tagName -q .tagName)
|
||||
echo "Latest release tag: $tag"
|
||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||
|
||||
body=$(gh release view --json body -q .body)
|
||||
echo "body<<EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "$body" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Send dispatch to homebrew-tap
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REPO_DISPATCH_PAT }}
|
||||
run: |
|
||||
tag="${{ steps.latest.outputs.tag }}"
|
||||
repo="${{ github.event.repository.name }}"
|
||||
body=$(cat <<'BODY_EOF'
|
||||
${{ steps.latest.outputs.body }}
|
||||
BODY_EOF
|
||||
)
|
||||
data=$(jq -n \
|
||||
--arg tag "$tag" \
|
||||
--arg repo "$repo" \
|
||||
--arg body "$body" \
|
||||
'{event_type: "trigger-from-release", client_payload: {tag: $tag, repo: $repo, body: $body}}')
|
||||
echo "Dispatching tag $tag from $repo"
|
||||
echo "Data: $data"
|
||||
curl -X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer $GH_TOKEN" \
|
||||
"https://api.github.com/repos/${{ inputs.homebrew-tap-repo }}/dispatches" \
|
||||
-d "$data"
|
||||
echo "Dispatched tag $tag from $repo"
|
||||
echo "Created job on https://github.com/${{ inputs.homebrew-tap-repo }}/actions"
|
||||
33
.github/workflows/nextcloud-block-unconventional-commits.yml
vendored
Normal file
33
.github/workflows/nextcloud-block-unconventional-commits.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# Reusable workflow for blocking unconventional commits
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Block unconventional commits
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
allowed-types:
|
||||
description: 'Comma-separated list of allowed commit types (leave empty for defaults: feat,fix,docs,style,refactor,perf,test,build,ci,chore,revert)'
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
block-unconventional-commits:
|
||||
name: Block unconventional commits
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: webiny/action-conventional-commits@v1.3.0
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
94
.github/workflows/nextcloud-build-npm.yml
vendored
Normal file
94
.github/workflows/nextcloud-build-npm.yml
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# Reusable workflow for NPM build verification
|
||||
#
|
||||
# SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Build NPM
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build-command:
|
||||
description: 'Command to run build'
|
||||
required: false
|
||||
type: string
|
||||
default: 'pnpm build'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '.github/workflows/**'
|
||||
- 'src/**'
|
||||
- '*.ts'
|
||||
- '*.js'
|
||||
- '*.json'
|
||||
- '*.yaml'
|
||||
- 'pnpm-lock.yaml'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
name: PNPM Build
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
PUPPETEER_SKIP_DOWNLOAD: true
|
||||
run: |
|
||||
npm i -g pnpm
|
||||
pnpm i --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: ${{ inputs.build-command }}
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, build]
|
||||
|
||||
if: always()
|
||||
|
||||
name: build-npm-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.build.result != 'success' }}; then exit 1; fi
|
||||
90
.github/workflows/nextcloud-lint-appinfo-xml.yml
vendored
Normal file
90
.github/workflows/nextcloud-lint-appinfo-xml.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
# Reusable workflow for Nextcloud appinfo.xml linting
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Lint appinfo.xml
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
xml-file:
|
||||
description: 'Path to the info.xml file'
|
||||
required: false
|
||||
type: string
|
||||
default: './appinfo/info.xml'
|
||||
schema-url:
|
||||
description: 'URL to the XSD schema file'
|
||||
required: false
|
||||
type: string
|
||||
default: 'https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/api/v1/release/info.xsd'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- 'appinfo/info.xml'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
xml-linters:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
name: info.xml lint
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download schema
|
||||
run: wget ${{ inputs.schema-url }} -O info.xsd
|
||||
|
||||
- name: Lint info.xml
|
||||
uses: ChristophWurst/xmllint-action@v1
|
||||
with:
|
||||
xml-file: ${{ inputs.xml-file }}
|
||||
xml-schema-file: ./info.xsd
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, xml-linters]
|
||||
|
||||
if: always()
|
||||
|
||||
name: appinfo-xml-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.xml-linters.result != 'success' }}; then exit 1; fi
|
||||
94
.github/workflows/nextcloud-lint-eslint.yml
vendored
Normal file
94
.github/workflows/nextcloud-lint-eslint.yml
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# Reusable workflow for ESLint linting
|
||||
#
|
||||
# SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
name: Lint eslint
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
lint-command:
|
||||
description: 'Command to run lint'
|
||||
required: false
|
||||
type: string
|
||||
default: 'pnpm lint'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '.github/workflows/**'
|
||||
- 'src/**'
|
||||
- '*.ts'
|
||||
- '*.js'
|
||||
- '*.json'
|
||||
- '*.yaml'
|
||||
- 'pnpm-lock.yaml'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
name: NPM lint
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
PUPPETEER_SKIP_DOWNLOAD: true
|
||||
run: |
|
||||
npm i -g pnpm
|
||||
pnpm i --frozen-lockfile
|
||||
|
||||
- name: Lint
|
||||
run: ${{ inputs.lint-command }}
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, lint]
|
||||
|
||||
if: always()
|
||||
|
||||
name: eslint
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.lint.result != 'success' }}; then exit 1; fi
|
||||
126
.github/workflows/nextcloud-lint-openapi.yml
vendored
Normal file
126
.github/workflows/nextcloud-lint-openapi.yml
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
# Reusable workflow for OpenAPI spec linting
|
||||
#
|
||||
# SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Lint OpenAPI
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
openapi-command:
|
||||
description: 'Composer command to regenerate OpenAPI'
|
||||
required: false
|
||||
type: string
|
||||
default: 'composer run openapi'
|
||||
typescript-types-pattern:
|
||||
description: 'Glob pattern to check for TypeScript OpenAPI types'
|
||||
required: false
|
||||
type: string
|
||||
default: 'src/types/openapi/openapi*.ts'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- 'lib/**/*.php'
|
||||
- 'openapi.json'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
openapi:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true' && github.repository_owner != 'nextcloud-gmbh'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get php version
|
||||
id: php_versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
|
||||
- name: Set up php
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ steps.php_versions.outputs.php-available }}
|
||||
extensions: xml
|
||||
coverage: none
|
||||
ini-file: development
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check Typescript OpenApi types
|
||||
id: check_typescript_openapi
|
||||
uses: andstor/file-existence-action@v3
|
||||
with:
|
||||
files: ${{ inputs.typescript-types-pattern }}
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
PUPPETEER_SKIP_DOWNLOAD: true
|
||||
run: |
|
||||
npm i -g pnpm
|
||||
pnpm i --frozen-lockfile
|
||||
|
||||
- name: Set up dependencies
|
||||
run: composer i
|
||||
|
||||
- name: Regenerate OpenAPI
|
||||
run: ${{ inputs.openapi-command }}
|
||||
|
||||
- name: Check openapi*.json and typescript changes
|
||||
run: |
|
||||
bash -c "[[ ! \"`git status --porcelain `\" ]] || (echo 'Please run \"composer run openapi\" and commit the openapi*.json files and (if applicable) src/types/openapi/openapi*.ts, see the section \"Show changes on failure\" for details' && exit 1)"
|
||||
|
||||
- name: Show changes on failure
|
||||
if: failure()
|
||||
run: |
|
||||
git status
|
||||
git --no-pager diff
|
||||
exit 1
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, openapi]
|
||||
|
||||
if: always()
|
||||
|
||||
name: openapi-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.openapi.result != 'success' && needs.openapi.result != 'skipped' }}; then exit 1; fi
|
||||
103
.github/workflows/nextcloud-lint-php-cs.yml
vendored
Normal file
103
.github/workflows/nextcloud-lint-php-cs.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
# Reusable workflow for PHP code style linting
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Lint php-cs
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
cs-check-command:
|
||||
description: 'Composer command to check code style'
|
||||
required: false
|
||||
type: string
|
||||
default: "composer run cs:check || ( echo 'Please run `composer run cs:fix` to format your code' && exit 1 )"
|
||||
php-extensions:
|
||||
description: 'PHP extensions to install'
|
||||
required: false
|
||||
type: string
|
||||
default: 'bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '**.php'
|
||||
- '.php-cs-fixer.dist.php'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
name: php-cs
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get php version
|
||||
id: versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
|
||||
- name: Set up php${{ steps.versions.outputs.php-available }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ steps.versions.outputs.php-available }}
|
||||
extensions: ${{ inputs.php-extensions }}
|
||||
coverage: none
|
||||
ini-file: development
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer i
|
||||
|
||||
- name: Lint
|
||||
run: ${{ inputs.cs-check-command }}
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, lint]
|
||||
|
||||
if: always()
|
||||
|
||||
name: php-cs-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.lint.result != 'success' }}; then exit 1; fi
|
||||
122
.github/workflows/nextcloud-lint-php.yml
vendored
Normal file
122
.github/workflows/nextcloud-lint-php.yml
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
# Reusable workflow for PHP syntax linting
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Lint php
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
lint-command:
|
||||
description: 'Composer command to run lint'
|
||||
required: false
|
||||
type: string
|
||||
default: 'composer run lint'
|
||||
php-versions-min:
|
||||
description: 'Minimum PHP version to include in the lint matrix (filters out anything lower than this from the auto-detected matrix)'
|
||||
required: false
|
||||
type: string
|
||||
default: '8.1'
|
||||
php-extensions:
|
||||
description: 'PHP extensions to install'
|
||||
required: false
|
||||
type: string
|
||||
default: 'bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '**.php'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
outputs:
|
||||
php-versions: ${{ steps.filter.outputs.php-versions }}
|
||||
steps:
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
- name: Get version matrix
|
||||
id: versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
- name: Filter php versions by minimum
|
||||
id: filter
|
||||
run: |
|
||||
FILTERED=$(echo '${{ steps.versions.outputs.php-versions }}' | jq -c --arg min "${{ inputs.php-versions-min }}" '[.[] | select(. >= $min)]')
|
||||
echo "php-versions=$FILTERED" >> $GITHUB_OUTPUT
|
||||
echo "Filtered php matrix (>= ${{ inputs.php-versions-min }}): $FILTERED"
|
||||
|
||||
php-lint:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, matrix]
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ${{fromJson(needs.matrix.outputs.php-versions)}}
|
||||
|
||||
name: php-lint
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up php ${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: ${{ inputs.php-extensions }}
|
||||
coverage: none
|
||||
ini-file: development
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Lint
|
||||
run: ${{ inputs.lint-command }}
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, php-lint]
|
||||
|
||||
if: always()
|
||||
|
||||
name: php-lint-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.php-lint.result != 'success' }}; then exit 1; fi
|
||||
380
.github/workflows/nextcloud-phpunit-incremental.yml
vendored
Normal file
380
.github/workflows/nextcloud-phpunit-incremental.yml
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
# Reusable workflow for incremental migration tests
|
||||
#
|
||||
# This workflow tests that migrations work correctly when upgrading from an older version.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: PHPUnit Incremental Migration
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
baseline-version:
|
||||
description: 'Git tag/ref for the baseline version to upgrade from'
|
||||
required: true
|
||||
type: string
|
||||
php-version:
|
||||
description: 'PHP version to test'
|
||||
required: false
|
||||
type: string
|
||||
default: '8.3'
|
||||
php-extensions-mysql:
|
||||
description: 'PHP extensions for MySQL tests'
|
||||
required: false
|
||||
type: string
|
||||
default: 'bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, mysql, pdo_mysql'
|
||||
php-extensions-pgsql:
|
||||
description: 'PHP extensions for PostgreSQL tests'
|
||||
required: false
|
||||
type: string
|
||||
default: 'bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, pgsql, pdo_pgsql'
|
||||
validation-query:
|
||||
description: 'SQL query to validate migration (e.g., "SELECT COUNT(*) FROM oc_forum_users")'
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '.github/workflows/**'
|
||||
- 'appinfo/**'
|
||||
- 'lib/**'
|
||||
- 'tests/**'
|
||||
- 'composer.json'
|
||||
- 'composer.lock'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
incremental-pgsql:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
name: Incremental Migration (PostgreSQL)
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: ghcr.io/nextcloud/continuous-integration-postgres-16:latest
|
||||
ports:
|
||||
- 4444:5432/tcp
|
||||
env:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_PASSWORD: rootpassword
|
||||
POSTGRES_DB: nextcloud
|
||||
options: --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5
|
||||
|
||||
steps:
|
||||
- name: Checkout app (current)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: app-current
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Detect app ID from appinfo/info.xml
|
||||
run: |
|
||||
APP_ID=$(grep -oP '(?<=<id>)[^<]+' app-current/appinfo/info.xml | head -1)
|
||||
echo "APP_NAME=$APP_ID" >> $GITHUB_ENV
|
||||
echo "Detected app ID: $APP_ID"
|
||||
|
||||
- name: Get supported server versions
|
||||
id: versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
with:
|
||||
filename: app-current/appinfo/info.xml
|
||||
|
||||
- name: Save current app for later
|
||||
run: |
|
||||
mkdir -p /tmp/app-backup
|
||||
cp -r app-current /tmp/app-backup/
|
||||
|
||||
- name: Checkout server
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: true
|
||||
repository: nextcloud/server
|
||||
ref: ${{ fromJson(steps.versions.outputs.branches)[0] }}
|
||||
|
||||
- name: Checkout app at baseline version
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ inputs.baseline-version }}
|
||||
path: apps/${{ env.APP_NAME }}
|
||||
|
||||
- name: Set up php ${{ inputs.php-version }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ inputs.php-version }}
|
||||
extensions: ${{ inputs.php-extensions-pgsql }}
|
||||
coverage: none
|
||||
ini-file: development
|
||||
ini-values: disable_functions=
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up dependencies (baseline)
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer remove nextcloud/ocp --dev --no-scripts || true
|
||||
composer i --no-scripts || composer i
|
||||
|
||||
- name: Set up Nextcloud and install app at baseline
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
mkdir data
|
||||
./occ maintenance:install --verbose --database=pgsql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
|
||||
echo "::group::Installing app at baseline"
|
||||
./occ app:enable --force ${{ env.APP_NAME }}
|
||||
echo "::endgroup::"
|
||||
echo "::group::Database tables after baseline install"
|
||||
./occ db:convert-filecache-bigint --no-interaction || true
|
||||
PGPASSWORD=rootpassword psql -h 127.0.0.1 -p $DB_PORT -U root -d nextcloud -c "\dt oc_${{ env.APP_NAME }}_*"
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Upgrade app to current version
|
||||
run: |
|
||||
echo "::group::Replacing app with current version"
|
||||
rm -rf apps/${{ env.APP_NAME }}
|
||||
cp -r /tmp/app-backup/app-current apps/${{ env.APP_NAME }}
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Set up dependencies (current)
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer remove nextcloud/ocp --dev --no-scripts || true
|
||||
composer i
|
||||
|
||||
- name: Run migrations to current version
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
echo "::group::Running upgrade migrations"
|
||||
./occ maintenance:mode --off || true
|
||||
./occ app:disable ${{ env.APP_NAME }}
|
||||
./occ app:enable ${{ env.APP_NAME }}
|
||||
echo "::endgroup::"
|
||||
echo "::group::Database tables after upgrade"
|
||||
PGPASSWORD=rootpassword psql -h 127.0.0.1 -p $DB_PORT -U root -d nextcloud -c "\dt oc_${{ env.APP_NAME }}_*"
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Validate migration
|
||||
if: inputs.validation-query != ''
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
echo "::group::Running validation query"
|
||||
PGPASSWORD=rootpassword psql -h 127.0.0.1 -p $DB_PORT -U root -d nextcloud -c "${{ inputs.validation-query }}" || exit 1
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Check PHPUnit integration script is defined
|
||||
id: check_integration
|
||||
continue-on-error: true
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer run --list | grep '^ test:integration ' | wc -l | grep 1
|
||||
|
||||
- name: Run Nextcloud
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
run: php -S localhost:8080 &
|
||||
|
||||
- name: PHPUnit integration
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: composer run test:integration -- --display-all-issues
|
||||
|
||||
- name: Print logs
|
||||
if: always()
|
||||
run: |
|
||||
cat data/nextcloud.log
|
||||
|
||||
incremental-mysql:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
name: Incremental Migration (MySQL)
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: ghcr.io/nextcloud/continuous-integration-mariadb-10.11:latest
|
||||
ports:
|
||||
- 4444:3306/tcp
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: rootpassword
|
||||
MYSQL_DATABASE: nextcloud
|
||||
options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 5
|
||||
|
||||
steps:
|
||||
- name: Checkout app (current)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: app-current
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Detect app ID from appinfo/info.xml
|
||||
run: |
|
||||
APP_ID=$(grep -oP '(?<=<id>)[^<]+' app-current/appinfo/info.xml | head -1)
|
||||
echo "APP_NAME=$APP_ID" >> $GITHUB_ENV
|
||||
echo "Detected app ID: $APP_ID"
|
||||
|
||||
- name: Get supported server versions
|
||||
id: versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
with:
|
||||
filename: app-current/appinfo/info.xml
|
||||
|
||||
- name: Save current app for later
|
||||
run: |
|
||||
mkdir -p /tmp/app-backup
|
||||
cp -r app-current /tmp/app-backup/
|
||||
|
||||
- name: Checkout server
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: true
|
||||
repository: nextcloud/server
|
||||
ref: ${{ fromJson(steps.versions.outputs.branches)[0] }}
|
||||
|
||||
- name: Checkout app at baseline version
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ inputs.baseline-version }}
|
||||
path: apps/${{ env.APP_NAME }}
|
||||
|
||||
- name: Set up php ${{ inputs.php-version }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ inputs.php-version }}
|
||||
extensions: ${{ inputs.php-extensions-mysql }}
|
||||
coverage: none
|
||||
ini-file: development
|
||||
ini-values: disable_functions=
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up dependencies (baseline)
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer remove nextcloud/ocp --dev --no-scripts || true
|
||||
composer i --no-scripts || composer i
|
||||
|
||||
- name: Set up Nextcloud and install app at baseline
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
mkdir data
|
||||
./occ maintenance:install --verbose --database=mysql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
|
||||
echo "::group::Installing app at baseline"
|
||||
./occ app:enable --force ${{ env.APP_NAME }}
|
||||
echo "::endgroup::"
|
||||
echo "::group::Database tables after baseline install"
|
||||
mysql -h 127.0.0.1 -P $DB_PORT -u root -prootpassword nextcloud -e "SHOW TABLES LIKE 'oc_${{ env.APP_NAME }}_%'"
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Upgrade app to current version
|
||||
run: |
|
||||
echo "::group::Replacing app with current version"
|
||||
rm -rf apps/${{ env.APP_NAME }}
|
||||
cp -r /tmp/app-backup/app-current apps/${{ env.APP_NAME }}
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Set up dependencies (current)
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer remove nextcloud/ocp --dev --no-scripts || true
|
||||
composer i
|
||||
|
||||
- name: Run migrations to current version
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
echo "::group::Running upgrade migrations"
|
||||
./occ maintenance:mode --off || true
|
||||
./occ app:disable ${{ env.APP_NAME }}
|
||||
./occ app:enable ${{ env.APP_NAME }}
|
||||
echo "::endgroup::"
|
||||
echo "::group::Database tables after upgrade"
|
||||
mysql -h 127.0.0.1 -P $DB_PORT -u root -prootpassword nextcloud -e "SHOW TABLES LIKE 'oc_${{ env.APP_NAME }}_%'"
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Validate migration
|
||||
if: inputs.validation-query != ''
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
echo "::group::Running validation query"
|
||||
mysql -h 127.0.0.1 -P $DB_PORT -u root -prootpassword nextcloud -e "${{ inputs.validation-query }}" || exit 1
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Check PHPUnit integration script is defined
|
||||
id: check_integration
|
||||
continue-on-error: true
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer run --list | grep '^ test:integration ' | wc -l | grep 1
|
||||
|
||||
- name: Run Nextcloud
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
run: php -S localhost:8080 &
|
||||
|
||||
- name: PHPUnit integration
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: composer run test:integration -- --display-all-issues
|
||||
|
||||
- name: Print logs
|
||||
if: always()
|
||||
run: |
|
||||
cat data/nextcloud.log
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, incremental-pgsql, incremental-mysql]
|
||||
|
||||
if: always()
|
||||
|
||||
name: incremental-migration-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && (needs.incremental-pgsql.result != 'success' || needs.incremental-mysql.result != 'success') }}; then exit 1; fi
|
||||
243
.github/workflows/nextcloud-phpunit-mysql.yml
vendored
Normal file
243
.github/workflows/nextcloud-phpunit-mysql.yml
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
# Reusable workflow for PHPUnit tests with MySQL
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: PHPUnit MySQL
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
php-versions-min:
|
||||
description: 'Minimum PHP version to test'
|
||||
required: false
|
||||
type: string
|
||||
default: '8.2'
|
||||
php-versions-max:
|
||||
description: 'Maximum PHP version to test'
|
||||
required: false
|
||||
type: string
|
||||
default: '8.3'
|
||||
mysql-version:
|
||||
description: 'MySQL version to use'
|
||||
required: false
|
||||
type: string
|
||||
default: '8.4'
|
||||
php-extensions:
|
||||
description: 'PHP extensions to install'
|
||||
required: false
|
||||
type: string
|
||||
default: 'bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, mysql, pdo_mysql'
|
||||
path-filters:
|
||||
description: 'JSON array of paths to filter on'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '.github/workflows/**'
|
||||
- 'appinfo/**'
|
||||
- 'lib/**'
|
||||
- 'templates/**'
|
||||
- 'tests/**'
|
||||
- 'vendor/**'
|
||||
- 'vendor-bin/**'
|
||||
- '.php-cs-fixer.dist.php'
|
||||
- 'composer.json'
|
||||
- 'composer.lock'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get supported server versions
|
||||
id: versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
|
||||
- name: Build test matrix
|
||||
id: set-matrix
|
||||
run: |
|
||||
BRANCHES='${{ steps.versions.outputs.branches }}'
|
||||
MATRIX=$(jq -nc \
|
||||
--argjson branches "$BRANCHES" \
|
||||
--arg phpMin "${{ inputs.php-versions-min }}" \
|
||||
--arg phpMax "${{ inputs.php-versions-max }}" \
|
||||
--arg mysql "${{ inputs.mysql-version }}" \
|
||||
'{include: [{"php-versions": $phpMin, "mysql-versions": $mysql, "server-versions": $branches[0]}, {"php-versions": $phpMax, "mysql-versions": $mysql, "server-versions": $branches[-1]}]}'
|
||||
)
|
||||
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
|
||||
echo "Generated matrix: $MATRIX"
|
||||
|
||||
phpunit-mysql:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
needs: [changes, matrix]
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
strategy:
|
||||
matrix: ${{ fromJson(needs.matrix.outputs.matrix) }}
|
||||
|
||||
name: MySQL ${{ matrix.mysql-versions }} PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }}
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: ghcr.io/nextcloud/continuous-integration-mysql-${{ matrix.mysql-versions }}:latest
|
||||
ports:
|
||||
- 4444:3306/tcp
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: rootpassword
|
||||
options: --health-cmd="mysqladmin ping" --health-interval 5s --health-timeout 2s --health-retries 10
|
||||
|
||||
steps:
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: app-checkout
|
||||
|
||||
- name: Detect app ID from appinfo/info.xml
|
||||
run: |
|
||||
APP_ID=$(grep -oP '(?<=<id>)[^<]+' app-checkout/appinfo/info.xml | head -1)
|
||||
echo "APP_NAME=$APP_ID" >> $GITHUB_ENV
|
||||
echo "Detected app ID: $APP_ID"
|
||||
|
||||
- name: Checkout server
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: true
|
||||
repository: nextcloud/server
|
||||
ref: ${{ matrix.server-versions }}
|
||||
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: apps/${{ env.APP_NAME }}
|
||||
|
||||
- name: Set up php ${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: ${{ inputs.php-extensions }}
|
||||
coverage: none
|
||||
ini-file: development
|
||||
ini-values: disable_functions=
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable ONLY_FULL_GROUP_BY MySQL option
|
||||
run: |
|
||||
echo "SET GLOBAL sql_mode=(SELECT CONCAT(@@sql_mode,',ONLY_FULL_GROUP_BY'));" | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
|
||||
echo 'SELECT @@sql_mode;' | mysql -h 127.0.0.1 -P 4444 -u root -prootpassword
|
||||
|
||||
- name: Check composer file existence
|
||||
id: check_composer
|
||||
uses: andstor/file-existence-action@v3
|
||||
with:
|
||||
files: apps/${{ env.APP_NAME }}/composer.json
|
||||
|
||||
- name: Set up dependencies
|
||||
if: steps.check_composer.outputs.files_exists == 'true'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer remove nextcloud/ocp --dev --no-scripts
|
||||
composer i
|
||||
|
||||
- name: Set up Nextcloud
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
mkdir data
|
||||
./occ maintenance:install --verbose --database=mysql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
|
||||
./occ app:enable --force ${{ env.APP_NAME }}
|
||||
|
||||
- name: Check PHPUnit script is defined
|
||||
id: check_phpunit
|
||||
continue-on-error: true
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer run --list | grep '^ test:unit ' | wc -l | grep 1
|
||||
|
||||
- name: PHPUnit
|
||||
if: steps.check_phpunit.outcome == 'success'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: composer run test:unit -- --display-all-issues
|
||||
|
||||
- name: Check PHPUnit integration script is defined
|
||||
id: check_integration
|
||||
continue-on-error: true
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer run --list | grep '^ test:integration ' | wc -l | grep 1
|
||||
|
||||
- name: Run Nextcloud
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
run: php -S localhost:8080 &
|
||||
|
||||
- name: PHPUnit integration
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: composer run test:integration -- --display-all-issues
|
||||
|
||||
- name: Print logs
|
||||
if: always()
|
||||
run: |
|
||||
cat data/nextcloud.log
|
||||
|
||||
- name: Skipped
|
||||
if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure'
|
||||
run: |
|
||||
echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts'
|
||||
exit 1
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, phpunit-mysql]
|
||||
|
||||
if: always()
|
||||
|
||||
name: phpunit-mysql-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.phpunit-mysql.result != 'success' }}; then exit 1; fi
|
||||
228
.github/workflows/nextcloud-phpunit-pgsql.yml
vendored
Normal file
228
.github/workflows/nextcloud-phpunit-pgsql.yml
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
# Reusable workflow for PHPUnit tests with PostgreSQL
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: PHPUnit PostgreSQL
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
php-version:
|
||||
description: 'PHP version to test'
|
||||
required: false
|
||||
type: string
|
||||
default: '8.3'
|
||||
php-extensions:
|
||||
description: 'PHP extensions to install'
|
||||
required: false
|
||||
type: string
|
||||
default: 'bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, pgsql, pdo_pgsql'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '.github/workflows/**'
|
||||
- 'appinfo/**'
|
||||
- 'lib/**'
|
||||
- 'templates/**'
|
||||
- 'tests/**'
|
||||
- 'vendor/**'
|
||||
- 'vendor-bin/**'
|
||||
- '.php-cs-fixer.dist.php'
|
||||
- 'composer.json'
|
||||
- 'composer.lock'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get supported server versions
|
||||
id: versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
|
||||
- name: Build test matrix
|
||||
id: set-matrix
|
||||
run: |
|
||||
BRANCHES='${{ steps.versions.outputs.branches }}'
|
||||
MATRIX=$(jq -nc \
|
||||
--argjson branches "$BRANCHES" \
|
||||
--arg php "${{ inputs.php-version }}" \
|
||||
'{include: [{"php-versions": $php, "server-versions": $branches[-1]}]}'
|
||||
)
|
||||
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
|
||||
echo "Generated matrix: $MATRIX"
|
||||
|
||||
phpunit-pgsql:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
needs: [changes, matrix]
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
strategy:
|
||||
matrix: ${{ fromJson(needs.matrix.outputs.matrix) }}
|
||||
|
||||
name: PostgreSQL PHP ${{ matrix.php-versions }} Nextcloud ${{ matrix.server-versions }}
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: ghcr.io/nextcloud/continuous-integration-postgres-16:latest
|
||||
ports:
|
||||
- 4444:5432/tcp
|
||||
env:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_PASSWORD: rootpassword
|
||||
POSTGRES_DB: nextcloud
|
||||
options: --health-cmd pg_isready --health-interval 5s --health-timeout 2s --health-retries 5
|
||||
|
||||
steps:
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: app-checkout
|
||||
|
||||
- name: Detect app ID from appinfo/info.xml
|
||||
run: |
|
||||
APP_ID=$(grep -oP '(?<=<id>)[^<]+' app-checkout/appinfo/info.xml | head -1)
|
||||
echo "APP_NAME=$APP_ID" >> $GITHUB_ENV
|
||||
echo "Detected app ID: $APP_ID"
|
||||
|
||||
- name: Checkout server
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: true
|
||||
repository: nextcloud/server
|
||||
ref: ${{ matrix.server-versions }}
|
||||
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
path: apps/${{ env.APP_NAME }}
|
||||
|
||||
- name: Set up php ${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: ${{ inputs.php-extensions }}
|
||||
coverage: none
|
||||
ini-file: development
|
||||
ini-values: disable_functions=
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check composer file existence
|
||||
id: check_composer
|
||||
uses: andstor/file-existence-action@v3
|
||||
with:
|
||||
files: apps/${{ env.APP_NAME }}/composer.json
|
||||
|
||||
- name: Set up dependencies
|
||||
if: steps.check_composer.outputs.files_exists == 'true'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer remove nextcloud/ocp --dev --no-scripts
|
||||
composer i
|
||||
|
||||
- name: Set up Nextcloud
|
||||
env:
|
||||
DB_PORT: 4444
|
||||
run: |
|
||||
mkdir data
|
||||
./occ maintenance:install --verbose --database=pgsql --database-name=nextcloud --database-host=127.0.0.1 --database-port=$DB_PORT --database-user=root --database-pass=rootpassword --admin-user admin --admin-pass admin
|
||||
./occ app:enable --force ${{ env.APP_NAME }}
|
||||
|
||||
- name: Check PHPUnit script is defined
|
||||
id: check_phpunit
|
||||
continue-on-error: true
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer run --list | grep '^ test:unit ' | wc -l | grep 1
|
||||
|
||||
- name: PHPUnit
|
||||
if: steps.check_phpunit.outcome == 'success'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: composer run test:unit -- --display-all-issues
|
||||
|
||||
- name: Check PHPUnit integration script is defined
|
||||
id: check_integration
|
||||
continue-on-error: true
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: |
|
||||
composer run --list | grep '^ test:integration ' | wc -l | grep 1
|
||||
|
||||
- name: Run Nextcloud
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
run: php -S localhost:8080 &
|
||||
|
||||
- name: PHPUnit integration
|
||||
if: steps.check_integration.outcome == 'success'
|
||||
working-directory: apps/${{ env.APP_NAME }}
|
||||
run: composer run test:integration -- --display-all-issues
|
||||
|
||||
- name: Print logs
|
||||
if: always()
|
||||
run: |
|
||||
cat data/nextcloud.log
|
||||
|
||||
- name: Skipped
|
||||
if: steps.check_phpunit.outcome == 'failure' && steps.check_integration.outcome == 'failure'
|
||||
run: |
|
||||
echo 'Neither PHPUnit nor PHPUnit integration tests are specified in composer.json scripts'
|
||||
exit 1
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, phpunit-pgsql]
|
||||
|
||||
if: always()
|
||||
|
||||
name: phpunit-pgsql-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.phpunit-pgsql.result != 'success' }}; then exit 1; fi
|
||||
126
.github/workflows/nextcloud-psalm.yml
vendored
Normal file
126
.github/workflows/nextcloud-psalm.yml
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
# Reusable workflow for Psalm static analysis
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: Static analysis
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
psalm-command:
|
||||
description: 'Composer command to run Psalm'
|
||||
required: false
|
||||
type: string
|
||||
default: 'composer run psalm'
|
||||
php-versions-min:
|
||||
description: 'Minimum PHP version to include in the analysis matrix (filters out any auto-detected ocp-matrix entries below this)'
|
||||
required: false
|
||||
type: string
|
||||
default: '8.1'
|
||||
php-extensions:
|
||||
description: 'PHP extensions to install'
|
||||
required: false
|
||||
type: string
|
||||
default: 'bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '**.php'
|
||||
- 'psalm.xml'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
outputs:
|
||||
ocp-matrix: ${{ steps.filter.outputs.ocp-matrix }}
|
||||
steps:
|
||||
- name: Checkout app
|
||||
uses: actions/checkout@v4
|
||||
- name: Get version matrix
|
||||
id: versions
|
||||
uses: icewind1991/nextcloud-version-matrix@v1
|
||||
- name: Filter ocp-matrix by minimum php version
|
||||
id: filter
|
||||
run: |
|
||||
FILTERED=$(echo '${{ steps.versions.outputs.ocp-matrix }}' | jq -c --arg min "${{ inputs.php-versions-min }}" '.include |= [.[] | select(.["php-versions"] >= $min)]')
|
||||
echo "ocp-matrix=$FILTERED" >> $GITHUB_OUTPUT
|
||||
echo "Filtered ocp-matrix (php >= ${{ inputs.php-versions-min }}): $FILTERED"
|
||||
|
||||
static-analysis:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, matrix]
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.matrix.outputs.ocp-matrix) }}
|
||||
|
||||
name: static-psalm-analysis ${{ matrix.ocp-version }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up php${{ matrix.php-versions }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: ${{ inputs.php-extensions }}
|
||||
coverage: none
|
||||
ini-file: development
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer i
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer require --dev nextcloud/ocp:${{ matrix.ocp-version }} --ignore-platform-reqs --with-dependencies
|
||||
|
||||
- name: Run coding standards check
|
||||
run: ${{ inputs.psalm-command }}
|
||||
|
||||
summary:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, static-analysis]
|
||||
|
||||
if: always()
|
||||
|
||||
name: static-psalm-analysis-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.static-analysis.result != 'success' }}; then exit 1; fi
|
||||
120
.github/workflows/nextcloud-vitest.yml
vendored
Normal file
120
.github/workflows/nextcloud-vitest.yml
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
# Reusable workflow for Vitest frontend tests
|
||||
#
|
||||
# SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
name: Vitest
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
node-version:
|
||||
description: 'Node.js version to use'
|
||||
required: false
|
||||
type: string
|
||||
default: '22'
|
||||
test-command:
|
||||
description: 'Command to run tests'
|
||||
required: false
|
||||
type: string
|
||||
default: 'pnpm test:run'
|
||||
path-filters:
|
||||
description: 'Paths to filter on (YAML format)'
|
||||
required: false
|
||||
type: string
|
||||
default: |
|
||||
- '.github/workflows/**'
|
||||
- 'src/**'
|
||||
- 'tests/**'
|
||||
- '*.ts'
|
||||
- '*.js'
|
||||
- '*.json'
|
||||
- '*.yaml'
|
||||
- 'pnpm-lock.yaml'
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.changes.outputs.src }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build filters
|
||||
id: build-filters
|
||||
run: |
|
||||
echo "yaml<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "src:" >> $GITHUB_OUTPUT
|
||||
cat <<'INPUT_EOF' | sed 's/^/ /' >> $GITHUB_OUTPUT
|
||||
${{ inputs.path-filters }}
|
||||
INPUT_EOF
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
continue-on-error: true
|
||||
with:
|
||||
filters: ${{ steps.build-filters.outputs.yaml }}
|
||||
|
||||
vitest:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
|
||||
name: Vitest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run tests
|
||||
run: ${{ inputs.test-command }}
|
||||
|
||||
summary:
|
||||
permissions:
|
||||
contents: none
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, vitest]
|
||||
|
||||
if: always()
|
||||
|
||||
name: vitest-summary
|
||||
|
||||
steps:
|
||||
- name: Summary status
|
||||
run: if ${{ needs.changes.outputs.src == 'true' && needs.vitest.result != 'success' }}; then exit 1; fi
|
||||
250
.github/workflows/release-please-fastlane-changelog.yml
vendored
Normal file
250
.github/workflows/release-please-fastlane-changelog.yml
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
# Reusable Release Please + Fastlane Changelog Workflow
|
||||
#
|
||||
# Runs release-please, then if a PR was created/updated, generates a
|
||||
# fastlane changelog from CHANGELOG.md and amends it into the release
|
||||
# commit. The changelog is truncated to 500 chars (Play Store limit).
|
||||
#
|
||||
# Two complementary ways to configure output directories:
|
||||
#
|
||||
# 1. `fastlane-changelog-dirs` — newline-separated paths. These are
|
||||
# "catch-all" dirs: every commit (regardless of scope) is written
|
||||
# to them, unfiltered.
|
||||
#
|
||||
# 2. `scopes` — YAML map of `scope: dir(s)`. Dirs listed here are
|
||||
# scope-filtered: they only receive commits whose scope either:
|
||||
# - is not present anywhere in the map (treated as "applies
|
||||
# to all"), or
|
||||
# - is present and lists that dir among its targets.
|
||||
#
|
||||
# Example:
|
||||
# scopes: |
|
||||
# ios: fastlane/metadata/ios/en-US/changelogs
|
||||
# apple: |
|
||||
# fastlane/metadata/ios/en-US/changelogs
|
||||
# fastlane/metadata/macos/en-US/changelogs
|
||||
# android: fastlane/metadata/android/en-US/changelogs
|
||||
#
|
||||
# With this, `feat(ios): …` lands only in the iOS dir,
|
||||
# `feat(apple): …` lands in iOS and macOS, `feat(android): …`
|
||||
# lands only in the Android dir, and unscoped commits land in all.
|
||||
#
|
||||
# A dir present in both inputs is treated as a catch-all.
|
||||
#
|
||||
# Outputs are forwarded from release-please so downstream jobs can
|
||||
# use release_created, tag_name, and version.
|
||||
|
||||
name: Release Please + Fastlane Changelog
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
release-type:
|
||||
description: 'Release Please release type (e.g., dart, node, python, go)'
|
||||
required: true
|
||||
type: string
|
||||
version-file:
|
||||
description: 'File containing the version string'
|
||||
required: false
|
||||
type: string
|
||||
default: 'pubspec.yaml'
|
||||
changelog-file:
|
||||
description: 'Path to the CHANGELOG.md file'
|
||||
required: false
|
||||
type: string
|
||||
default: 'CHANGELOG.md'
|
||||
fastlane-changelog-dirs:
|
||||
description: |
|
||||
Newline-separated list of catch-all directories. Every commit
|
||||
is written here unfiltered, regardless of scope.
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
scopes:
|
||||
description: |
|
||||
YAML mapping of commit scope to one-or-more output directories.
|
||||
Dirs listed here are scope-filtered: they only receive commits
|
||||
whose scope is unmapped or lists that dir among its targets.
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
max-length:
|
||||
description: 'Maximum changelog length (Play Store limit is 500)'
|
||||
required: false
|
||||
type: number
|
||||
default: 500
|
||||
truncation-trailer:
|
||||
description: 'Text appended when changelog is truncated'
|
||||
required: false
|
||||
type: string
|
||||
default: "\n\n… see full notes on GitHub."
|
||||
secrets:
|
||||
token:
|
||||
description: 'GitHub token for release-please (defaults to GITHUB_TOKEN)'
|
||||
required: false
|
||||
outputs:
|
||||
release_created:
|
||||
description: 'Whether a release was created'
|
||||
value: ${{ jobs.release-please.outputs.release_created }}
|
||||
tag_name:
|
||||
description: 'The release tag name'
|
||||
value: ${{ jobs.release-please.outputs.tag_name }}
|
||||
version:
|
||||
description: 'The release version'
|
||||
value: ${{ jobs.release-please.outputs.version }}
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
release_created: ${{ steps.release.outputs.release_created }}
|
||||
tag_name: ${{ steps.release.outputs.tag_name }}
|
||||
version: ${{ steps.release.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Release Please
|
||||
id: release
|
||||
uses: googleapis/release-please-action@v4
|
||||
with:
|
||||
release-type: ${{ inputs.release-type }}
|
||||
token: ${{ secrets.token || github.token }}
|
||||
|
||||
- name: Update fastlane changelog on release PR
|
||||
if: ${{ steps.release.outputs.pr && !steps.release.outputs.release_created }}
|
||||
env:
|
||||
PR_JSON: ${{ steps.release.outputs.pr }}
|
||||
VERSION_FILE: ${{ inputs.version-file }}
|
||||
CHANGELOG_FILE: ${{ inputs.changelog-file }}
|
||||
OUT_DIRS: ${{ inputs.fastlane-changelog-dirs }}
|
||||
SCOPES_INPUT: ${{ inputs.scopes }}
|
||||
MAX_LENGTH: ${{ inputs.max-length }}
|
||||
TRAILER: ${{ inputs.truncation-trailer }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
PR_BRANCH=$(echo "$PR_JSON" | jq -r .headBranchName)
|
||||
git clone --depth=5 --branch "$PR_BRANCH" \
|
||||
https://x-access-token:${{ secrets.token || github.token }}@github.com/${{ github.repository }}.git _pr
|
||||
cd _pr
|
||||
|
||||
# Extract version name and code
|
||||
VERSION_LINE=$(grep '^version:' "$VERSION_FILE")
|
||||
VERSION=$(echo "$VERSION_LINE" | sed 's/version: *//;s/+.*//')
|
||||
CODE=$(echo "$VERSION_LINE" | sed 's/.*+//')
|
||||
|
||||
# Extract raw release notes from CHANGELOG.md (unfiltered, pre-cosmetics)
|
||||
if [ ! -f "$CHANGELOG_FILE" ]; then
|
||||
RAW_NOTES=""
|
||||
echo "No $CHANGELOG_FILE found, will use fallback."
|
||||
else
|
||||
RAW_NOTES=$(awk "
|
||||
/^## \\[${VERSION//./\\.}\\]/ { found=1; next }
|
||||
/^## / { if (found) exit }
|
||||
found { print }
|
||||
" "$CHANGELOG_FILE")
|
||||
fi
|
||||
|
||||
# Parse scopes map (if provided) → SCOPE_NAMES + SCOPE_DIRS
|
||||
SCOPE_NAMES=()
|
||||
declare -A SCOPE_DIRS=()
|
||||
SCOPED_DIRS=""
|
||||
if [ -n "${SCOPES_INPUT//[[:space:]]/}" ]; then
|
||||
mapfile -t SCOPE_NAMES < <(printf '%s' "$SCOPES_INPUT" | yq 'keys | .[]')
|
||||
for s in "${SCOPE_NAMES[@]}"; do
|
||||
raw=$(printf '%s' "$SCOPES_INPUT" | yq ".\"$s\"")
|
||||
[ "$raw" = "null" ] && raw=""
|
||||
clean=$(printf '%s\n' "$raw" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | awk 'NF')
|
||||
SCOPE_DIRS["$s"]="$clean"
|
||||
SCOPED_DIRS=$(printf '%s\n%s' "$SCOPED_DIRS" "$clean")
|
||||
done
|
||||
fi
|
||||
SCOPED_DIRS=$(printf '%s\n' "$SCOPED_DIRS" | awk 'NF' | sort -u)
|
||||
|
||||
# Catch-all dirs from fastlane-changelog-dirs receive all commits unfiltered.
|
||||
# A dir present in both inputs is treated as a catch-all.
|
||||
CATCHALL_DIRS=$(printf '%s\n' "$OUT_DIRS" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | awk 'NF' | sort -u)
|
||||
ALL_DIRS=$(printf '%s\n%s\n' "$SCOPED_DIRS" "$CATCHALL_DIRS" | awk 'NF' | sort -u)
|
||||
|
||||
echo "Catch-all dirs:"
|
||||
[ -n "$CATCHALL_DIRS" ] && printf ' %s\n' $CATCHALL_DIRS || echo " (none)"
|
||||
echo "Scope-filtered dirs:"
|
||||
if [ ${#SCOPE_NAMES[@]} -gt 0 ]; then
|
||||
for s in "${SCOPE_NAMES[@]}"; do
|
||||
echo " scope '$s':"
|
||||
printf ' %s\n' ${SCOPE_DIRS[$s]}
|
||||
done
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
|
||||
format_notes() {
|
||||
local input="$1"
|
||||
local out
|
||||
out=$(printf '%s\n' "$input" \
|
||||
| sed -E 's/ *\(\[[0-9a-f]+\]\([^)]+\)\)//g' \
|
||||
| sed -E 's/^\* \*\*[^*]+:\*\* */- /; s/^\* /- /' \
|
||||
| sed 's/^### //' \
|
||||
| sed '/^[[:space:]]*$/d')
|
||||
# strip leading + trailing blank lines
|
||||
out=$(printf '%s' "$out" | sed -e '/./,$!d' -e :a -e '/^\n*$/{$d;N;ba;}')
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
truncate_notes() {
|
||||
local notes="$1"
|
||||
if [ ${#notes} -gt "$MAX_LENGTH" ]; then
|
||||
local budget=$((MAX_LENGTH - ${#TRAILER}))
|
||||
notes="${notes:0:$budget}"
|
||||
notes=$(printf '%s' "$notes" | sed '$d')
|
||||
notes="${notes}${TRAILER}"
|
||||
fi
|
||||
printf '%s' "$notes"
|
||||
}
|
||||
|
||||
# Write per-directory
|
||||
while IFS= read -r dir; do
|
||||
[ -z "$dir" ] && continue
|
||||
|
||||
is_catchall=0
|
||||
if printf '%s\n' "$CATCHALL_DIRS" | grep -Fxq "$dir"; then
|
||||
is_catchall=1
|
||||
fi
|
||||
|
||||
exclude_alt=""
|
||||
if [ "$is_catchall" -eq 0 ] && [ ${#SCOPE_NAMES[@]} -gt 0 ]; then
|
||||
for s in "${SCOPE_NAMES[@]}"; do
|
||||
if ! printf '%s\n' "${SCOPE_DIRS[$s]}" | grep -Fxq "$dir"; then
|
||||
if [ -z "$exclude_alt" ]; then
|
||||
exclude_alt="$s"
|
||||
else
|
||||
exclude_alt="$exclude_alt|$s"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
filtered="$RAW_NOTES"
|
||||
if [ -n "$exclude_alt" ]; then
|
||||
filtered=$(printf '%s\n' "$RAW_NOTES" | grep -vE "^\* \*\*($exclude_alt)[^*]*:\*\*" || true)
|
||||
fi
|
||||
|
||||
notes=$(format_notes "$filtered")
|
||||
[ -z "$notes" ] && notes="Release $VERSION"
|
||||
notes=$(truncate_notes "$notes")
|
||||
|
||||
mkdir -p "$dir"
|
||||
printf '%s\n' "$notes" > "$dir/$CODE.txt"
|
||||
if [ "$is_catchall" -eq 1 ]; then
|
||||
echo "Wrote $dir/$CODE.txt (${#notes} chars, catch-all)"
|
||||
else
|
||||
echo "Wrote $dir/$CODE.txt (${#notes} chars, excluded scopes: ${exclude_alt:-none})"
|
||||
fi
|
||||
done <<< "$ALL_DIRS"
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add .
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changelog changes."
|
||||
else
|
||||
git commit --amend --no-edit
|
||||
git push --force-with-lease
|
||||
fi
|
||||
15
.prettierrc
Normal file
15
.prettierrc
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.md",
|
||||
"options": {
|
||||
"printWidth": 100,
|
||||
"proseWrap": "always"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright © 2026 Chen Asraf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
49
Makefile
Normal file
49
Makefile
Normal file
@@ -0,0 +1,49 @@
|
||||
.PHONY: tag help
|
||||
|
||||
help:
|
||||
@echo "Usage: make tag [TAG=<name>] [VERSION=<number>]"
|
||||
@echo ""
|
||||
@echo " TAG - Tag prefix name (e.g., 'go-release', 'nextcloud')"
|
||||
@echo " Can also be set via TAG env var"
|
||||
@echo " VERSION - Version number (optional, auto-increments if omitted)"
|
||||
@echo ""
|
||||
@echo "Examples:"
|
||||
@echo " make tag TAG=go-release"
|
||||
@echo " make tag TAG=go-release VERSION=3"
|
||||
@echo " TAG=nextcloud make tag"
|
||||
|
||||
tag:
|
||||
ifndef TAG
|
||||
@read -p "Enter tag name: " tag_input; \
|
||||
if [ -z "$$tag_input" ]; then \
|
||||
echo "Error: TAG is required"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
$(MAKE) tag TAG=$$tag_input $(if $(VERSION),VERSION=$(VERSION),)
|
||||
else
|
||||
@# Auto-detect version if not provided
|
||||
$(eval _detected_version := $(shell \
|
||||
latest=$$(git tag --list '$(TAG)-v*' | sed 's/$(TAG)-v//' | sort -n | tail -1); \
|
||||
if [ -z "$$latest" ]; then echo 1; else echo $$((latest + 1)); fi \
|
||||
))
|
||||
$(eval VERSION := $(or $(VERSION),$(_detected_version)))
|
||||
@echo "Tagging with:"
|
||||
@echo " Tag version: $(TAG)-v$(VERSION)"
|
||||
@echo " Latest tag: $(TAG)-latest"
|
||||
@echo ""
|
||||
@# Create tag-specific version
|
||||
git tag -f $(TAG)-v$(VERSION)
|
||||
@# Remove old latest tag and re-create
|
||||
-git tag -d $(TAG)-latest 2>/dev/null || true
|
||||
git tag $(TAG)-latest
|
||||
@echo ""
|
||||
@echo "Tags created successfully!"
|
||||
@read -p "Push tags to remote? [Y/n] " answer; \
|
||||
answer=$${answer:-y}; \
|
||||
if echo "$$answer" | grep -iq "^y"; then \
|
||||
echo "Pushing tags to remote..."; \
|
||||
git push origin $(TAG)-v$(VERSION) $(TAG)-latest --force; \
|
||||
else \
|
||||
echo "To push tags later, run: git push origin $(TAG)-v$(VERSION) $(TAG)-latest --force"; \
|
||||
fi
|
||||
endif
|
||||
471
README.md
Normal file
471
README.md
Normal file
@@ -0,0 +1,471 @@
|
||||
# Reusable GitHub Workflows
|
||||
|
||||
A collection of reusable GitHub Actions workflows.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Workflows](#workflows)
|
||||
- [Go Release](#go-release-go-releaseyml)
|
||||
- [Manual Homebrew Release](#manual-homebrew-release-manual-homebrew-releaseyml)
|
||||
- [Release Please + Fastlane Changelog](#release-please--fastlane-changelog-release-please-fastlane-changelogyml)
|
||||
- [Nextcloud Workflows](#nextcloud-workflows)
|
||||
- [PHPUnit MySQL](#phpunit-mysql-nextcloud-phpunit-mysqlyml)
|
||||
- [PHPUnit PostgreSQL](#phpunit-postgresql-nextcloud-phpunit-pgsqlyml)
|
||||
- [PHPUnit Incremental Migration](#phpunit-incremental-migration-nextcloud-phpunit-incrementalyml)
|
||||
- [Psalm Static Analysis](#psalm-static-analysis-nextcloud-psalmyml)
|
||||
- [PHP Lint](#php-lint-nextcloud-lint-phpyml)
|
||||
- [PHP-CS-Fixer](#php-cs-fixer-nextcloud-lint-php-csyml)
|
||||
- [ESLint](#eslint-nextcloud-lint-eslintyml)
|
||||
- [OpenAPI Lint](#openapi-lint-nextcloud-lint-openapiyml)
|
||||
- [AppInfo XML Lint](#appinfo-xml-lint-nextcloud-lint-appinfo-xmlyml)
|
||||
- [NPM Build](#npm-build-nextcloud-build-npmyml)
|
||||
- [Vitest](#vitest-nextcloud-vitestyml)
|
||||
- [Block Unconventional Commits](#block-unconventional-commits-nextcloud-block-unconventional-commitsyml)
|
||||
- [License](#license)
|
||||
|
||||
## Workflows
|
||||
|
||||
### Go Release (`go-release.yml`)
|
||||
|
||||
A complete CI/CD workflow for Go projects that handles testing, cross-platform builds, releases, and
|
||||
Homebrew tap updates.
|
||||
|
||||
#### Features
|
||||
|
||||
- Runs tests with configurable test command
|
||||
- Cross-platform builds (Linux, macOS, Windows)
|
||||
- Automated releases via [release-please](https://github.com/googleapis/release-please)
|
||||
- Automatic Homebrew tap updates via repository dispatch
|
||||
|
||||
#### Usage
|
||||
|
||||
```yaml
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: chenasraf/workflows/.github/workflows/go-release.yml@master
|
||||
with:
|
||||
name: my-cli
|
||||
go-version: '1.24'
|
||||
platforms: '["linux/amd64", "darwin/arm64"]'
|
||||
main-branch: main
|
||||
homebrew-tap-repo: myorg/homebrew-tap
|
||||
secrets:
|
||||
REPO_DISPATCH_PAT: ${{ secrets.REPO_DISPATCH_PAT }}
|
||||
```
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
| ------------------- | ---------------------------------------------------- | -------- | ------------------------------------------------------------------ |
|
||||
| `name` | Binary/project name | Yes | - |
|
||||
| `go-version` | Go version to use | No | `1.24` |
|
||||
| `platforms` | JSON array of platforms to build | No | `["linux/amd64", "darwin/amd64", "darwin/arm64", "windows/amd64"]` |
|
||||
| `package` | Go package path (empty for root) | No | `""` |
|
||||
| `compress` | Compress build artifacts | No | `true` |
|
||||
| `test-command` | Test command to run | No | `go test -v ./...` |
|
||||
| `skip-tests` | Skip running tests | No | `false` |
|
||||
| `main-branch` | Main branch name for releases | No | `master` |
|
||||
| `homebrew-tap-repo` | Homebrew tap repo for dispatch (leave empty to skip) | No | `` |
|
||||
|
||||
#### Secrets
|
||||
|
||||
| Secret | Description | Required |
|
||||
| ------------------- | ---------------------------------------- | -------- |
|
||||
| `REPO_DISPATCH_PAT` | PAT for dispatching to homebrew tap repo | No |
|
||||
|
||||
---
|
||||
|
||||
### Manual Homebrew Release (`manual-homebrew-release.yml`)
|
||||
|
||||
Manually triggers a Homebrew tap update for the latest release. Useful when you need to re-trigger a Homebrew formula update without creating a new release.
|
||||
|
||||
#### Features
|
||||
|
||||
- Fetches the latest release tag and body from the repository
|
||||
- Sends a repository dispatch event to your Homebrew tap repo
|
||||
- Works with any Homebrew tap that listens for `trigger-from-release` events with payload: `{ tag, repo, body }`
|
||||
|
||||
#### Usage
|
||||
|
||||
```yaml
|
||||
name: Manual Homebrew Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
homebrew:
|
||||
uses: chenasraf/workflows/.github/workflows/manual-homebrew-release.yml@master
|
||||
with:
|
||||
homebrew-tap-repo: myorg/homebrew-tap
|
||||
secrets:
|
||||
REPO_DISPATCH_PAT: ${{ secrets.REPO_DISPATCH_PAT }}
|
||||
```
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
| ------------------- | ------------------------------------------------ | -------- | ------- |
|
||||
| `homebrew-tap-repo` | Homebrew tap repo to dispatch to (e.g., owner/homebrew-tap) | Yes | - |
|
||||
|
||||
#### Secrets
|
||||
|
||||
| Secret | Description | Required |
|
||||
| ------------------- | ---------------------------------------- | -------- |
|
||||
| `REPO_DISPATCH_PAT` | PAT for dispatching to homebrew tap repo | Yes |
|
||||
|
||||
---
|
||||
|
||||
### Release Please + Fastlane Changelog (`release-please-fastlane-changelog.yml`)
|
||||
|
||||
Runs [release-please](https://github.com/googleapis/release-please), then when a release PR is
|
||||
created or updated, extracts the changelog for the current version from `CHANGELOG.md`, formats it
|
||||
for the Play Store (stripped of markdown links, commit hashes, etc.), truncates to the 500-char
|
||||
limit, and writes it to one or more fastlane metadata directories. The changelog is amended into
|
||||
release-please's commit so the tagged release includes the file.
|
||||
|
||||
#### Features
|
||||
|
||||
- Runs release-please with configurable release type
|
||||
- Extracts version-specific notes from `CHANGELOG.md`
|
||||
- Strips commit links, reformats bullets, removes markdown headers
|
||||
- Truncates to Play Store's 500-char limit with a configurable trailer
|
||||
- Writes to multiple output directories (e.g. Android + iOS fastlane metadata)
|
||||
- Amends the release-please commit (no extra commits in the PR)
|
||||
- Forwards `release_created`, `tag_name`, and `version` outputs
|
||||
|
||||
#### Usage
|
||||
|
||||
```yaml
|
||||
name: CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
uses: chenasraf/workflows/.github/workflows/release-please-fastlane-changelog.yml@master
|
||||
with:
|
||||
release-type: dart
|
||||
```
|
||||
|
||||
With multiple output directories (Android + iOS):
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
release-please:
|
||||
uses: chenasraf/workflows/.github/workflows/release-please-fastlane-changelog.yml@master
|
||||
with:
|
||||
release-type: dart
|
||||
fastlane-changelog-dirs: |
|
||||
fastlane/metadata/android/en-US/changelogs
|
||||
fastlane/metadata/ios/en-US/changelogs
|
||||
|
||||
build:
|
||||
needs: release-please
|
||||
if: ${{ needs.release-please.outputs.release_created }}
|
||||
# ...
|
||||
```
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
| -------------------------- | ------------------------------------------------------------------ | -------- | ------------------------------------------------ |
|
||||
| `release-type` | Release Please release type (`dart`, `node`, `python`, `go`, etc.) | Yes | - |
|
||||
| `version-file` | File containing the version string | No | `pubspec.yaml` |
|
||||
| `changelog-file` | Path to the CHANGELOG.md file | No | `CHANGELOG.md` |
|
||||
| `fastlane-changelog-dirs` | Newline-separated list of output directories | No | `fastlane/metadata/android/en-US/changelogs` |
|
||||
| `max-length` | Maximum changelog length in characters | No | `500` |
|
||||
| `truncation-trailer` | Text appended when the changelog is truncated | No | `\n\n… see full notes on GitHub.` |
|
||||
|
||||
#### Secrets
|
||||
|
||||
| Secret | Description | Required |
|
||||
| ------- | -------------------------------------------------- | -------- |
|
||||
| `token` | GitHub token for release-please (defaults to `GITHUB_TOKEN`) | No |
|
||||
|
||||
#### Outputs
|
||||
|
||||
| Output | Description |
|
||||
| ----------------- | ---------------------------- |
|
||||
| `release_created` | Whether a release was created |
|
||||
| `tag_name` | The release tag name |
|
||||
| `version` | The release version |
|
||||
|
||||
---
|
||||
|
||||
## Nextcloud Workflows
|
||||
|
||||
Reusable workflows for Nextcloud app development. These workflows include automatic path filtering to skip unnecessary runs when irrelevant files change.
|
||||
|
||||
### PHPUnit MySQL (`nextcloud-phpunit-mysql.yml`)
|
||||
|
||||
Runs PHPUnit tests with MySQL database.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
phpunit:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-phpunit-mysql.yml@nextcloud-latest
|
||||
with:
|
||||
php-versions-min: '8.1'
|
||||
php-versions-max: '8.4'
|
||||
mysql-version: '8.0'
|
||||
path-filters: |
|
||||
- 'lib/**'
|
||||
- 'tests/**'
|
||||
- 'composer.json'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `php-versions-min` | Minimum PHP version | No | `8.2` |
|
||||
| `php-versions-max` | Maximum PHP version | No | `8.3` |
|
||||
| `mysql-version` | MySQL version | No | `8.4` |
|
||||
| `php-extensions` | PHP extensions to install | No | _(common extensions)_ |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | _(lib, tests, etc.)_ |
|
||||
|
||||
### PHPUnit PostgreSQL (`nextcloud-phpunit-pgsql.yml`)
|
||||
|
||||
Runs PHPUnit tests with PostgreSQL database.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
phpunit:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-phpunit-pgsql.yml@nextcloud-latest
|
||||
with:
|
||||
php-version: '8.2'
|
||||
path-filters: |
|
||||
- 'lib/**'
|
||||
- 'tests/**'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `php-version` | PHP version | No | `8.3` |
|
||||
| `php-extensions` | PHP extensions to install | No | _(common extensions)_ |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | _(lib, tests, etc.)_ |
|
||||
|
||||
### PHPUnit Incremental Migration (`nextcloud-phpunit-incremental.yml`)
|
||||
|
||||
Tests database migrations by upgrading from a baseline version.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
incremental:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-phpunit-incremental.yml@nextcloud-latest
|
||||
with:
|
||||
baseline-version: v1.0.0
|
||||
php-version: '8.2'
|
||||
validation-query: 'SELECT COUNT(*) FROM oc_myapp_users'
|
||||
path-filters: |
|
||||
- 'lib/Migration/**'
|
||||
- 'appinfo/info.xml'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `baseline-version` | Git tag/ref to upgrade from | Yes | - |
|
||||
| `php-version` | PHP version | No | `8.3` |
|
||||
| `php-extensions-mysql` | PHP extensions for MySQL tests | No | _(common extensions)_ |
|
||||
| `php-extensions-pgsql` | PHP extensions for PostgreSQL tests | No | _(common extensions)_ |
|
||||
| `validation-query` | SQL query to validate migration | No | _(empty)_ |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | _(lib, tests, etc.)_ |
|
||||
|
||||
### Psalm Static Analysis (`nextcloud-psalm.yml`)
|
||||
|
||||
Runs Psalm static analysis across supported Nextcloud versions.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
psalm:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-psalm.yml@nextcloud-latest
|
||||
with:
|
||||
psalm-command: 'composer run psalm -- --show-info=true'
|
||||
path-filters: |
|
||||
- 'lib/**/*.php'
|
||||
- 'psalm.xml'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `psalm-command` | Command to run Psalm | No | `composer run psalm` |
|
||||
| `php-extensions` | PHP extensions to install | No | _(common extensions)_ |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `**.php`, `psalm.xml` |
|
||||
|
||||
### PHP Lint (`nextcloud-lint-php.yml`)
|
||||
|
||||
Runs PHP syntax linting across supported PHP versions.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
lint:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-lint-php.yml@nextcloud-latest
|
||||
with:
|
||||
lint-command: 'composer run lint -- --colors'
|
||||
path-filters: |
|
||||
- 'lib/**/*.php'
|
||||
- 'appinfo/**/*.php'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `lint-command` | Command to run lint | No | `composer run lint` |
|
||||
| `php-extensions` | PHP extensions to install | No | _(common extensions)_ |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `**.php` |
|
||||
|
||||
### PHP-CS-Fixer (`nextcloud-lint-php-cs.yml`)
|
||||
|
||||
Checks PHP code style with PHP-CS-Fixer.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
cs:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-lint-php-cs.yml@nextcloud-latest
|
||||
with:
|
||||
cs-check-command: 'vendor/bin/php-cs-fixer fix --dry-run --diff'
|
||||
path-filters: |
|
||||
- 'lib/**/*.php'
|
||||
- 'tests/**/*.php'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `cs-check-command` | Command to check code style | No | `composer run cs:check` |
|
||||
| `php-extensions` | PHP extensions to install | No | _(common extensions)_ |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `**.php`, `.php-cs-fixer.dist.php` |
|
||||
|
||||
### ESLint (`nextcloud-lint-eslint.yml`)
|
||||
|
||||
Runs ESLint on frontend code.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
eslint:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-lint-eslint.yml@nextcloud-latest
|
||||
with:
|
||||
lint-command: 'pnpm lint --max-warnings 0'
|
||||
path-filters: |
|
||||
- 'src/**/*.ts'
|
||||
- 'src/**/*.vue'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `lint-command` | Command to run lint | No | `pnpm lint` |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `src/**`, `*.ts`, `*.js`, etc. |
|
||||
|
||||
### OpenAPI Lint (`nextcloud-lint-openapi.yml`)
|
||||
|
||||
Validates OpenAPI spec is up to date.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
openapi:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-lint-openapi.yml@nextcloud-latest
|
||||
with:
|
||||
openapi-command: 'composer run generate-openapi'
|
||||
typescript-types-pattern: 'src/api/types/*.ts'
|
||||
path-filters: |
|
||||
- 'lib/Controller/**/*.php'
|
||||
- 'openapi.json'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `openapi-command` | Command to regenerate OpenAPI | No | `composer run openapi` |
|
||||
| `typescript-types-pattern` | Glob for TypeScript types | No | `src/types/openapi/openapi*.ts` |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `lib/**/*.php`, `openapi.json` |
|
||||
|
||||
### AppInfo XML Lint (`nextcloud-lint-appinfo-xml.yml`)
|
||||
|
||||
Validates `appinfo/info.xml` against schema.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
xml:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-lint-appinfo-xml.yml@nextcloud-latest
|
||||
with:
|
||||
xml-file: './custom/path/info.xml'
|
||||
path-filters: |
|
||||
- 'custom/path/info.xml'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `xml-file` | Path to the info.xml file | No | `./appinfo/info.xml` |
|
||||
| `schema-url` | URL to XML schema | No | _(Nextcloud schema)_ |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `appinfo/info.xml` |
|
||||
|
||||
### NPM Build (`nextcloud-build-npm.yml`)
|
||||
|
||||
Builds frontend assets with pnpm.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-build-npm.yml@nextcloud-latest
|
||||
with:
|
||||
build-command: 'pnpm build:prod'
|
||||
path-filters: |
|
||||
- 'src/**'
|
||||
- 'package.json'
|
||||
- 'pnpm-lock.yaml'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `build-command` | Command to run build | No | `pnpm build` |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `src/**`, `*.json`, etc. |
|
||||
|
||||
### Vitest (`nextcloud-vitest.yml`)
|
||||
|
||||
Runs Vitest frontend tests.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
vitest:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-vitest.yml@nextcloud-latest
|
||||
with:
|
||||
node-version: '20'
|
||||
test-command: 'pnpm vitest run --coverage'
|
||||
path-filters: |
|
||||
- 'src/**'
|
||||
- 'tests/**'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `node-version` | Node.js version to use | No | `22` |
|
||||
| `test-command` | Command to run tests | No | `pnpm test:run` |
|
||||
| `path-filters` | Paths to trigger on (YAML list) | No | `src/**`, `*.ts`, etc. |
|
||||
|
||||
### Block Unconventional Commits (`nextcloud-block-unconventional-commits.yml`)
|
||||
|
||||
Blocks commits that don't follow conventional commit format.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
commits:
|
||||
uses: chenasraf/workflows/.github/workflows/nextcloud-block-unconventional-commits.yml@nextcloud-latest
|
||||
with:
|
||||
allowed-types: 'feat,fix,docs,chore,refactor'
|
||||
```
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `allowed-types` | Comma-separated list of allowed commit types | No | _(feat, fix, docs, etc.)_ |
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user