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

Comment on deploy checklist when a pull request is CP'd #7802

Merged
merged 10 commits into from
Feb 23, 2022
3 changes: 3 additions & 0 deletions .github/actions/awaitStagingDeploys/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ inputs:
GITHUB_TOKEN:
description: Auth token for New Expensify Github
required: true
TAG:
description: If provided, this action will only wait for a deploy matching this tag.
required: false
runs:
using: 'node12'
main: './index.js'
18 changes: 12 additions & 6 deletions .github/actions/awaitStagingDeploys/awaitStagingDeploys.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const _ = require('underscore');
const ActionUtils = require('../../libs/ActionUtils');
const GitHubUtils = require('../../libs/GithubUtils');
const {promiseDoWhile} = require('../../libs/promiseWhile');

function run() {
const tag = ActionUtils.getStringInput('TAG', {required: false});
let currentStagingDeploys = [];
return promiseDoWhile(
() => !_.isEmpty(currentStagingDeploys),
Expand All @@ -14,20 +16,24 @@ function run() {
repo: GitHubUtils.APP_REPO,
workflow_id: 'platformDeploy.yml',
event: 'push',
branch: tag,
}),

// These have the potential to become active deploys, so we need to wait for them to finish as well
// These have the potential to become active deploys, so we need to wait for them to finish as well (unless we're looking for a specific tag)
// In this context, we'll refer to unresolved preDeploy workflow runs as staging deploys as well
GitHubUtils.octokit.actions.listWorkflowRuns({
!tag && GitHubUtils.octokit.actions.listWorkflowRuns({
owner: GitHubUtils.GITHUB_OWNER,
repo: GitHubUtils.APP_REPO,
workflow_id: 'preDeploy.yml',
}),
])
.then(responses => [
...responses[0].data.workflow_runs,
...responses[1].data.workflow_runs,
])
.then((responses) => {
const workflowRuns = responses[0].data.workflow_runs;
if (!tag) {
workflowRuns.push(...responses[1].data.workflow_runs);
}
return workflowRuns;
})
.then(workflowRuns => currentStagingDeploys = _.filter(workflowRuns, workflowRun => workflowRun.status !== 'completed'))
.then(() => console.log(
_.isEmpty(currentStagingDeploys)
Expand Down
64 changes: 58 additions & 6 deletions .github/actions/awaitStagingDeploys/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ module.exports =
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {

const _ = __nccwpck_require__(3571);
const ActionUtils = __nccwpck_require__(970);
const GitHubUtils = __nccwpck_require__(7999);
const {promiseDoWhile} = __nccwpck_require__(4502);

function run() {
const tag = ActionUtils.getStringInput('TAG', {required: false});
let currentStagingDeploys = [];
return promiseDoWhile(
() => !_.isEmpty(currentStagingDeploys),
Expand All @@ -24,20 +26,24 @@ function run() {
repo: GitHubUtils.APP_REPO,
workflow_id: 'platformDeploy.yml',
event: 'push',
branch: tag,
}),

// These have the potential to become active deploys, so we need to wait for them to finish as well
// These have the potential to become active deploys, so we need to wait for them to finish as well (unless we're looking for a specific tag)
// In this context, we'll refer to unresolved preDeploy workflow runs as staging deploys as well
GitHubUtils.octokit.actions.listWorkflowRuns({
!tag && GitHubUtils.octokit.actions.listWorkflowRuns({
owner: GitHubUtils.GITHUB_OWNER,
repo: GitHubUtils.APP_REPO,
workflow_id: 'preDeploy.yml',
}),
])
.then(responses => [
...responses[0].data.workflow_runs,
...responses[1].data.workflow_runs,
])
.then((responses) => {
const workflowRuns = responses[0].data.workflow_runs;
if (!tag) {
workflowRuns.push(...responses[1].data.workflow_runs);
}
return workflowRuns;
})
.then(workflowRuns => currentStagingDeploys = _.filter(workflowRuns, workflowRun => workflowRun.status !== 'completed'))
.then(() => console.log(
_.isEmpty(currentStagingDeploys)
Expand All @@ -58,6 +64,52 @@ if (require.main === require.cache[eval('__filename')]) {
module.exports = run;


/***/ }),

/***/ 970:
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {

const core = __nccwpck_require__(2186);

/**
* Safely parse a JSON input to a GitHub Action.
*
* @param {String} name - The name of the input.
* @param {Object} options - Options to pass to core.getInput
* @param {*} [defaultValue] - A default value to provide for the input.
* Not required if the {required: true} option is given in the second arg to this function.
* @returns {any}
*/
function getJSONInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (input) {
return JSON.parse(input);
}
return defaultValue;
}

/**
* Safely access a string input to a GitHub Action, or fall back on a default if the string is empty.
*
* @param {String} name
* @param {Object} options
* @param {*} [defaultValue]
* @returns {string|undefined}
*/
function getStringInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (!input) {
return defaultValue;
}
return input;
}

module.exports = {
getJSONInput,
getStringInput,
};


/***/ }),

/***/ 7999:
Expand Down
17 changes: 17 additions & 0 deletions .github/actions/getDeployPullRequestList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,25 @@ function getJSONInput(name, options, defaultValue = undefined) {
return defaultValue;
}

/**
* Safely access a string input to a GitHub Action, or fall back on a default if the string is empty.
*
* @param {String} name
* @param {Object} options
* @param {*} [defaultValue]
* @returns {string|undefined}
*/
function getStringInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (!input) {
return defaultValue;
}
return input;
}

module.exports = {
getJSONInput,
getStringInput,
};


Expand Down
17 changes: 17 additions & 0 deletions .github/actions/getPullRequestDetails/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,25 @@ function getJSONInput(name, options, defaultValue = undefined) {
return defaultValue;
}

/**
* Safely access a string input to a GitHub Action, or fall back on a default if the string is empty.
*
* @param {String} name
* @param {Object} options
* @param {*} [defaultValue]
* @returns {string|undefined}
*/
function getStringInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (!input) {
return defaultValue;
}
return input;
}

module.exports = {
getJSONInput,
getStringInput,
};


Expand Down
17 changes: 17 additions & 0 deletions .github/actions/getReleaseBody/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,25 @@ function getJSONInput(name, options, defaultValue = undefined) {
return defaultValue;
}

/**
* Safely access a string input to a GitHub Action, or fall back on a default if the string is empty.
*
* @param {String} name
* @param {Object} options
* @param {*} [defaultValue]
* @returns {string|undefined}
*/
function getStringInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (!input) {
return defaultValue;
}
return input;
}

