Skip to content

Commit fcba46a

Browse files
author
Tarun Vijwani
authored
Merge pull request #56 from woocommerce/add/update-milestone-after-release
Release process: automatically set milestone date after a successful release
2 parents 8a42f29 + 2aecb2c commit fcba46a

File tree

10 files changed

+476
-0
lines changed

10 files changed

+476
-0
lines changed

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ inputs:
2020
'major' - Assign to the next major version.
2121
required: false
2222
default: minor
23+
target_milestone:
24+
description: |
25+
Title of the milestone that will be updated.
26+
required: false
27+
default: ''
2328
runs:
2429
using: 'node12'
2530
main: 'dist/index.js'

dist/index.js

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module.exports = [
2424
__webpack_require__( 2994 ),
2525
__webpack_require__( 7866 ),
2626
__webpack_require__( 8224 ),
27+
__webpack_require__( 3707 ),
2728
];
2829

2930

@@ -2512,6 +2513,209 @@ module.exports = async ( { context, octokit, config = {}, issue }, data ) => {
25122513
};
25132514

25142515

2516+
/***/ }),
2517+
2518+
/***/ 8927:
2519+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2520+
2521+
/**
2522+
* External dependencies
2523+
*/
2524+
const { setFailed, getInput: coreGetInput } = __webpack_require__( 2186 );
2525+
2526+
const inputs = {
2527+
targetMilestone: {
2528+
input: 'target_milestone',
2529+
default: '',
2530+
required: false,
2531+
},
2532+
};
2533+
2534+
const getInput = ( input ) => {
2535+
const value = coreGetInput( input.input ) || input.default;
2536+
if ( input.required && ! value ) {
2537+
throw new Error(
2538+
`Update Milestone: Missing required input ${ input.input } your input: ${ input }`
2539+
);
2540+
}
2541+
2542+
return value;
2543+
};
2544+
2545+
module.exports = async () => {
2546+
try {
2547+
return {
2548+
targetMilestone: getInput( inputs.targetMilestone ),
2549+
};
2550+
} catch ( error ) {
2551+
setFailed( `Update Milestone: Target milestone: ${ error }` );
2552+
}
2553+
};
2554+
2555+
2556+
/***/ }),
2557+
2558+
/***/ 3707:
2559+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2560+
2561+
const runner = __webpack_require__( 9561 );
2562+
const getConfig = __webpack_require__( 8927 );
2563+
2564+
module.exports = {
2565+
name: 'update-milestone',
2566+
events: [ 'release' ],
2567+
runner,
2568+
getConfig,
2569+
};
2570+
2571+
2572+
/***/ }),
2573+
2574+
/***/ 9561:
2575+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2576+
2577+
/**
2578+
* External dependencies
2579+
*/
2580+
const { setFailed } = __webpack_require__( 2186 );
2581+
2582+
/**
2583+
* Internal dependencies
2584+
*/
2585+
const debug = __webpack_require__( 5800 );
2586+
const updateMilestoneHandler = __webpack_require__( 8223 );
2587+
2588+
/**
2589+
* @typedef {import('@actions/github').GitHub} GitHub
2590+
* @typedef {import('@actions/github').context} GitHubContext
2591+
* @typedef {import('../../typedefs').AutomationTaskRunner} AutomationTaskRunner
2592+
*/
2593+
2594+
const runnerMatrix = {
2595+
release: {
2596+
published: updateMilestoneHandler,
2597+
},
2598+
};
2599+
2600+
/**
2601+
* The task runner for this action
2602+
*
2603+
* @param {string} eventName The event we want the runner for.
2604+
* @param {string} [action] The action we want the runner for.
2605+
*
2606+
* @return {AutomationTaskRunner} A runner function.
2607+
*/
2608+
const getRunnerTask = ( eventName, action ) => {
2609+
if (
2610+
! runnerMatrix[ eventName ] ||
2611+
action === undefined ||
2612+
! runnerMatrix[ eventName ][ action ]
2613+
) {
2614+
return;
2615+
}
2616+
return runnerMatrix[ eventName ][ action ];
2617+
};
2618+
2619+
/**
2620+
* The task runner for this action to update the milestone
2621+
*
2622+
* @param {GitHubContext} context Context for the job run (github).
2623+
* @param {GitHub} octokit GitHub api helper.
2624+
* @param {Object} config Config object.
2625+
*
2626+
* @return {AutomationTaskRunner} task runner.
2627+
*/
2628+
const runner = async ( context, octokit, config ) => {
2629+
const task = getRunnerTask( context.eventName, context.payload.action );
2630+
if ( typeof task === 'function' ) {
2631+
debug( `Update Milestone: Executing the ${ task.name } task.` );
2632+
await task( context, octokit, config );
2633+
} else {
2634+
setFailed(
2635+
`Update Milestone: There is no configured task for the event = '${ context.eventName }' and the payload action = '${ context.payload.action }'`
2636+
);
2637+
}
2638+
};
2639+
2640+
module.exports = runner;
2641+
2642+
2643+
/***/ }),
2644+
2645+
/***/ 8223:
2646+
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2647+
2648+
/**
2649+
* Internal dependencies
2650+
*/
2651+
const debug = __webpack_require__( 5800 );
2652+
const { getMilestoneByTitle } = __webpack_require__( 1606 );
2653+
2654+
/**
2655+
* @typedef {import('../../typedefs').GitHubContext} GitHubContext
2656+
* @typedef {import('../../typedefs').GitHub} GitHub
2657+
*/
2658+
2659+
/**
2660+
* @param {GitHubContext} context
2661+
* @param {GitHub} octokit
2662+
* @param {Object} config
2663+
*/
2664+
module.exports = async ( context, octokit, config ) => {
2665+
const targetMilestone = await getMilestoneByTitle(
2666+
context,
2667+
octokit,
2668+
config.targetMilestone,
2669+
'closed'
2670+
);
2671+
2672+
if ( ! targetMilestone ) {
2673+
debug(
2674+
`Update Milestone: Could not find the target milestone: ${ config.targetMilestone }`
2675+
);
2676+
return;
2677+
}
2678+
debug(
2679+
`Update Milestone: Found the target milestone: ${ config.targetMilestone }`
2680+
);
2681+
2682+
if ( targetMilestone.due_on !== null ) {
2683+
debug(
2684+
`Update Milestone: Target milestone: ${ config.targetMilestone } already have a due date.`
2685+
);
2686+
return;
2687+
}
2688+
2689+
const updateDueDate = ( milestoneNumber, dueDate ) => {
2690+
return octokit.issues.updateMilestone( {
2691+
owner: context.repo.owner,
2692+
repo: context.repo.repo,
2693+
milestone_number: milestoneNumber,
2694+
due_on: dueDate,
2695+
} );
2696+
};
2697+
2698+
const date = new Date();
2699+
const dueDate = date.toISOString();
2700+
2701+
const milestoneUpdate = await updateDueDate(
2702+
targetMilestone.number,
2703+
dueDate
2704+
);
2705+
2706+
if ( ! milestoneUpdate ) {
2707+
debug(
2708+
`Update Milestone: Could not update the due date of the milestone: ${ config.targetMilestone }`
2709+
);
2710+
return;
2711+
}
2712+
2713+
debug(
2714+
`Update Milestone: Milstone ${ config.targetMilestone } successfully updated with the ${ dueDate } due date.`
2715+
);
2716+
};
2717+
2718+
25152719
/***/ }),
25162720

