Skip to content

Commit

Permalink
Fix multiple project columns (#30)
Browse files Browse the repository at this point in the history
* Fix multiple project columns
  • Loading branch information
Alex Page authored Mar 26, 2020
1 parent fdffc76 commit 0597b62
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 107 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
automate-project-columns:
runs-on: ubuntu-latest
steps:
- uses: alex-page/[email protected].0
- uses: alex-page/[email protected].1
with:
project: Backlog
column: Triage
Expand All @@ -51,7 +51,7 @@ jobs:
automate-project-columns:
runs-on: ubuntu-latest
steps:
- uses: alex-page/[email protected].0
- uses: alex-page/[email protected].1
with:
project: Backlog
column: To do
Expand Down Expand Up @@ -94,6 +94,7 @@ GraphqlError: Resource protected by organization SAML enforcement. You must gran
## Release History
- v0.2.1 - Fix bug with move logic when card is already in project
- v0.2.0 - Restructure project, add tests, change add and move logic
- v0.1.3 - Exact match for project names
- v0.1.2 - Fix action not running for a card that exists in multiple projects
Expand Down
119 changes: 52 additions & 67 deletions __tests__/generate-mutation-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,18 @@ const generateMutationQuery = require('../src/generate-mutation-query');
const project = 'Backlog';
const column = 'To do';
const nodeId = 'MDU6SXNzdWU1ODc4NzU1Mjk=';
const data = {

const moveData = {
projectCards: {
nodes: [
{
id: 'MDExOlByb2plY3RDYXJkMzUxNzI2MjM=',
column: {
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxODk4'
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ6'
},
project: {
name: project
}
},
{
id: 'MDExOlByb2plY3RDYXJkMzUxNzI2Mj2=',
column: {
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5'
},
project: {
name: 'Backlogg'
name: project,
id: 'MDc6UHJvamVjdDQwNzU5MDI='
}
}
]
Expand All @@ -37,24 +30,55 @@ const data = {
columns: {
nodes: [
{
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5',
name: column
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ6',
name: 'Icebox'
},
{
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ6',
name: 'To doo'
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5',
name: column
}
]
}
},
}
]
},
owner: {
projects: {
nodes: []
}
}
}
};

test('generateMutationQuery move the card when in the correct project and wrong column', t => {
t.deepEqual(generateMutationQuery(moveData, project, column, nodeId), [
`mutation {
moveProjectCard( input: {
cardId: "MDExOlByb2plY3RDYXJkMzUxNzI2MjM=",
columnId: "MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5"
}) { clientMutationId } }`
]);
});