module.exports = {
getJSONInput,
getStringInput,
};


Expand Down
17 changes: 17 additions & 0 deletions .github/actions/markPullRequestsAsDeployed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,25 @@ function getJSONInput(name, options, defaultValue = undefined) {
return defaultValue;
}

/**
* Safely access a string input to a GitHub Action, or fall back on a default if the string is empty.
*
* @param {String} name
* @param {Object} options
* @param {*} [defaultValue]
* @returns {string|undefined}
*/
function getStringInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (!input) {
return defaultValue;
}
return input;
}

module.exports = {
getJSONInput,
getStringInput,
};


Expand Down
17 changes: 17 additions & 0 deletions .github/actions/triggerWorkflowAndWait/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,25 @@ function getJSONInput(name, options, defaultValue = undefined) {
return defaultValue;
}

/**
* Safely access a string input to a GitHub Action, or fall back on a default if the string is empty.
*
* @param {String} name
* @param {Object} options
* @param {*} [defaultValue]
* @returns {string|undefined}
*/
function getStringInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (!input) {
return defaultValue;
}
return input;
}

module.exports = {
getJSONInput,
getStringInput,
};


Expand Down
17 changes: 17 additions & 0 deletions .github/libs/ActionUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ function getJSONInput(name, options, defaultValue = undefined) {
return defaultValue;
}

