Bladeren bron

Generate playground previews for themes (#7719)

Co-authored-by: Sarah Norris <sarah@sekai.co.uk>
Vicente Canales 1 jaar geleden
bovenliggende
commit
8d3da22b11
2 gewijzigde bestanden met toevoegingen van 226 en 0 verwijderingen
  1. 151 0
      .github/scripts/create-preview-links.js
  2. 75 0
      .github/workflows/preview-theme.yml

+ 151 - 0
.github/scripts/create-preview-links.js

@@ -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.
+${
+	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 - 0
.github/workflows/preview-theme.yml

@@ -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
+              });
+            }
+