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

Generate playground previews for theme changes #7719

Merged
merged 1 commit into from
Apr 24, 2024
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
151 changes: 151 additions & 0 deletions .github/scripts/create-preview-links.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
const fs = require('fs');

/*
* This function creates a WordPress Playground blueprint JSON string for a theme.
*
* @param {string} themeSlug - The slug of the theme to create a blueprint for.
* @param {string} branch - The branch where the theme changes are located.
* @returns {string} - A JSON string representing the blueprint.
*/
function createBlueprint(themeSlug, branch) {
const template = {
steps: [
{
step: 'login',
username: 'admin',
password: 'password',
},
{
step: 'installTheme',
themeZipFile: {
resource: 'url',
url: `https://github-proxy.com/proxy.php?action=partial&repo=Automattic/themes&directory=${themeSlug}&branch=${branch}`,
},
},
{
step: 'activateTheme',
themeFolderName: themeSlug,
},
],
};

return JSON.stringify(template);
}

/*
* This function reads the `style.css` file of a theme and returns the theme name.
*
* @param {string} themeSlug - The slug of the theme to get the name of.
* @returns {string} - The name of the theme as defined in the `style.css` file.
*/
function getThemeName(themeSlug) {
const styleCss = fs.readFileSync(`${themeSlug}/style.css`, 'utf8');
const themeName = styleCss.match(/Theme Name:(.*)/i)[1].trim();
return themeName;
}

/*
* This function reads the `style.css` file of a theme and returns the name of the parent theme.
* If the theme is not a child theme, it returns an empty string.
*
* @param {string} themeSlug - The slug of the theme to get the parent theme name of.
* @returns {string} - The name of the parent theme as defined in the `style.css` file.
*/
function getParentThemeName(themeSlug) {
const styleCss = fs.readFileSync(`${themeSlug}/style.css`, 'utf8');
const parentTheme = styleCss.match(/Template:(.*)/i);
const isChildTheme = parentTheme && '' !== parentTheme[1].trim();

if (!isChildTheme) {
return '';
}

return parentTheme && '' !== parentTheme[1].trim()
? parentTheme[1].trim()
: '';
}

/*
* This function creates a comment on a PR with preview links for the changed themes.
* It is used by `preview-theme` workflow.
*
* @param {object} github - An authenticated instance of the GitHub API.
* @param {object} context - The context of the event that triggered the action.
* @param {string} changedThemeSlugs - A space-separated string of theme slugs that have changed.
*/
async function createPreviewLinksComment(github, context, changedThemeSlugs) {
const changedThemes = changedThemeSlugs.split(' ');
const previewLinks = changedThemes
.map((themeSlug) => {
const parentThemeName = getParentThemeName(themeSlug);
const note = parentThemeName
? ` (child theme of **${parentThemeName}**)`
: '';

return `- [Preview changes for **${getThemeName(
themeSlug
)}**](https://playground.wordpress.net/#${createBlueprint(
themeSlug,
context.payload.pull_request.head.ref
)})${note}`;
})
.join('\n');

const includesChildThemes = changedThemes.some(
(themeSlug) => '' !== getParentThemeName(themeSlug)
);

const comment = `
I've detected changes to the following themes in this PR: ${changedThemes
.map((themeSlug) => getThemeName(themeSlug))
.join(', ')}.

You can preview these changes by following the links below:

${previewLinks}

I will update this comment with the latest preview links as you push more changes to this PR.
**⚠️ Note:** The preview sites are created using [WordPress Playground](https://wordpress.org/playground/). You can add content, edit settings, and test the themes as you would on a real site, but please note that changes are not saved between sessions.
vcanales marked this conversation as resolved.
Show resolved Hide resolved
${
includesChildThemes
? '\n**⚠️ Note:** Child themes are dependent on their parent themes. You will have to install the parent theme as well for the preview to work correctly.'
: ''
}
`;

const repoData = {
owner: context.repo.owner,
repo: context.repo.repo,
};

// Check if a comment already exists and update it if it does
const { data: comments } = await github.rest.issues.listComments({
issue_number: context.payload.pull_request.number,
...repoData,
});
const existingComment = comments.find(
(comment) =>
comment.user.login === 'github-actions[bot]' &&
comment.body.startsWith('### Preview changes')
);
const commentObject = {
body: `### Preview changes\n${comment}`,
...repoData,
};

if (existingComment) {
await github.rest.issues.updateComment({
comment_id: existingComment.id,
...commentObject,
});
return;
}

// Create a new comment if one doesn't exist
github.rest.issues.createComment({
issue_number: context.payload.pull_request.number,
...commentObject,
});
}

module.exports = createPreviewLinksComment;
75 changes: 75 additions & 0 deletions .github/workflows/preview-theme.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Preview Theme Changes

on:
pull_request:

jobs:
check-for-changes-to-themes:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Retrieved Theme Changes
id: check-for-changes
run: |
# Retrieve list of all changed files
git fetch origin trunk:trunk
changed_files=$(git diff --name-only HEAD origin/trunk)

# Loop through changed files and identify parent directories
declare -A unique_dirs
for file in $changed_files; do
dir_name=$(dirname "$file")
while [[ "$dir_name" != "." ]]; do
if [[ -f "$dir_name/style.css" ]]; then # Check if the parent directory contains a theme
# Save only the basename
unique_dirs[$dir_name]=$(basename $dir_name)
break
fi
dir_name=$(dirname "$dir_name")
done
done
# Check if themes have changed
if [[ ${#unique_dirs[@]} -eq 0 ]]; then
echo "No theme changes detected"
echo "HAS_THEME_CHANGES=false" >> $GITHUB_OUTPUT
exit 0
fi
# Output list of theme slugs with changes
echo "HAS_THEME_CHANGES=true" >> $GITHUB_OUTPUT
echo "CHANGED_THEMES=$(echo ${unique_dirs[@]})" >> $GITHUB_ENV
echo "Theme directories with changes: $CHANGED_THEMES"

- name: Add Preview Links comment
id: comment-on-pr
if: ${{ steps.check-for-changes.outputs.HAS_THEME_CHANGES == 'true' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const createPreviewLinks = require('.github/scripts/create-preview-links');
createPreviewLinks(github, context, process.env.CHANGED_THEMES);

- name: Remove comment if no changes are detected
if: ${{ steps.check-for-changes.outputs.HAS_THEME_CHANGES == 'false' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: comments } = await github.rest.issues.listComments({
issue_number: context.payload.pull_request.number,
owner: context.repo.owner,
repo: context.repo.repo
});

const existingComment = comments.find(comment => comment.user.login === 'github-actions[bot]' && comment.body.startsWith('### Preview changes'));

if (existingComment) {
await github.rest.issues.deleteComment({
comment_id: existingComment.id,
owner: context.repo.owner,
repo: context.repo.repo
});
}

Loading