const addData = {
projectCards: {
nodes: []
},
repository: {
projects: {
nodes: [
{
id: 'MDc6UHJvamVjdDQwNzU5MDE=',
name: 'Backlogg',
name: project,
id: 'MDc6UHJvamVjdDQwNzU5MDI=',
columns: {
nodes: [
{
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxODk7',
name: 'To do'
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5',
name: column
},
{
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxOTAz',
name: 'In progress'
}
]
}
Expand All @@ -63,57 +87,18 @@ const data = {
},
owner: {
projects: {
nodes: [
{
id: 'MDc6UHJvamVjdDQwNzU5MDI=',
name: project,
columns: {
nodes: [
{
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ8',
name: column
},
{
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ9',
name: 'In progress'
}
]
}
},
{
id: 'MDc6UHJvamVjdDQwNzU5MDE=',
name: 'Backlogg',
columns: {
nodes: [
{
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxOD10',
name: 'To do'
}
]
}
}
]
nodes: []
}
}
}
};

test('findColumns should return column Ids for exact matches', t => {
t.deepEqual(generateMutationQuery(data, project, column, nodeId), [
test('generateMutationQuery add the card when the card does not exist in the project', t => {
t.deepEqual(generateMutationQuery(addData, project, column, nodeId), [
`mutation {
addProjectCard( input: {
contentId: "MDU6SXNzdWU1ODc4NzU1Mjk=",
projectColumnId: "MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5"
}) { clientMutationId } }`,
`mutation {
addProjectCard( input: {
contentId: "MDU6SXNzdWU1ODc4NzU1Mjk=",
projectColumnId: "MDEzOlByb2plY3RDb2x1bW44NDU0MzQ8"
}) { clientMutationId } }`,
`mutation {
moveProjectCard( input: {
cardId: "MDExOlByb2plY3RDYXJkMzUxNzI2MjM=",
columnId: "MDEzOlByb2plY3RDb2x1bW44MjUxODk4"
}) { clientMutationId } }`
]);
});
Expand Down Expand Up @@ -147,10 +132,10 @@ const dataNoColumn = {
}
};

test('findColumns should fail if it cannot find a matching column', t => {
test('generateMutationQuery should fail if it cannot find a matching column', t => {
const error = t.throws(() => generateMutationQuery(dataNoColumn, project, column, nodeId));

t.is(error.message, 'Could not find the column "To do" in project "Backlog"');
t.is(error.message, `Could not find the column "${column}" or project "${project}"`);
});

const dataNoProject = {
Expand Down Expand Up @@ -182,8 +167,8 @@ const dataNoProject = {
}
};

test('findColumns should fail if it cannot find a matching project', t => {
test('generateMutationQuery should fail if it cannot find a matching project', t => {
const error = t.throws(() => generateMutationQuery(dataNoProject, project, column, nodeId));

t.is(error.message, 'Could not find the project "Backlog"');
t.is(error.message, `Could not find the column "${column}" or project "${project}"`);
});
6 changes: 6 additions & 0 deletions __tests__/generate-project-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ const issueQuery = `query {
}
project {
name
id
}
}
}
repository {
projects( search: "Backlog", first: 10, states: [OPEN] ) {
nodes {
name
id
columns( first: 100 ) {
nodes {
id
Expand All @@ -33,6 +35,7 @@ const issueQuery = `query {
projects( search: "Backlog", first: 10, states: [OPEN] ) {
nodes {
name
id
columns( first: 100 ) {
nodes {
id
Expand All @@ -59,13 +62,15 @@ const pullrequestQuery = `query {
}
project {
name
id
}
}
}
repository {
projects( search: "Backlogg", first: 10, states: [OPEN] ) {
nodes {
name
id
columns( first: 100 ) {
nodes {
id
Expand All @@ -79,6 +84,7 @@ const pullrequestQuery = `query {
projects( search: "Backlogg", first: 10, states: [OPEN] ) {
nodes {
name
id
columns( first: 100 ) {
nodes {
id
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "github-project-automation-plus",
"version": "0.2.0",
"version": "0.2.1",
"description": "🤖 Automate GitHub Project cards with any webhook event",
"private": true,
"main": "dist/index.js",
Expand Down
82 changes: 46 additions & 36 deletions src/generate-mutation-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,58 +14,68 @@ const generateMutationQuery = (data, projectName, columnName, contentId) => {
data.repository.owner.projects.nodes) ||
[];

// Flatten the org and repo projects that match the user provided projectName
const matchingNewProjects = [...repoProjects, ...orgProjects]
// Find matching projects and columns for the card to move to
const endLocation = [...repoProjects, ...orgProjects]
.filter(project => project.name === projectName)
.flatMap(project =>
project.columns.nodes.length === 0 ? [] : project.columns.nodes
);
.flatMap(project => project)
.filter(project => {
const matchingColumns = project.columns.nodes
.filter(column => column.name === columnName);
return matchingColumns.length !== 0;
});

if (matchingNewProjects.length === 0) {
throw new Error(`Could not find the project "${projectName}"`);
// There are no locations for the card to move to
if (endLocation.length === 0) {
throw new Error(`Could not find the column "${columnName}" or project "${projectName}"`);
}

// Columns that match the column inputted
const newColumnIds = matchingNewProjects
.filter(column => column.name === columnName)
.map(column => column.id);
// Get the ids of the end card location
const endLocationIds = endLocation.map(project => ({
projectId: project.id,
columnId: project.columns.nodes
.filter(column => column.name === columnName)
.map(column => column.id)[0]
}));

if (newColumnIds.length === 0) {
throw new Error(`Could not find the column "${columnName}" in project "${projectName}"`);
}

// Get an array of cards that are assigned to the correct project
const assingedProjects = data.projectCards.nodes
// See if the card has a current location
const currentLocation = data.projectCards.nodes
.filter(card => card.project.name === projectName);

// Get cards in the right project that are not in the correct column
const currentCards = assingedProjects
.filter(card => !newColumnIds.includes(card.column.id));
const currentLocationIds = currentLocation.map(card => ({
projectId: card.project.id,
columnId: card.column.id,
cardId: card.id
}));

// Create an array of queries to move the card
const moveProjectCard = currentCards.map(card =>
`mutation {
moveProjectCard( input: {
cardId: "${card.id}",
columnId: "${card.column.id}"
}) { clientMutationId } }`
);

// Get column ids where the card does not exist
const currentColumnIds = currentCards.map(card => card.column.id);
const emptyColumns = newColumnIds
.filter(columnId => !currentColumnIds.includes(columnId));
// Get cards to create when they do not have a matching existing project
const currentCardProjectIds = currentLocationIds.map(ids => ids.projectId);
const newCards = endLocationIds.filter(ids => !currentCardProjectIds.includes(ids.projectId));

// Create an an array of queries to add the card
const addProjectCard = emptyColumns.map(columnId =>
const addProjectCardQueries = newCards.map(card =>
`mutation {
addProjectCard( input: {
contentId: "${contentId}",
projectColumnId: "${columnId}"
projectColumnId: "${card.columnId}"
}) { clientMutationId } }`
);

return [...addProjectCard, ...moveProjectCard];
// Get cards to move when they exist in a project
const endLocationProjectIds = endLocationIds.map(ids => ids.projectId);
const moveCards = currentLocationIds.filter(ids => endLocationProjectIds.includes(ids.projectId));

// Create an array of queries to move the card
const moveProjectCardQueries = moveCards.map(card => {
const endLocation = endLocationIds.filter(ids => ids.projectId === card.projectId)[0];

return `mutation {
moveProjectCard( input: {
cardId: "${card.cardId}",
columnId: "${endLocation.columnId}"
}) { clientMutationId } }`;
});

return [...addProjectCardQueries, ...moveProjectCardQueries];
};

module.exports = generateMutationQuery;
3 changes: 3 additions & 0 deletions src/generate-project-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ const projectQuery = (url, eventName, project) => (
}
project {
name
id
}
}
}
repository {
projects( search: "${project}", first: 10, states: [OPEN] ) {
nodes {
name
id
columns( first: 100 ) {
nodes {
id
Expand All @@ -37,6 +39,7 @@ const projectQuery = (url, eventName, project) => (
projects( search: "${project}", first: 10, states: [OPEN] ) {
nodes {
name
id
columns( first: 100 ) {
nodes {
id
Expand Down
Loading

0 comments on commit 0597b62

Please sign in to comment.