Skip to content

Commit 0597b62

Browse files
author
Alex Page
authored
Fix multiple project columns (#30)
* Fix multiple project columns
1 parent fdffc76 commit 0597b62

File tree

8 files changed

+118
-107
lines changed

8 files changed

+118
-107
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
automate-project-columns:
3030
runs-on: ubuntu-latest
3131
steps:
32-
- uses: alex-page/[email protected].0
32+
- uses: alex-page/[email protected].1
3333
with:
3434
project: Backlog
3535
column: Triage
@@ -51,7 +51,7 @@ jobs:
5151
automate-project-columns:
5252
runs-on: ubuntu-latest
5353
steps:
54-
- uses: alex-page/[email protected].0
54+
- uses: alex-page/[email protected].1
5555
with:
5656
project: Backlog
5757
column: To do
@@ -94,6 +94,7 @@ GraphqlError: Resource protected by organization SAML enforcement. You must gran
9494
9595
## Release History
9696
97+
- v0.2.1 - Fix bug with move logic when card is already in project
9798
- v0.2.0 - Restructure project, add tests, change add and move logic
9899
- v0.1.3 - Exact match for project names
99100
- v0.1.2 - Fix action not running for a card that exists in multiple projects

__tests__/generate-mutation-query.js

Lines changed: 52 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,18 @@ const generateMutationQuery = require('../src/generate-mutation-query');
55
const project = 'Backlog';
66
const column = 'To do';
77
const nodeId = 'MDU6SXNzdWU1ODc4NzU1Mjk=';
8-
const data = {
8+
9+
const moveData = {
910
projectCards: {
1011
nodes: [
1112
{
1213
id: 'MDExOlByb2plY3RDYXJkMzUxNzI2MjM=',
1314
column: {
14-
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxODk4'
15+
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ6'
1516
},
1617
project: {
17-
name: project
18-
}
19-
},
20-
{
21-
id: 'MDExOlByb2plY3RDYXJkMzUxNzI2Mj2=',
22-
column: {
23-
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5'
24-
},
25-
project: {
26-
name: 'Backlogg'
18+
name: project,
19+
id: 'MDc6UHJvamVjdDQwNzU5MDI='
2720
}
2821
}
2922
]
@@ -37,24 +30,55 @@ const data = {
3730
columns: {
3831
nodes: [
3932
{
40-
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5',
41-
name: column
33+
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ6',
34+
name: 'Icebox'
4235
},
4336
{
44-
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ6',
45-
name: 'To doo'
37+
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5',
38+
name: column
4639
}
4740
]
4841
}
49-
},
42+
}
43+
]
44+
},
45+
owner: {
46+
projects: {
47+
nodes: []
48+
}
49+
}
50+
}
51+
};
52+
53+
test('generateMutationQuery move the card when in the correct project and wrong column', t => {
54+
t.deepEqual(generateMutationQuery(moveData, project, column, nodeId), [
55+
`mutation {
56+
moveProjectCard( input: {
57+
cardId: "MDExOlByb2plY3RDYXJkMzUxNzI2MjM=",
58+
columnId: "MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5"
59+
}) { clientMutationId } }`
60+
]);
61+
});
62+
63+
const addData = {
64+
projectCards: {
65+
nodes: []
66+
},
67+
repository: {
68+
projects: {
69+
nodes: [
5070
{
51-
id: 'MDc6UHJvamVjdDQwNzU5MDE=',
52-
name: 'Backlogg',
71+
name: project,
72+
id: 'MDc6UHJvamVjdDQwNzU5MDI=',
5373
columns: {
5474
nodes: [
5575
{
56-
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxODk7',
57-
name: 'To do'
76+
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5',
77+
name: column
78+
},
79+
{
80+
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxOTAz',
81+
name: 'In progress'
5882
}
5983
]
6084
}
@@ -63,57 +87,18 @@ const data = {
6387
},
6488
owner: {
6589
projects: {
66-
nodes: [
67-
{
68-
id: 'MDc6UHJvamVjdDQwNzU5MDI=',
69-
name: project,
70-
columns: {
71-
nodes: [
72-
{
73-
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ8',
74-
name: column
75-
},
76-
{
77-
id: 'MDEzOlByb2plY3RDb2x1bW44NDU0MzQ9',
78-
name: 'In progress'
79-
}
80-
]
81-
}
82-
},
83-
{
84-
id: 'MDc6UHJvamVjdDQwNzU5MDE=',
85-
name: 'Backlogg',
86-
columns: {
87-
nodes: [
88-
{
89-
id: 'MDEzOlByb2plY3RDb2x1bW44MjUxOD10',
90-
name: 'To do'
91-
}
92-
]
93-
}
94-
}
95-
]
90+
nodes: []
9691
}
9792
}
9893
}
9994
};
10095

101-
test('findColumns should return column Ids for exact matches', t => {
102-
t.deepEqual(generateMutationQuery(data, project, column, nodeId), [
96+
test('generateMutationQuery add the card when the card does not exist in the project', t => {
97+
t.deepEqual(generateMutationQuery(addData, project, column, nodeId), [
10398
`mutation {
10499
addProjectCard( input: {
105100
contentId: "MDU6SXNzdWU1ODc4NzU1Mjk=",
106101
projectColumnId: "MDEzOlByb2plY3RDb2x1bW44NDU0MzQ5"
107-
}) { clientMutationId } }`,
108-
`mutation {
109-
addProjectCard( input: {
110-
contentId: "MDU6SXNzdWU1ODc4NzU1Mjk=",
111-
projectColumnId: "MDEzOlByb2plY3RDb2x1bW44NDU0MzQ8"
112-
}) { clientMutationId } }`,
113-
`mutation {
114-
moveProjectCard( input: {
115-
cardId: "MDExOlByb2plY3RDYXJkMzUxNzI2MjM=",
116-
columnId: "MDEzOlByb2plY3RDb2x1bW44MjUxODk4"
117102
}) { clientMutationId } }`
118103
]);
119104
});
@@ -147,10 +132,10 @@ const dataNoColumn = {
147132
}
148133
};
149134

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

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

156141
const dataNoProject = {
@@ -182,8 +167,8 @@ const dataNoProject = {
182167
}
183168
};
184169

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

188-
t.is(error.message, 'Could not find the project "Backlog"');
173+
t.is(error.message, `Could not find the column "${column}" or project "${project}"`);
189174
});

__tests__/generate-project-query.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ const issueQuery = `query {
1313
}
1414
project {
1515
name
16+
id
1617
}
1718
}
1819
}
1920
repository {
2021
projects( search: "Backlog", first: 10, states: [OPEN] ) {
2122
nodes {
2223
name
24+
id
2325
columns( first: 100 ) {
2426
nodes {
2527
id
@@ -33,6 +35,7 @@ const issueQuery = `query {
3335
projects( search: "Backlog", first: 10, states: [OPEN] ) {
3436
nodes {
3537
name
38+
id
3639
columns( first: 100 ) {
3740
nodes {
3841
id
@@ -59,13 +62,15 @@ const pullrequestQuery = `query {
5962
}
6063
project {
6164
name
65+
id
6266
}
6367
}
6468
}
6569
repository {
6670
projects( search: "Backlogg", first: 10, states: [OPEN] ) {
6771
nodes {
6872
name
73+
id
6974
columns( first: 100 ) {
7075
nodes {
7176
id
@@ -79,6 +84,7 @@ const pullrequestQuery = `query {
7984
projects( search: "Backlogg", first: 10, states: [OPEN] ) {
8085
nodes {
8186
name
87+
id
8288
columns( first: 100 ) {
8389
nodes {
8490
id

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "github-project-automation-plus",
3-
"version": "0.2.0",
3+
"version": "0.2.1",
44
"description": "🤖 Automate GitHub Project cards with any webhook event",
55
"private": true,
66
"main": "dist/index.js",

src/generate-mutation-query.js

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,58 +14,68 @@ const generateMutationQuery = (data, projectName, columnName, contentId) => {
1414
data.repository.owner.projects.nodes) ||
1515
[];
1616

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

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

28-
// Columns that match the column inputted
29-
const newColumnIds = matchingNewProjects
30-
.filter(column => column.name === columnName)
31-
.map(column => column.id);
32+
// Get the ids of the end card location
33+
const endLocationIds = endLocation.map(project => ({
34+
projectId: project.id,
35+
columnId: project.columns.nodes
36+
.filter(column => column.name === columnName)
37+
.map(column => column.id)[0]
38+
}));
3239

33-
if (newColumnIds.length === 0) {
34-
throw new Error(`Could not find the column "${columnName}" in project "${projectName}"`);
35-
}
36-
37-
// Get an array of cards that are assigned to the correct project
38-
const assingedProjects = data.projectCards.nodes
40+
// See if the card has a current location
41+
const currentLocation = data.projectCards.nodes
3942
.filter(card => card.project.name === projectName);
4043

41-
// Get cards in the right project that are not in the correct column
42-
const currentCards = assingedProjects
43-
.filter(card => !newColumnIds.includes(card.column.id));
44+
const currentLocationIds = currentLocation.map(card => ({
45+
projectId: card.project.id,
46+
columnId: card.column.id,
47+
cardId: card.id
48+
}));
4449

45-
// Create an array of queries to move the card
46-
const moveProjectCard = currentCards.map(card =>
47-
`mutation {
48-
moveProjectCard( input: {
49-
cardId: "${card.id}",
50-
columnId: "${card.column.id}"
51-
}) { clientMutationId } }`
52-
);
53-
54-
// Get column ids where the card does not exist
55-
const currentColumnIds = currentCards.map(card => card.column.id);
56-
const emptyColumns = newColumnIds
57-
.filter(columnId => !currentColumnIds.includes(columnId));
50+
// Get cards to create when they do not have a matching existing project
51+
const currentCardProjectIds = currentLocationIds.map(ids => ids.projectId);
52+
const newCards = endLocationIds.filter(ids => !currentCardProjectIds.includes(ids.projectId));
5853

5954
// Create an an array of queries to add the card
60-
const addProjectCard = emptyColumns.map(columnId =>
55+
const addProjectCardQueries = newCards.map(card =>
6156
`mutation {
6257
addProjectCard( input: {
6358
contentId: "${contentId}",
64-
projectColumnId: "${columnId}"
59+
projectColumnId: "${card.columnId}"
6560
}) { clientMutationId } }`
6661
);
6762

68-
return [...addProjectCard, ...moveProjectCard];
63+
// Get cards to move when they exist in a project
64+
const endLocationProjectIds = endLocationIds.map(ids => ids.projectId);
65+
const moveCards = currentLocationIds.filter(ids => endLocationProjectIds.includes(ids.projectId));
66+
67+
// Create an array of queries to move the card
68+
const moveProjectCardQueries = moveCards.map(card => {
69+
const endLocation = endLocationIds.filter(ids => ids.projectId === card.projectId)[0];
70+
71+
return `mutation {
72+
moveProjectCard( input: {
73+
cardId: "${card.cardId}",
74+
columnId: "${endLocation.columnId}"
75+
}) { clientMutationId } }`;
76+
});
77+
78+
return [...addProjectCardQueries, ...moveProjectCardQueries];
6979
};
7080

7181
module.exports = generateMutationQuery;

src/generate-project-query.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ const projectQuery = (url, eventName, project) => (
1717
}
1818
project {
1919
name
20+
id
2021
}
2122
}
2223
}
2324
repository {
2425
projects( search: "${project}", first: 10, states: [OPEN] ) {
2526
nodes {
2627
name
28+
id
2729
columns( first: 100 ) {
2830
nodes {
2931
id
@@ -37,6 +39,7 @@ const projectQuery = (url, eventName, project) => (
3739
projects( search: "${project}", first: 10, states: [OPEN] ) {
3840
nodes {
3941
name
42+
id
4043
columns( first: 100 ) {
4144
nodes {
4245
id

0 commit comments

Comments
 (0)