Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare release #2

Merged
merged 1 commit into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
name: Publish Release
run-name: Publish Release

on:
workflow_dispatch:
inputs:
release:
description: 'Release version (e.g. 1.2.3)'
required: true
prerelease:
description: 'Pre-release version (e.g. RC1, beta, etc...)'
required: false

permissions:
contents: write

env:
TAG: ${{ github.event.inputs.release }}
PRETAG: ${{ github.event.inputs.prerelease }}
BRANCH: temp-release-${{ github.event.inputs.release }}

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Prepare vars
id: vars
uses: actions/github-script@v7
with:
script: |
const full_tag = [
process.env.TAG,
process.env.PRETAG
].filter(Boolean).join('-');
const branch = `temp-release-${full_tag}`;
const is_prerelease = !!process.env.PRETAG;

core.setOutput('full_tag', full_tag );
core.setOutput('branch', branch );
core.setOutput('is_prerelease', is_prerelease );

# 'ref' and 'repository' are required, otherwise repo could appear in detached head state
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
repository: ${{ github.repository }}

- name: Parse Changelog Entries
uses: actions/github-script@v7
id: changelog
with:
script: |
const { open } = require('fs/promises');

const version = process.env.TAG;
const delimiter = '#### ';
const file = await open('./changes.md');

let description = [];
let found = false;

for await (let line of file.readLines()) {
line = line.trim();

if ( line.startsWith(`${delimiter}${version}`) ) {
found = true;
continue;
}

if (!found) continue;
if ( line.startsWith(delimiter) ) break;

description.push(line);
}

if ( !description.length ) core.setFailed(`Release ${version} not found in the changelog!`);

core.setOutput('description', description.join('\n') );


# cleanup files that are not needed for the release
# but keep the .git folder, because we need it for the next step
- name: Cleanup files
run: |
rm -f composer.lock || true
rm -rf tests || true
rm -rf vendor/bin || true
rm -rf vendor/composer/installers || true
find ./ -name '.git*' -not -path './.git' -type f -delete || true
find ./ -name '.git*' -not -path './.git' -type d -exec rm -rf {} \; || true
find ./vendor -name .svn -exec rm -rf {} \; || true

# cleanup files, specific to Google API PHP library
- name: Cleanup files for Google API library
run: |
rm -f lib/Google/phpstan.neon.dist || true
rm -f lib/Google/vendor/paragonie/random_compat/build-phar.sh || true
find ./lib/Google/ -name '.repo-metadata.json' -type f -delete || true
find ./lib/Google/vendor -name .svn -exec rm -rf '{}' \; || true

# commit changes to temporary release branch and create a new tag
- name: Commit changes
uses: EndBug/add-and-commit@v9
with:
message: Cleanup files for release
new_branch: ${{ steps.vars.outputs.branch }}
tag: ${{ steps.vars.outputs.full_tag }}

# generate SBOM that will be attached to a release as an artifact
- name: Create SBOM
id: sbom
uses: anchore/sbom-action@v0
with:
path: .
output-file: sbom.spdx.json
format: spdx-json

# create a draft release with the version changelog as a description
- name: Create Draft Release
id: draft_release
uses: softprops/action-gh-release@v2
with:
name: "Release ${{ steps.vars.outputs.full_tag }}"
body: "${{ steps.changelog.outputs.description }}"
tag_name: ${{ steps.vars.outputs.full_tag }}
draft: true
prerelease: ${{ steps.vars.outputs.is_prerelease }}

# attach SBOM to release
- name: Upload SBOM to release
uses: actions/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.draft_release.outputs.upload_url }}
asset_path: ./sbom.spdx.json
asset_name: sbom.spdx.json
asset_content_type: application/json

# publish release using an ID from the 'draft_release' step
- name: Publish Release
uses: eregon/publish-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
release_id: ${{ steps.draft_release.outputs.id }}

