Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions .github/workflows/test-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
continue-on-error: true
run: |
npm install
export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
./node_modules/.bin/jest --json --outputFile=${{env.jest-output-file}} ./src/

- name: Process jest results
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
- name: Create GitHub Deployment
id: defaults
continue-on-error: true # Setting to true so the job doesn't fail if updating the board fails.
uses: im-open/[email protected].10 # You may also reference just the major or major.minor version
uses: im-open/[email protected].8 # You may also reference just the major or major.minor version
with:
workflow-actor: ${{ github.actor }} # This will add the user who kicked off the workflow to the deployment payload
token: ${{ secrets.GITHUB_TOKEN }} # If a different token is used, update github-login with the corresponding account
Expand Down
65 changes: 35 additions & 30 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42107,17 +42107,21 @@ var require_deployments = __commonJS({
var { Octokit } = require_dist_node12();
var { graphql } = require_dist_node6();
var WORKFLOW_DEPLOY = 'workflowdeploy';
var ALLOWED_STATUSES = [
'success',
'error',
'failure',
'inactive',
'in_progress',
'queued',
'pending'
];
var ALLOWED_STATUSES = {
SUCCESS: 'success',
ERROR: 'error',
FAILURE: 'failure',
INACTIVE: 'inactive',
IN_PROGRESS: 'in_progress',
QUEUED: 'queued',
PENDING: 'pending'
};
var createOctokitClient = token => new Octokit({ auth: token });
var createOctokitGraphQLClient = token =>
graphql.defaults({ headers: { authorization: `token ${token}` } });
async function inactivatePriorDeployments(context, currentDeploymentNodeId) {
const octokit = new Octokit({ auth: context.token });
const octokit = createOctokitClient(context.token);
const octokitGraphQl = createOctokitGraphQLClient(context.token);
const params = {
owner: context.owner,
repo: context.repo,
Expand All @@ -42126,19 +42130,14 @@ var require_deployments = __commonJS({
per_page: 100
};
const deploymentsList = (
await octokit.paginate(octokit.rest.repos.listDeployments, params)
).filter(
d =>
d.node_id != currentDeploymentNodeId &&
d.payload.entity == context.entity &&
d.payload.instance == context.instance
);
await getPriorDeployments(octokit, context.entity, context.instance, params)
).filter(d => d.node_id != currentDeploymentNodeId);
const statuses = await getPriorDeploymentStatuses(
context.token,
octokitGraphQl,
deploymentsList.map(d => d.node_id)
);
for (let i = 0; i < statuses.deployments.length; i++) {
let deploymentQl = statuses.deployments[i];
for (let i = 0; i < statuses.length; i++) {
let deploymentQl = statuses[i];
let deployment = deploymentsList.filter(d => d.node_id == deploymentQl.id)[0];
for (let j = 0; j < deploymentQl.statuses.nodes.length; j++) {
const status = deploymentQl.statuses.nodes[j];
Expand All @@ -42156,12 +42155,12 @@ var require_deployments = __commonJS({
}
}
}
async function getPriorDeploymentStatuses(token, deploymentNodeIds) {
const octokitGraphQl = graphql.defaults({
headers: {
authorization: `token ${token}`
}
});
async function getPriorDeployments(octokit, entity, instance, params) {
return (await octokit.paginate(octokit.rest.repos.listDeployments, params)).filter(
d => d.payload.entity == entity && d.payload.instance == instance
);
}
async function getPriorDeploymentStatuses(octokitGraphQl, deploymentNodeIds) {
const statuses = [];
const statusesQuery = `
query($deploymentNodeIds: [ID!]!) {
Expand Down Expand Up @@ -42194,7 +42193,7 @@ var require_deployments = __commonJS({
return statuses;
}
async function createDeployment2(context) {
const octokit = new Octokit({ auth: context.token });
const octokit = createOctokitClient(context.token);
const deployment = (
await octokit.rest.repos.createDeployment({
owner: context.owner,
Expand Down Expand Up @@ -42252,7 +42251,12 @@ var require_deployments = __commonJS({
}
module2.exports = {
ALLOWED_STATUSES,
createDeployment: createDeployment2
WORKFLOW_DEPLOY,
createDeployment: createDeployment2,
createOctokitClient,
createOctokitGraphQLClient,
getPriorDeployments,
getPriorDeploymentStatuses
};
}
});
Expand Down Expand Up @@ -42317,7 +42321,7 @@ var require_library = __commonJS({
const workflow_run_id = github.context.runId;
const owner = github.context.repo.owner;
const repo = github.context.repo.repo;
if (!ALLOWED_STATUSES.map(s => s.toLowerCase()).includes(deployment_status.toLowerCase())) {
if (!Object.values(ALLOWED_STATUSES).includes(deployment_status.toLowerCase())) {
throw { name: INVALID_STATUS, message: `Invalid deployment status: ${deployment_status}` };
}
return new context(
Expand All @@ -42337,7 +42341,8 @@ var require_library = __commonJS({
}
module2.exports = {
INVALID_STATUS,
setup: setup2
setup: setup2,
context
};
}
});
Expand Down
63 changes: 35 additions & 28 deletions src/deployments.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
const { Octokit } = require('@octokit/rest');
const { graphql } = require('@octokit/graphql');
const WORKFLOW_DEPLOY = 'workflowdeploy';
const ALLOWED_STATUSES = [
'success',
'error',
'failure',
'inactive',
'in_progress',
'queued',
'pending'
];
const ALLOWED_STATUSES = {
SUCCESS: 'success',
ERROR: 'error',
FAILURE: 'failure',
INACTIVE: 'inactive',
IN_PROGRESS: 'in_progress',
QUEUED: 'queued',
PENDING: 'pending'
};

const createOctokitClient = token => new Octokit({ auth: token });
const createOctokitGraphQLClient = token =>
graphql.defaults({ headers: { authorization: `token ${token}` } });
Comment on lines +14 to +16

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an advantage to defining a function that creates an octokit client as opposed to creating a single client that is passed to the functions that need it? It seems like having a single client that all the different functions use might be better than each function creating its own version of the client.

Copy link
Contributor Author

@hpractv hpractv Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is getting used by the deployment testing file, too. I wanted to make sure the setting params for these clients were the same in both the runtime code as well as the jest test.


async function inactivatePriorDeployments(context, currentDeploymentNodeId) {
const octokit = new Octokit({ auth: context.token });
const octokit = createOctokitClient(context.token);
const octokitGraphQl = createOctokitGraphQLClient(context.token);

const params = {
owner: context.owner,
Expand All @@ -23,21 +28,16 @@ async function inactivatePriorDeployments(context, currentDeploymentNodeId) {
};

const deploymentsList = (
await octokit.paginate(octokit.rest.repos.listDeployments, params)
).filter(
d =>
d.node_id != currentDeploymentNodeId &&
d.payload.entity == context.entity &&
d.payload.instance == context.instance
);
await getPriorDeployments(octokit, context.entity, context.instance, params)
).filter(d => d.node_id != currentDeploymentNodeId);

const statuses = await getPriorDeploymentStatuses(
context.token,
octokitGraphQl,
deploymentsList.map(d => d.node_id)
);

for (let i = 0; i < statuses.deployments.length; i++) {
let deploymentQl = statuses.deployments[i];
for (let i = 0; i < statuses.length; i++) {
let deploymentQl = statuses[i];
let deployment = deploymentsList.filter(d => d.node_id == deploymentQl.id)[0];

for (let j = 0; j < deploymentQl.statuses.nodes.length; j++) {
Expand All @@ -58,13 +58,13 @@ async function inactivatePriorDeployments(context, currentDeploymentNodeId) {
}
}

async function getPriorDeploymentStatuses(token, deploymentNodeIds) {
const octokitGraphQl = graphql.defaults({
headers: {
authorization: `token ${token}`
}
});
async function getPriorDeployments(octokit, entity, instance, params) {
return (await octokit.paginate(octokit.rest.repos.listDeployments, params)).filter(
d => d.payload.entity == entity && d.payload.instance == instance
);
}

async function getPriorDeploymentStatuses(octokitGraphQl, deploymentNodeIds) {
const statuses = [];
const statusesQuery = `
query($deploymentNodeIds: [ID!]!) {
Expand Down Expand Up @@ -101,7 +101,8 @@ async function getPriorDeploymentStatuses(token, deploymentNodeIds) {
}

async function createDeployment(context) {
const octokit = new Octokit({ auth: context.token });
const octokit = createOctokitClient(context.token);

// create deployment record
const deployment = (
await octokit.rest.repos.createDeployment({
Expand All @@ -126,6 +127,7 @@ async function createDeployment(context) {
const inactivate = new Promise((resolve, reject) =>
resolve(inactivatePriorDeployments(context, deployment.node_id))
);

inactivate.then(async () => {
await createDeploymentStatus(
octokit,
Expand Down Expand Up @@ -164,5 +166,10 @@ async function createDeploymentStatus(

module.exports = {
ALLOWED_STATUSES,
createDeployment
WORKFLOW_DEPLOY,
createDeployment,
createOctokitClient,
createOctokitGraphQLClient,
getPriorDeployments,
getPriorDeploymentStatuses
};
99 changes: 99 additions & 0 deletions src/deployments.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const { describe, test, expect, beforeEach, beforeAll, afterAll } = require('@jest/globals');
const {
ALLOWED_STATUSES,
WORKFLOW_DEPLOY,
createOctokitClient,
createOctokitGraphQLClient,
getPriorDeployments,
getPriorDeploymentStatuses,
createDeployment
} = require('./deployments.js');
const { context } = require('./library.js');

const token = process.env['GITHUB_TOKEN'];
let octokit;
let octokitGraphQl;
const owner = 'im-open';
const repo = 'create-github-deployment';
const create_environment = 'INTEGRATION';
const pull_environment = 'DEV';
const entity = 'create-github-deployment';
const instance = 'action';
const priorDeployments = [];
const priorDeploymentStatuses = [];
let testDeploymentId = null;
const workflow_actor = 'test-actor';

// Create the octokit clients
beforeAll(() => {
octokit = createOctokitClient(token);
octokitGraphQl = createOctokitGraphQLClient(token);
});

//clean up test deployment
afterAll(async () => {
if (testDeploymentId !== null) {
setTimeout(async () => {
await octokit.rest.repos.deleteDeployment({
owner: owner,
repo: repo,
deployment_id: testDeploymentId
});
octokit = null;
octokitGraphQl = null;
}, 5000);
}
});

describe('deployments', () => {
let firstDeploymentId;

test('get the deployments', async () => {
const deployments = await getPriorDeployments(octokit, entity, instance, {
owner: owner,
repo: repo,
task: WORKFLOW_DEPLOY,
environment: pull_environment,
per_page: 100
});
expect(deployments).toBeDefined();
expect(deployments.length).toBeGreaterThan(0);
expect(deployments[0].payload).toBeDefined();
firstDeploymentId = deployments[0].node_id;

priorDeployments.push(...deployments);
});

test('get the deployment statuses', async () => {
const statuses = await getPriorDeploymentStatuses(octokitGraphQl, [firstDeploymentId]);
expect(statuses).toBeDefined();
expect(statuses.length).toBeGreaterThan(0);

expect(statuses[0].statuses).toBeDefined();
expect(statuses[0].statuses.nodes).toBeDefined();
expect(statuses[0].statuses.nodes.length).toBeGreaterThan(0);

priorDeploymentStatuses.push(...statuses);
});

test('create deployment', async () => {
testDeploymentId = await createDeployment(
new context(
workflow_actor,
token,
create_environment,
'v1',
ALLOWED_STATUSES.SUCCESS,
'Testing deployment creation',
entity,
instance,
'https://github.com',
'https://github.com',
owner,
repo
)
);

expect(Number.isNaN(testDeploymentId)).toBe(false);
});
});
5 changes: 3 additions & 2 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function setup() {
const owner = github.context.repo.owner;
const repo = github.context.repo.repo;

if (!ALLOWED_STATUSES.map(s => s.toLowerCase()).includes(deployment_status.toLowerCase())) {
if (!Object.values(ALLOWED_STATUSES).includes(deployment_status.toLowerCase())) {
throw { name: INVALID_STATUS, message: `Invalid deployment status: ${deployment_status}` };
}

Expand All @@ -79,5 +79,6 @@ function setup() {

module.exports = {
INVALID_STATUS,
setup
setup,
context
};
20 changes: 11 additions & 9 deletions src/library.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const { assert } = require('node:assert');
const { describe, test, expect, beforeEach } = require('@jest/globals');
const { setup, INVALID_STATUS } = require('./library.js');
const { ALLOWED_STATUSES } = require('./deployments.js');
Expand Down Expand Up @@ -32,13 +31,16 @@ describe('deployment status', () => {
}
});

test.each(ALLOWED_STATUSES)(`valid deployment status of %s does not throw exception`, status => {
process.env[inputKey('deployment-status')] = status;
try {
const testConext = setup();
expect(testConext.deployment_status).toBe(status);
} catch (error) {
expect(error).toBeUndefined();
test.each(Object.values(ALLOWED_STATUSES))(
`valid deployment status of %s does not throw exception`,
status => {
process.env[inputKey('deployment-status')] = status;
try {
const testContext = setup();
expect(testContext.deployment_status).toBe(status);
} catch (error) {
expect(error).toBeUndefined();
}
}
});
);
});
Loading