25172721
/***/ 5800:

lib/automations.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ module.exports = [
99
require( './automations/todos' ),
1010
require( './automations/release' ),
1111
require( './automations/assign-milestone' ),
12+
require( './automations/update-milestone' ),
1213
];
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
## Update Milestone Automation
2+
3+
When a release is completed, this automation will update the due date of its milestone to current date.
4+
5+
## Usage
6+
7+
To implement this action, include it in your workflow configuration file:
8+
9+
```yaml
10+
on:
11+
release:
12+
types: [published]
13+
jobs:
14+
tag:
15+
name: New Release
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v3
20+
- name: 'Get Previous tag'
21+
id: previoustag
22+
uses: "WyriHaximus/github-action-get-previous-tag@v1"
23+
- name: Set milestone due date
24+
uses: woocommerce/automations@v1
25+
with:
26+
github_token: ${{ secrets.GITHUB_TOKEN }}
27+
automations: update-milestone
28+
target_milestone: ${{ steps.previoustag.outputs.tag }}
29+
```
30+
31+
## API
32+
33+
### Inputs
34+
35+
- `github_token`: Required. GitHub API token to use for making API requests. You can use the default `secrets.GITHUB_TOKEN` used by GitHub actions or store a different one in the secrets configuration of your GitHub repository.
36+
- `automations`: Optional. You can include a comma-delimited list of specific automations you want to run if you don't want to use them all in a given workflow.
37+
- `target_milestone`: Optional. For the update-milestone workflow, this controls which milestone due date needs to be updated.
38+
39+
### Outputs
40+
41+
_None._
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* External dependencies
3+
*/
4+
const { setFailed, getInput: coreGetInput } = require( '@actions/core' );
5+
6+
const inputs = {
7+
targetMilestone: {
8+
input: 'target_milestone',
9+
default: '',
10+
required: false,
11+
},
12+
};
13+
14+
const getInput = ( input ) => {
15+
const value = coreGetInput( input.input ) || input.default;
16+
if ( input.required && ! value ) {
17+
throw new Error(
18+
`Update Milestone: Missing required input ${ input.input }`
19+
);
20+
}
21+
22+
return value;
23+
};
24+
25+
module.exports = async () => {
26+
try {
27+
return {
28+
targetMilestone: getInput( inputs.targetMilestone ),
29+
};
30+
} catch ( error ) {
31+
setFailed( `Update Milestone: Target milestone: ${ error }` );
32+
}
33+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const runner = require( './runner' );
2+
const getConfig = require( './get-config' );
3+
4+
module.exports = {
5+
name: 'update-milestone',
6+
events: [ 'release' ],
7+
runner,
8+
getConfig,
9+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* External dependencies
3+
*/
4+
const { setFailed } = require( '@actions/core' );
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
const debug = require( '../../debug' );
10+
const updateMilestoneHandler = require( './update-milestone-handler' );
11+
12+
/**
13+
* @typedef {import('@actions/github').GitHub} GitHub
14+
* @typedef {import('@actions/github').context} GitHubContext
15+
* @typedef {import('../../typedefs').AutomationTaskRunner} AutomationTaskRunner
16+
*/
17+
18+
const runnerMatrix = {
19+
release: {
20+
published: updateMilestoneHandler,
21+
},
22+
};
23+
24+
/**
25+
* The task runner for this action
26+
*
27+
* @param {string} eventName The event we want the runner for.
28+
* @param {string} [action] The action we want the runner for.
29+
*
30+
* @return {AutomationTaskRunner} A runner function.
31+
*/
32+
const getRunnerTask = ( eventName, action ) => {
33+
if (
34+
! runnerMatrix[ eventName ] ||
35+
action === undefined ||
36+
! runnerMatrix[ eventName ][ action ]
37+
) {
38+
return;
39+
}
40+
return runnerMatrix[ eventName ][ action ];
41+
};
42+
43+
/**
44+
* The task runner for this action to update the milestone
45+
*
46+
* @param {GitHubContext} context Context for the job run (github).
47+
* @param {GitHub} octokit GitHub api helper.
48+
* @param {Object} config Config object.
49+
*
50+
* @return {AutomationTaskRunner} task runner.
51+
*/
52+
const runner = async ( context, octokit, config ) => {
53+
const task = getRunnerTask( context.eventName, context.payload.action );
54+
if ( typeof task === 'function' ) {
55+
debug( `Update Milestone: Executing the ${ task.name } task.` );
56+
await task( context, octokit, config );
57+
} else {
58+
setFailed(
59+
`Update Milestone: There is no configured task for the event = '${ context.eventName }' and the payload action = '${ context.payload.action }'`
60+
);
61+
}
62+
};
63+
64+
module.exports = runner;

0 commit comments

Comments
 (0)