/**
* Safely access a string input to a GitHub Action, or fall back on a default if the string is empty.
*
* @param {String} name
* @param {Object} options
* @param {*} [defaultValue]
* @returns {string|undefined}
*/
function getStringInput(name, options, defaultValue = undefined) {
const input = core.getInput(name, options);
if (!input) {
return defaultValue;
}
return input;
}

module.exports = {
getJSONInput,
getStringInput,
};
6 changes: 3 additions & 3 deletions .github/scripts/validateActionsAndWorkflows.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ curl https://json.schemastore.org/github-action.json --output ./tempSchemas/gith
curl https://json.schemastore.org/github-workflow.json --output ./tempSchemas/github-workflow.json --silent || exit 1

# Validate the actions and workflows using the JSON schemas and ajv https://github.com/ajv-validator/ajv-cli
find ./actions/ -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-action.json -d file --strict=false || EXIT_CODE=1
find ./workflows/ -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-workflow.json -d file --strict=false || EXIT_CODE=1
find ./actions -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-action.json -d file --strict=false || EXIT_CODE=1
find ./workflows -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-workflow.json -d file --strict=false || EXIT_CODE=1

if (( $EXIT_CODE != 0 )); then
if (( "$EXIT_CODE" != 0 )); then
exit $EXIT_CODE
fi

Expand Down
34 changes: 32 additions & 2 deletions .github/workflows/preDeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ jobs:
WORKFLOW: updateProtectedBranch.yml
INPUTS: '{ "TARGET_BRANCH": "staging" }'

- name: Determine if this pull request will be cherry-picked
run: echo "DO_CHERRY_PICK=${{ fromJSON(needs.chooseDeployActions.outputs.isStagingDeployLocked) && fromJSON(needs.chooseDeployActions.outputs.shouldCherryPick) }}" >> "$GITHUB_ENV"

- name: Cherry pick to staging
if: ${{ fromJSON(needs.chooseDeployActions.outputs.isStagingDeployLocked) && fromJSON(needs.chooseDeployActions.outputs.shouldCherryPick) }}
if: ${{ env.DO_CHERRY_PICK }}
uses: Expensify/App/.github/actions/triggerWorkflowAndWait@main
with:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
Expand All @@ -157,6 +160,33 @@ jobs:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
NPM_VERSION: ${{ env.NEW_VERSION }}

- name: Comment in StagingDeployCash to alert Applause that a new pull request has been cherry-picked
if: ${{ env.DO_CHERRY_PICK }}
run: |
PR_URL="https://github.com/Expensify/App/pull/${{ needs.chooseDeployActions.outputs.mergedPullRequest }}"
printf -v COMMENT ":clap: Heads up @Expensify/applauseleads :clap:\nA [new pull request](%s) has been :cherries: cherry-picked :cherries: to staging, and will be deployed to staging in version \`%s\` :rocket:" "$PR_URL" ${{ env.NEW_VERSION }}
gh issue comment \
"$(gh issue list --label StagingDeployCash --json number --jq '.[0].number')" \
--body "$COMMENT"
env:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}

- name: Wait for staging deploys to finish
if: ${{ env.DO_CHERRY_PICK }}
uses: Expensify/App/.github/actions/awaitStagingDeploys@main
with:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
TAG: ${{ env.NEW_VERSION }}

- name: Comment in StagingDeployCash to alert Applause that cherry-picked pull request has been deployed.
if: ${{ env.DO_CHERRY_PICK }}
run: |
gh issue comment \
"$(gh issue list --label StagingDeployCash --json number --jq '.[0].number')" \
--body ":tada: All set?…You bet! https://github.com/Expensify/App/releases/tag/${{ env.NEW_VERSION }} has been deployed to staging :tada:"
roryabraham marked this conversation as resolved.
Show resolved Hide resolved
env:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}

# This Slack step is duplicated in all workflows, if you make a change to this step, make sure to update all
# the other workflows with the same change
- uses: 8398a7/action-slack@v3
Expand All @@ -178,7 +208,7 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

# Check if actor is member of Expensify organization by looking for expensify-expensify team
# Check if actor is member of Expensify organization by looking for expensify-expensify team
isExpensifyEmployee:
runs-on: ubuntu-latest

Expand Down
Loading