# delete temporary release branch
- name: Delete temporary release branch
run: |
git push origin --delete ${{ steps.vars.outputs.branch }}
2 changes: 0 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ name: Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Provides compatibility between the [Simple Local Avatars](https://wordpress.org/

### Notes

* Tested with Simple Local Avatars version 2.7.5
* Tested with Simple Local Avatars version 2.8.3

### Support, Feedback, & Contribute

Expand Down
23 changes: 23 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Security Policy Overview

Thank you for using and contributing to our product. At [UDX](https://udx.io), we take the security of our products seriously and appreciate collaborative efforts to ensure the safety of our users and contributors.

## Reporting a Security Vulnerability

**Please do not report security vulnerabilities through public GitHub issues.**

If you find a security vulnerability, please [submit a vulnerability report](https://github.com/udx/wp-stateless-simple-local-avatars-addon/security/advisories/new). Provide detailed information about the vulnerability to help us understand and address the issue promptly. We kindly request that you avoid public disclosure until we've had the opportunity to analyze and resolve the reported issue.

## Responsible Disclosure

Responsible disclosure is crucial to maintaining the security of our product. We ask for your cooperation in allowing us sufficient time to investigate and address the reported vulnerability before making it public. We will keep you informed of our progress and make every effort to address the issue promptly.

## Supported Versions

Security updates are provided for the latest stable release. Please ensure that you are using a supported version before reporting a security vulnerability.

## Contact Information

For security-related matters, please contact our security team at [[email protected]](mailto:[email protected]). For general inquiries, feature requests, and other non-security-related discussions, please use our regular [issue tracker](https://github.com/udx/wp-stateless-simple-local-avatars-addon-addon/issues).

Thank you for helping us ensure the security of WP-Stateless - Simple Local Avatars Addon. Your contributions are greatly appreciated.
49 changes: 46 additions & 3 deletions class-simple-local-avatars.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<?php

namespace WPSL\SimpleLocalAvatars;
namespace SLCA\SimpleLocalAvatars;

use wpCloud\StatelessMedia\Compatibility;

class SimpleLocalAvatars extends Compatibility {
const META_KEY = 'simple_local_avatar';

protected $id = 'simple-local-avatars';
protected $title = 'Simple Local Avatars';
protected $constant = 'WP_STATELESS_COMPATIBILITY_SLA';
Expand All @@ -17,8 +19,10 @@ class SimpleLocalAvatars extends Compatibility {
* @param $sm
*/
public function module_init($sm) {
add_action( 'updated_user_meta', array($this, 'updated_user_meta'), 10, 4 );

// Only makes sense in CDN or Ephemeral modes
if (in_array($sm['mode'], ['cdn', 'ephemeral', 'stateless'])) {
if ( ud_get_stateless_media()->is_mode(['cdn', 'ephemeral', 'stateless']) ) {
add_filter('get_user_metadata', array($this, 'get_user_metadata'), 10, 4);
}
}
Expand All @@ -34,7 +38,7 @@ public function module_init($sm) {
*/
public function get_user_metadata($null, $object_id, $meta_key, $_) {
// Get out if not the meta we are interested in
if ($meta_key !== 'simple_local_avatar') return $null;
if ($meta_key !== self::META_KEY) return $null;

// Remove THIS filter to avoid the infinite recursion
remove_filter('get_user_metadata', array($this, 'get_user_metadata'), 10);
Expand Down Expand Up @@ -62,4 +66,43 @@ public function get_user_metadata($null, $object_id, $meta_key, $_) {
// Return filtered data back
return $user_meta;
}

/**
* Sync avatar files to GCS after meta update to make sure they are available on GCS
*
* @param $user_id
*/
public function updated_user_meta($meta_id, $object_id, $meta_key, $_meta_value) {
if ( $meta_key !== self::META_KEY || !is_array($_meta_value) ) {
return;
}

$upload_dir = wp_upload_dir();
$gsc_host = ud_get_stateless_media()->get_gs_host();
$gsc_path = ud_get_stateless_media()->get_gs_path();

$baseurl = ud_get_stateless_media()->is_mode('stateless') ? $gsc_host : $upload_dir['baseurl'];

foreach ( $_meta_value as $key => $value ) {
// Skip non-image value and full size image, which is already synced
if ( strpos($value, $baseurl) !== 0 || $key === 'full' ) {
continue;
}

$name = str_replace($baseurl, '', $value);
$name = ltrim($name, '/');
$absolute_path = ud_get_stateless_media()->is_mode('stateless')
? str_replace($gsc_host, $gsc_path, $value)
: str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $value);

$name = apply_filters('wp_stateless_file_name', $name, true);

do_action('sm:sync::syncFile', $name, $absolute_path, false, [
'use_root' => true,
'name_with_root' => true,
'source' => 'Simple Local Avatars',
'source_version' => defined('SLA_VERSION') ? SLA_VERSION : '',
]);
}
}
}
8 changes: 4 additions & 4 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
=== WP-Stateless - Simple Local Avatars Addon ===
Contributors: usability_dynamics, andypotanin, ideric, maxim.peshkov, planvova, obolgun
Contributors: usability_dynamics, andypotanin, ideric, planvova, obolgun
Donate link: https://udx.io
Tags: avatar, gravatar, user photos, google, google cloud, google cloud storage, cdn, uploads, media, stateless, backup
Tags: simple local avatars, simple local avatars addon extension, google cloud storage, stateless, wp-stateless
License: GPLv2 or later
Requires PHP: 8.0
Requires at least: 5.0
Tested up to: 6.4.1
Tested up to: 6.7.1
Stable tag: 0.0.1

Provides compatibility between the Simple Local Avatars and the WP-Stateless plugins.
Expand All @@ -20,7 +20,7 @@ Provides compatibility between the [Simple Local Avatars](https://wordpress.org/

= Notes =

* Tested with Simple Local Avatars version 2.7.5
* Tested with Simple Local Avatars version 2.8.3

= Support, Feedback, & Contribute =

Expand Down
34 changes: 30 additions & 4 deletions tests/ClassSimpleLocalAvatarsTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace WPSL\SimpleLocalAvatars;
namespace SLCA\SimpleLocalAvatars;

use PHPUnit\Framework\TestCase;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
Expand Down Expand Up @@ -49,19 +49,45 @@ public function tearDown(): void {
public function testShouldInitHooks() {
$simpleLocalAvatars = new SimpleLocalAvatars();

$simpleLocalAvatars->module_init([ 'mode' => 'cdn' ]);
ud_get_stateless_media()->set('sm.mode', 'cdn');
$simpleLocalAvatars->module_init([]);

self::assertNotFalse( has_action('updated_user_meta', [ $simpleLocalAvatars, 'updated_user_meta' ]) );
self::assertNotFalse( has_filter('get_user_metadata', [ $simpleLocalAvatars, 'get_user_metadata' ]) );
}

public function testShouldNotInitHooks() {
public function testShouldInitHooksBackup() {
$simpleLocalAvatars = new SimpleLocalAvatars();

$simpleLocalAvatars->module_init([ 'mode' => 'backup' ]);
ud_get_stateless_media()->set('sm.mode', 'backup');
$simpleLocalAvatars->module_init([]);

self::assertNotFalse( has_action('updated_user_meta', [ $simpleLocalAvatars, 'updated_user_meta' ]) );
self::assertFalse( has_filter('get_user_metadata', [ $simpleLocalAvatars, 'get_user_metadata' ]) );
}

public function testShouldCountHooks() {
$simpleLocalAvatars = new SimpleLocalAvatars();

ud_get_stateless_media()->set('sm.mode', 'cdn');

Functions\expect('add_action')->times(1);
Functions\expect('add_filter')->times(1);

$simpleLocalAvatars->module_init([]);
}

public function testShouldCountHooksBackup() {
$simpleLocalAvatars = new SimpleLocalAvatars();

ud_get_stateless_media()->set('sm.mode', 'backup');

Functions\expect('add_action')->times(1);
Functions\expect('add_filter')->times(0);

$simpleLocalAvatars->module_init([]);
}

public function testShouldGetUserMetadata() {
$simpleLocalAvatars = new SimpleLocalAvatars();

Expand Down
8 changes: 8 additions & 0 deletions tests/prepend.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,13 @@ public function get($key): ?string {
public function get_gs_host(): string {
return self::TEST_GS_HOST;
}

public function is_mode($keys): ?string {
if ( !is_array($keys) ) {
$keys = [$keys];
}

return in_array( $this->options['sm.mode'], $keys );
}
}
}
2 changes: 1 addition & 1 deletion vendor/bin/.phpunit.result.cache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":1,"defects":{"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldGetUserMetadata":3,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotGetUserMetadata":4},"times":{"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldInitHooks":0.105,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotInitHooks":0,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotGetUserMetadata":0,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldGetUserMetadata":0.003}}
{"version":1,"defects":{"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldGetUserMetadata":3,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotGetUserMetadata":4,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldInitHooks":3,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldInitHooksBackup":3,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldCountHooks":4,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldCountHooksBackup":4},"times":{"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldInitHooks":0.105,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotInitHooks":0,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotGetUserMetadata":0,"WPSL\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldGetUserMetadata":0.003,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldInitHooks":0.122,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotInitHooks":0,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldGetUserMetadata":0.002,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldNotGetUserMetadata":0,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldInitHooksBackup":0,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldCountHooks":0.002,"SLCA\\SimpleLocalAvatars\\ClassSimpleLocalAvatarsTest::testShouldCountHooksBackup":0.001}}
4 changes: 2 additions & 2 deletions vendor/composer/installed.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
'name' => 'udx/wp-stateless-simple-local-avatars-addon',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '113cf56d1b6e6de9718de6bb38857572e244eae1',
'reference' => '9617e103bd3e1b16d149ff2054e18aed3f3898b6',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
Expand All @@ -13,7 +13,7 @@
'udx/wp-stateless-simple-local-avatars-addon' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '113cf56d1b6e6de9718de6bb38857572e244eae1',
'reference' => '9617e103bd3e1b16d149ff2054e18aed3f3898b6',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
Expand Down
Loading
Loading