-
Notifications
You must be signed in to change notification settings - Fork 112
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a release creation Github action
- Loading branch information
1 parent
50d7990
commit 90208ec
Showing
5 changed files
with
307 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,52 @@ | ||
name: Deploy to WordPress.org | ||
|
||
on: | ||
release: | ||
types: [published] | ||
pull_request: | ||
types: [closed] | ||
branches: | ||
- trunk | ||
|
||
jobs: | ||
tag: | ||
name: New release | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v2 | ||
- name: WordPress Plugin Deploy | ||
id: deploy | ||
uses: 10up/action-wordpress-plugin-deploy@stable | ||
with: | ||
generate-zip: true | ||
env: | ||
SVN_USERNAME: ${{ secrets.SVN_USERNAME }} | ||
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} | ||
- name: Upload release asset | ||
uses: actions/upload-release-asset@v1 | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
with: | ||
upload_url: ${{ github.event.release.upload_url }} | ||
asset_path: ${{github.workspace}}/${{ github.event.repository.name }}.zip | ||
asset_name: ${{ github.event.repository.name }}.zip | ||
asset_content_type: application/zip | ||
deploy-to-wordpress: | ||
if: > | ||
github.event_name == 'pull_request' && | ||
github.event.pull_request.merged == true && | ||
startsWith(github.event.pull_request.head.ref, 'release/') && | ||
( contains(github.event.pull_request.head.ref, '/major') || contains(github.event.pull_request.head.ref, '/minor') || contains(github.event.pull_request.head.ref, '/patch') ) && | ||
( github.event.pull_request.user.login == 'github-actions[bot]' ) | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Set up Node.js | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 20 | ||
- name: Install node dependencies | ||
run: npm install | ||
|
||
- name: Get New Version | ||
id: get-version | ||
run: echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT | ||
|
||
- name: Create Tag and Release on GitHub | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
run: | | ||
VERSION=v${{ steps.get-version.outputs.VERSION }} | ||
git tag $VERSION | ||
git push origin $VERSION | ||
gh release create $VERSION --generate-notes | ||
- name: Deploy Plugin to WordPress Plugin Directory | ||
uses: 10up/action-wordpress-plugin-deploy@stable | ||
env: | ||
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} | ||
SVN_USERNAME: ${{ secrets.SVN_USERNAME }} | ||
VERSION: ${{ steps.get-version.outputs.VERSION }} | ||
|
||
- name: WordPress.org plugin asset/readme update | ||
uses: 10up/action-wordpress-plugin-asset-update@stable | ||
env: | ||
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} | ||
SVN_USERNAME: ${{ secrets.SVN_USERNAME }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
name: Create new release PR | ||
|
||
on: | ||
workflow_dispatch: | ||
inputs: | ||
release_type: | ||
description: 'Release type' | ||
required: true | ||
type: choice | ||
options: | ||
- major | ||
- minor | ||
- patch | ||
|
||
jobs: | ||
prepare-release: | ||
if: github.event_name == 'workflow_dispatch' | ||
name: Prepare Release PR | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 20 | ||
|
||
- name: Install node dependencies | ||
run: npm install | ||
|
||
- name: Compile Javascript App | ||
run: npm run build | ||
|
||
- name: Create version update branch | ||
id: create-branch | ||
run: | | ||
BRANCH_NAME="release/$(date +%Y-%m-%d)/${{ github.event.inputs.release_type }}-release" | ||
git checkout -b $BRANCH_NAME | ||
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT | ||
- name: Update version and changelog | ||
id: update-version | ||
run: | | ||
npm run update-version | ||
echo "NEW_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT | ||
env: | ||
RELEASE_TYPE: ${{ github.event.inputs.release_type }} | ||
|
||
- name: Commit changes | ||
run: | | ||
git config user.name 'github-actions[bot]' | ||
git config user.email 'github-actions[bot]@users.noreply.github.com' | ||
git add . | ||
git commit -m "Version bump & changelog update" --no-verify | ||
git push --set-upstream origin ${{ steps.create-branch.outputs.BRANCH_NAME }} | ||
- name: Create Pull Request | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
run: | | ||
gh pr create \ | ||
--title "[Automation] New ${{ github.event.inputs.release_type }} Release: ${{ steps.update-version.outputs.NEW_VERSION }}" \ | ||
--base trunk \ | ||
--head ${{ steps.create-branch.outputs.BRANCH_NAME }} \ | ||
--label "Release: ${{ github.event.inputs.release_type }}" \ | ||
--body " | ||
### Release PR 🤖 | ||
This is a release PR for version **${{ steps.update-version.outputs.NEW_VERSION }}**, run by **@${{ github.actor }}**. | ||
It updates the version of the Plugin and adds changes since the last tag to the Changelog file. | ||
Merging this PR will trigger a new release and update the Plugin in the WordPress Plugin Directory." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "theme-check", | ||
"version": "20231220", | ||
"description": "Create a block-based theme", | ||
"author": "The theme check plugin is an easy way to test your theme and make sure it’s up to spec with the latest theme review standards.", | ||
"license": "GPL-2.0-or-later", | ||
"keywords": [ | ||
"WordPress", | ||
"theme" | ||
], | ||
"homepage": "https://wordpress.org/plugins/theme-check/", | ||
"repository": "git+https://github.com/WordPress/theme-check.git", | ||
"bugs": { | ||
"url": "https://wordpress.org/support/plugin/theme-check/" | ||
}, | ||
"engines": { | ||
"node": ">=20.10.0", | ||
"npm": ">=10.2.3" | ||
}, | ||
"scripts": { | ||
"update-version": "node update-version-and-changelog.js" | ||
}, | ||
"devDependencies": { | ||
"simple-git": "^3.26.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
/* eslint-disable no-console */ | ||
|
||
/** | ||
* External dependencies | ||
*/ | ||
const fs = require( 'fs' ); | ||
const core = require( '@actions/core' ); | ||
const simpleGit = require( 'simple-git' ); | ||
const { promisify } = require( 'util' ); | ||
const exec = promisify( require( 'child_process' ).exec ); | ||
|
||
const git = simpleGit.default(); | ||
|
||
const releaseType = process.env.RELEASE_TYPE; | ||
|
||
// Constants | ||
const VALID_RELEASE_TYPES = [ 'major', 'minor', 'patch' ]; | ||
const MAIN_PLUGIN_FILE = 'theme-check.php'; | ||
|
||
// To get the merges since the last (previous) tag | ||
async function getChangesSinceLastTag() { | ||
try { | ||
// Fetch all tags, sorted by creation date | ||
const tagsResult = await git.tags( { | ||
'--sort': '-creatordate', | ||
} ); | ||
const tags = tagsResult.all; | ||
if ( tags.length === 0 ) { | ||
console.error( '❌ Error: No previous tags found.' ); | ||
return null; | ||
} | ||
const previousTag = tags[ 0 ]; // The most recent tag | ||
|
||
// Now get the changes since this tag | ||
const changes = await git.log( [ `${ previousTag }..HEAD` ] ); | ||
return changes; | ||
} catch ( error ) { | ||
throw error; | ||
} | ||
} | ||
|
||
// To know if there are changes since the last tag. | ||
// we are not using getChangesSinceGitTag because it returns the just the merges and not the commits. | ||
// So for example if a hotfix was committed directly to trunk this function will detect it but getChangesSinceGitTag will not. | ||
async function getHasChangesSinceGitTag( tag ) { | ||
const changes = await git.log( [ `HEAD...${ tag }` ] ); | ||
return changes?.all?.length > 0; | ||
} | ||
|
||
async function updateVersion() { | ||
if ( ! VALID_RELEASE_TYPES.includes( releaseType ) ) { | ||
console.error( | ||
'❌ Error: Release type is not valid. Valid release types are: major, minor, patch.' | ||
); | ||
process.exit( 1 ); | ||
} | ||
|
||
if ( | ||
! fs.existsSync( './package.json' ) || | ||
! fs.existsSync( './package-lock.json' ) | ||
) { | ||
console.error( '❌ Error: package.json or lock file not found.' ); | ||
process.exit( 1 ); | ||
} | ||
|
||
if ( ! fs.existsSync( './readme.txt' ) ) { | ||
console.error( '❌ Error: readme.txt file not found.' ); | ||
process.exit( 1 ); | ||
} | ||
|
||
if ( ! fs.existsSync( `./${ MAIN_PLUGIN_FILE }` ) ) { | ||
console.error( `❌ Error: ${ MAIN_PLUGIN_FILE } file not found.` ); | ||
process.exit( 1 ); | ||
} | ||
|
||
// get changes since last tag | ||
let changes = []; | ||
try { | ||
changes = await getChangesSinceLastTag(); | ||
} catch ( error ) { | ||
console.error( | ||
`❌ Error: failed to get changes since last tag: ${ error }` | ||
); | ||
process.exit( 1 ); | ||
} | ||
|
||
const packageJson = require( './package.json' ); | ||
const currentVersion = packageJson.version; | ||
|
||
// version bump package.json and package-lock.json using npm | ||
const { stdout, stderr } = await exec( | ||
`npm version --commit-hooks false --git-tag-version false ${ releaseType }` | ||
); | ||
if ( stderr ) { | ||
console.error( `❌ Error: failed to bump the version."` ); | ||
process.exit( 1 ); | ||
} | ||
|
||
const currentTag = `v${ currentVersion }`; | ||
const newTag = stdout.trim(); | ||
const newVersion = newTag.replace( 'v', '' ); | ||
const hasChangesSinceGitTag = await getHasChangesSinceGitTag( currentTag ); | ||
|
||
// check if there are any changes | ||
if ( ! hasChangesSinceGitTag ) { | ||
console.error( | ||
`❌ No changes since last tag (${ currentTag }). There is nothing new to release.` | ||
); | ||
// revert version update | ||
await exec( | ||
`npm version --commit-hooks false --git-tag-version false ${ currentVersion }` | ||
); | ||
process.exit( 1 ); | ||
} | ||
|
||
console.info( '✅ Package.json version updated', currentTag, '=>', newTag ); | ||
|
||
// update readme.txt version with the new changelog | ||
const readme = fs.readFileSync( './readme.txt', 'utf8' ); | ||
const capitalizeFirstLetter = ( string ) => | ||
string.charAt( 0 ).toUpperCase() + string.slice( 1 ); | ||
|
||
const changelogChanges = changes.all | ||
.map( | ||
( change ) => | ||
`* ${ capitalizeFirstLetter( change.message || change.body ) }` | ||
) | ||
.join( '\n' ); | ||
const newChangelog = `== Changelog ==\n\n= ${ newVersion } =\n${ changelogChanges }`; | ||
let newReadme = readme.replace( '== Changelog ==', newChangelog ); | ||
// update version in readme.txt | ||
newReadme = newReadme.replace( | ||
/Stable tag: (.*)/, | ||
`Stable tag: ${ newVersion }` | ||
); | ||
fs.writeFileSync( './readme.txt', newReadme ); | ||
console.info( '✅ Readme version updated', currentTag, '=>', newTag ); | ||
|
||
// update theme-check.php version | ||
const pluginPhpFile = fs.readFileSync( `./${ MAIN_PLUGIN_FILE }`, 'utf8' ); | ||
const newPluginPhpFile = pluginPhpFile.replace( | ||
/Version: (.*)/, | ||
`Version: ${ newVersion }` | ||
); | ||
fs.writeFileSync( `./${ MAIN_PLUGIN_FILE }`, newPluginPhpFile ); | ||
console.info( | ||
`✅ ${ MAIN_PLUGIN_FILE } file version updated`, | ||
currentTag, | ||
'=>', | ||
newTag | ||
); | ||
|
||
// output data to be used by the next steps of the github action | ||
core.setOutput( 'NEW_VERSION', newVersion ); | ||
core.setOutput( 'NEW_TAG', newTag ); | ||
core.setOutput( 'CHANGELOG', changelogChanges ); | ||
} | ||
|
||
updateVersion(); |