@duckduckgo/autoconsent 14.11.0 → 14.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,9 @@ on:
6
6
  tag_name:
7
7
  description: 'The tag of the release to propagate'
8
8
  required: true
9
+ release_task_url:
10
+ description: 'The link to the release task in Asana'
11
+ required: true
9
12
  android:
10
13
  description: 'Propagate to Android'
11
14
  type: boolean
@@ -28,6 +31,10 @@ on:
28
31
  type: string
29
32
  description: 'The tag of the release to propagate'
30
33
  required: true
34
+ release_task_url:
35
+ type: string
36
+ description: 'The link to the release task in Asana'
37
+ required: true
31
38
  android:
32
39
  description: 'Propagate to Android'
33
40
  type: boolean
@@ -50,39 +57,12 @@ jobs:
50
57
  # Retrieve the corresponding Release data from the GitHub API
51
58
  # ------------------------------------------------------------------------------
52
59
  get_release_info:
53
- runs-on: ubuntu-latest
54
- outputs:
55
- release-url: ${{ steps.get-release-url.outputs.result }}
56
- release-notes: ${{ steps.get-release-notes.outputs.result }}
57
- steps:
58
- - name: Get Release URL
59
- id: get-release-url
60
- uses: actions/github-script@v4
61
- with:
62
- result-encoding: string
63
- script: |
64
- const { data } = await github.repos.getReleaseByTag({
65
- owner: context.repo.owner,
66
- repo: context.repo.repo,
67
- tag: process.env.TAG
68
- });
69
- return data.html_url;
70
-
71
- - name: Get Release Notes
72
- id: get-release-notes
73
- uses: actions/github-script@v4
74
- with:
75
- result-encoding: string
76
- script: |
77
- const { data } = await github.repos.getReleaseByTag({
78
- owner: context.repo.owner,
79
- repo: context.repo.repo,
80
- tag: process.env.TAG
81
- });
82
- return data.body;
60
+ uses: ./.github/workflows/get-release-info.yml
61
+ with:
62
+ tag_name: ${{ inputs.tag_name }}
83
63
 
84
64
  # ------------------------------------------------------------------------------
85
- # Create initial Asana subtasks
65
+ # Create platform release subtasks
86
66
  # ------------------------------------------------------------------------------
87
67
  create_asana_tasks:
88
68
  needs: get_release_info
@@ -103,7 +83,7 @@ jobs:
103
83
  env:
104
84
  ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
105
85
  run: |
106
- JSON_STRING="$(node ./autoconsent/ci/asana-create-tasks.js)"
86
+ JSON_STRING="$(node ./autoconsent/ci/asana-create-platform-release-tasks.js)"
107
87
  echo "ASANA_OUTPUT=$JSON_STRING" >> $GITHUB_OUTPUT
108
88
 
109
89
  # ------------------------------------------------------------------------------
@@ -113,11 +93,11 @@ jobs:
113
93
  update_android:
114
94
  if: ${{ inputs.android }}
115
95
  runs-on: ubuntu-latest
116
- outputs:
117
- pull-request-url: ${{ steps.create-pr.outputs.pull-request-url }}
118
96
  needs:
119
- - create_asana_tasks
120
97
  - get_release_info
98
+ - create_asana_tasks
99
+ outputs:
100
+ pull-request-url: ${{ steps.create-pr.outputs.pull-request-url }}
121
101
  env:
122
102
  RELEASE_URL: ${{ needs.get_release_info.outputs.release-url }}
123
103
  steps:
@@ -178,8 +158,8 @@ jobs:
178
158
  outputs:
179
159
  pull-request-url: ${{ steps.create-pr.outputs.pull-request-url }}
180
160
  needs:
181
- - create_asana_tasks
182
161
  - get_release_info
162
+ - create_asana_tasks
183
163
  env:
184
164
  RELEASE_URL: ${{ needs.get_release_info.outputs.release-url }}
185
165
  steps:
@@ -249,8 +229,8 @@ jobs:
249
229
  outputs:
250
230
  pull-request-url: ${{ steps.create-pr.outputs.pull-request-url }}
251
231
  needs:
252
- - create_asana_tasks
253
232
  - get_release_info
233
+ - create_asana_tasks
254
234
  env:
255
235
  RELEASE_URL: ${{ needs.get_release_info.outputs.release-url }}
256
236
  steps:
@@ -0,0 +1,49 @@
1
+ name: Get Release Info
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ tag_name:
7
+ type: string
8
+ description: 'The tag of the release to get info for'
9
+ required: true
10
+ outputs:
11
+ release-url:
12
+ description: 'The HTML URL of the release'
13
+ value: ${{ jobs.get_release_info.outputs.release-url }}
14
+ release-notes:
15
+ description: 'The release notes body'
16
+ value: ${{ jobs.get_release_info.outputs.release-notes }}
17
+
18
+ jobs:
19
+ get_release_info:
20
+ runs-on: ubuntu-latest
21
+ outputs:
22
+ release-url: ${{ steps.get-release-url.outputs.result }}
23
+ release-notes: ${{ steps.get-release-notes.outputs.result }}
24
+ steps:
25
+ - name: Get Release URL
26
+ id: get-release-url
27
+ uses: actions/github-script@v4
28
+ with:
29
+ result-encoding: string
30
+ script: |
31
+ const { data } = await github.repos.getReleaseByTag({
32
+ owner: context.repo.owner,
33
+ repo: context.repo.repo,
34
+ tag: '${{ inputs.tag_name }}'
35
+ });
36
+ return data.html_url;
37
+
38
+ - name: Get Release Notes
39
+ id: get-release-notes
40
+ uses: actions/github-script@v4
41
+ with:
42
+ result-encoding: string
43
+ script: |
44
+ const { data } = await github.repos.getReleaseByTag({
45
+ owner: context.repo.owner,
46
+ repo: context.repo.repo,
47
+ tag: '${{ inputs.tag_name }}'
48
+ });
49
+ return data.body;
@@ -6,12 +6,20 @@ on:
6
6
  tag_name:
7
7
  description: 'The tag of the release to use'
8
8
  required: true
9
+ asana_task_gid:
10
+ type: string
11
+ description: 'The GID of the Asana task to link to'
12
+ required: false
9
13
  workflow_call:
10
14
  inputs:
11
15
  tag_name:
12
16
  type: string
13
17
  description: 'The tag of the release to use'
14
18
  required: true
19
+ asana_task_gid:
20
+ type: string
21
+ description: 'The GID of the Asana task to link to'
22
+ required: false
15
23
 
16
24
  env:
17
25
  TAG: ${{ inputs.tag_name }}
@@ -51,5 +59,5 @@ jobs:
51
59
  commit-message: Update autoconsent to ${{ env.TAG }}
52
60
  branch: update-autoconsent
53
61
  title: Update autoconsent to ${{ env.TAG }}
54
- body: ''
62
+ body: 'Asana Task/Github Issue: https://app.asana.com/1/137249556945/project/1201844467387842/task/${{ inputs.asana_task_gid }}'
55
63
  token: ${{ secrets.PRIVACY_CONFIG_PAT }}
@@ -4,6 +4,7 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - main
7
+ workflow_dispatch:
7
8
 
8
9
  jobs:
9
10
  release:
@@ -29,6 +30,11 @@ jobs:
29
30
  run: |
30
31
  npm run compile-filterlist
31
32
 
33
+ - name: Set Git identity
34
+ run: |
35
+ git config --global user.email "dax@duckduckgo.com"
36
+ git config --global user.name "Dax the Deployer"
37
+
32
38
  - name: Create Release
33
39
  env:
34
40
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -40,11 +46,51 @@ jobs:
40
46
  id: remember_tag
41
47
  run: echo "tag_name=$(git describe --exact-match --tags)" >> "$GITHUB_OUTPUT"
42
48
 
49
+ # ------------------------------------------------------------------------------
50
+ # Retrieve the corresponding Release data from the GitHub API
51
+ # ------------------------------------------------------------------------------
52
+ get_release_info:
53
+ needs: release
54
+ if: ${{ needs.release.outputs.tag_name != '' }}
55
+ uses: ./.github/workflows/get-release-info.yml
56
+ with:
57
+ tag_name: ${{ needs.release.outputs.tag_name }}
58
+
59
+ # ------------------------------------------------------------------------------
60
+ # Create initial Asana subtasks
61
+ # ------------------------------------------------------------------------------
62
+ create_asana_tasks:
63
+ needs: get_release_info
64
+ runs-on: ubuntu-latest
65
+ outputs:
66
+ task-gid: ${{ steps.create-asana-tasks.outputs.TASK_GID }}
67
+ env:
68
+ RELEASE_URL: ${{ needs.get_release_info.outputs.release-url }}
69
+ steps:
70
+ # --- Setup ---
71
+ - uses: actions/checkout@v3
72
+ with:
73
+ path: autoconsent/
74
+ - uses: ./autoconsent/.github/actions/setup-release-scripts
75
+ # --- Effect ---
76
+ - name: Create Asana Tasks
77
+ id: create-asana-tasks
78
+ env:
79
+ ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
80
+ run: |
81
+ RELEASE_TASK_GID="$(node ./autoconsent/ci/asana-create-release-task.js)"
82
+ echo "TASK_GID=$RELEASE_TASK_GID" >> "$GITHUB_OUTPUT"
83
+
84
+ # ------------------------------------------------------------------------------
85
+ # Create PR to privacy-configuration repository
86
+ # ------------------------------------------------------------------------------
43
87
  rule-release:
44
88
  name: Propagate rules to privacy config
45
- needs: release
46
- if: ${{ !contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'skip ci') && needs.release.outputs.tag_name != '' }}
89
+ needs:
90
+ - release
91
+ - create_asana_tasks
47
92
  uses: ./.github/workflows/privacy-config-pr.yml
48
93
  secrets: inherit
49
94
  with:
50
95
  tag_name: ${{ needs.release.outputs.tag_name }}
96
+ asana_task_gid: ${{ needs.create_asana_tasks.outputs.task-gid }}
package/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ # v14.12.0 (Wed Aug 13 2025)
2
+
3
+ #### 🚀 Enhancement
4
+
5
+ - [test] Add autoconsent rules for 1 sites (0 requiring review) [#873](https://github.com/duckduckgo/autoconsent/pull/873) ([@daxtheduck](https://github.com/daxtheduck))
6
+
7
+ #### 🐛 Bug Fix
8
+
9
+ - Release automation update [#880](https://github.com/duckduckgo/autoconsent/pull/880) ([@sammacbeth](https://github.com/sammacbeth))
10
+ - Fix playwright tests [#877](https://github.com/duckduckgo/autoconsent/pull/877) ([@muodov](https://github.com/muodov))
11
+ - 🤖 Add autoconsent rules for 1 sites (0 requiring review) [#874](https://github.com/duckduckgo/autoconsent/pull/874) ([@daxtheduck](https://github.com/daxtheduck))
12
+
13
+ #### ⚠️ Pushed to `main`
14
+
15
+ - Temp disable release tag requirement ([@sammacbeth](https://github.com/sammacbeth))
16
+ - Set Dax's credentials for releases ([@sammacbeth](https://github.com/sammacbeth))
17
+
18
+ #### 🧪 Tests
19
+
20
+ - Improve playwright tests [#852](https://github.com/duckduckgo/autoconsent/pull/852) ([@muodov](https://github.com/muodov))
21
+
22
+ #### Authors: 3
23
+
24
+ - Dax ([@daxtheduck](https://github.com/daxtheduck))
25
+ - Maxim Tsoy ([@muodov](https://github.com/muodov))
26
+ - Sam Macbeth ([@sammacbeth](https://github.com/sammacbeth))
27
+
28
+ ---
29
+
1
30
  # v14.11.0 (Wed Aug 06 2025)
2
31
 
3
32
  #### 🚀 Enhancement
package/Jenkinsfile CHANGED
@@ -1,15 +1,16 @@
1
1
  def runPlaywrightTests(resultDir, browser, testFiles) {
2
+ def junitFile = "results-${env.REGION}.xml"
2
3
  try {
3
4
  timeout(120) {
4
5
  def testFilesArg = testFiles.join(' ')
5
6
  sh """
6
- rm -f results.xml
7
- PLAYWRIGHT_JUNIT_OUTPUT_NAME=results.xml npx playwright test ${testFilesArg} --project ${browser} --reporter=junit || true
7
+ PLAYWRIGHT_JUNIT_OUTPUT_NAME=${junitFile} npx playwright test ${testFilesArg} --project ${browser} --workers 10 --reporter=junit,line || true
8
8
  """
9
9
  }
10
10
  } finally {
11
- def summary = junit skipMarkingBuildUnstable: true, skipPublishingChecks: true, testResults: 'results.xml'
12
- archiveArtifacts artifacts: 'test-results/screenshots/**/*.jpg', fingerprint: true, allowEmptyArchive: true
11
+ def summary = junit skipMarkingBuildUnstable: true, skipPublishingChecks: true, allowEmptyResults: true, testResults: junitFile
12
+ archiveArtifacts artifacts: "test-results/screenshots/**/*.jpg", fingerprint: true, allowEmptyArchive: true
13
+ archiveArtifacts artifacts: junitFile, fingerprint: true, allowEmptyArchive: true
13
14
  return summary
14
15
  }
15
16
  }
@@ -145,13 +146,13 @@ pipeline {
145
146
  }
146
147
 
147
148
  githubNotify(
148
- account: 'duckduckgo',
149
- repo: 'autoconsent',
150
- context: 'Tests / Changed files',
151
- sha: "${env.GIT_COMMIT}",
152
- description: description,
153
- status: status,
154
- credentialsId: 'autoconsent-rw'
149
+ account: 'duckduckgo',
150
+ repo: 'autoconsent',
151
+ context: 'Tests / Changed files',
152
+ sha: "${env.GIT_COMMIT}",
153
+ description: description,
154
+ status: status,
155
+ credentialsId: 'autoconsent-rw'
155
156
  )
156
157
  }
157
158
  }
@@ -0,0 +1,119 @@
1
+ /* eslint-disable camelcase */
2
+ const Asana = require('asana');
3
+
4
+ const ASANA_ACCESS_TOKEN = process.env.ASANA_ACCESS_TOKEN;
5
+ const RELEASE_TASK_URL = process.env.RELEASE_TASK_URL || '';
6
+ const version = process.env.TAG;
7
+
8
+ const templateTaskGid = '1206774921409831';
9
+ const projectExtractorRegex = /\[\[project_gids=(.*)]]/;
10
+
11
+ // Parse task GID out of URL
12
+ const regex = /^https:\/\/app.asana.com\/(\d+)\/((\d+)\/)?(project\/)?(?<project>\d+)(\/task)?\/(?<task>\d+).*?/;
13
+ const match = regex.exec(RELEASE_TASK_URL);
14
+ const releaseTaskGid = match?.groups?.task;
15
+
16
+ /**
17
+ * @typedef {{taskGid: string, taskUrl: string, displayName: string}} platformData
18
+ *
19
+ * @typedef {{
20
+ * android: platformData,
21
+ * windows: platformData,
22
+ * apple: platformData
23
+ * }} AsanaOutput
24
+ */
25
+
26
+ /** @type {AsanaOutput} */
27
+ const platforms = {
28
+ android: {
29
+ displayName: 'Android',
30
+ taskGid: '',
31
+ taskUrl: '',
32
+ },
33
+ windows: {
34
+ displayName: 'Windows',
35
+ taskGid: '',
36
+ taskUrl: '',
37
+ },
38
+ apple: {
39
+ displayName: 'Apple',
40
+ taskGid: '',
41
+ taskUrl: '',
42
+ },
43
+ };
44
+
45
+ const setupAsana = () => {
46
+ return Asana.Client.create({
47
+ defaultHeaders: {
48
+ 'Asana-Enable': 'new_project_templates,new_user_task_lists,new_goal_memberships',
49
+ },
50
+ }).useAccessToken(ASANA_ACCESS_TOKEN);
51
+ };
52
+
53
+ async function main() {
54
+ const asana = setupAsana();
55
+ const { data: templateSubTasks } = await asana.tasks.getSubtasksForTask(templateTaskGid, {
56
+ opt_fields: 'name,html_notes,permalink_url',
57
+ });
58
+
59
+ // Creating subtasks...
60
+ await Promise.all(
61
+ templateSubTasks.map((subtask) =>
62
+ asana.tasks.createSubtaskForTask(releaseTaskGid, {
63
+ name: subtask.name,
64
+ html_notes: subtask.html_notes,
65
+ opt_fields: 'name,html_notes,permalink_url',
66
+ }),
67
+ ),
68
+ );
69
+ const { data: subtasks } = await asana.tasks.getSubtasksForTask(releaseTaskGid, { opt_fields: 'gid,name,html_notes,permalink_url' });
70
+ console.error('subtasks:', subtasks);
71
+
72
+ // Get html_notes from the release task
73
+ const { html_notes: releaseTaskNotes } = await asana.tasks.getTask(releaseTaskGid, { opt_fields: 'html_notes' });
74
+
75
+ // Updating subtasks and moving to appropriate projects...
76
+ for (const subtask of subtasks) {
77
+ const { gid, name, html_notes, permalink_url } = subtask;
78
+
79
+ const platform = Object.keys(platforms).find((key) => name.includes(platforms[key].displayName));
80
+ if (!platform) {
81
+ continue;
82
+ }
83
+
84
+ platforms[platform].taskGid = gid;
85
+ platforms[platform].taskUrl = permalink_url;
86
+
87
+ const newName = name.replace('[[version]]', version);
88
+ const extractedProjects = html_notes.match(projectExtractorRegex)?.[1];
89
+
90
+ const subtaskNotes = html_notes.replace(projectExtractorRegex, '').replace('[[notes]]', releaseTaskNotes);
91
+
92
+ console.error(`updating task ${gid} with name ${newName} and notes ${subtaskNotes}`);
93
+ await asana.tasks.updateTask(gid, { name: newName, html_notes: subtaskNotes });
94
+
95
+ if (extractedProjects) {
96
+ console.error(`adding projects ${extractedProjects} to task ${gid}`);
97
+ for (const projectGidAndSection of extractedProjects.split(',')) {
98
+ const [projectGid, sectionGid] = projectGidAndSection.split(':');
99
+ await asana.tasks.addProjectForTask(gid, { project: projectGid, section: sectionGid });
100
+ }
101
+ }
102
+ }
103
+ const jsonString = JSON.stringify(platforms);
104
+ return { stdout: jsonString };
105
+ }
106
+
107
+ main()
108
+ .then((result) => {
109
+ // this log is for visibility in Github web interface
110
+ console.error('stage result:', result.stdout);
111
+ // The log is needed to read the value from the bash context
112
+ console.log(result.stdout);
113
+ })
114
+ .catch((e) => {
115
+ console.error('Failed to create asana tasks:');
116
+ // The Asana API returns errors in e.value.errors. If that's undefined log whatever else we got
117
+ console.error(e.value?.errors || e);
118
+ process.exit(1);
119
+ });
@@ -15,36 +15,6 @@ const templateTaskGid = '1206774921409831';
15
15
  const autoconsentProjectGid = '1201844467387842';
16
16
  const releaseSectionGid = '1202253736774466';
17
17
  const scheduledForReleaseSectionGid = '1207140808076253';
18
- const projectExtractorRegex = /\[\[project_gids=(.*)]]/;
19
-
20
- /**
21
- * @typedef {{taskGid: string, taskUrl: string, displayName: string}} platformData
22
- *
23
- * @typedef {{
24
- * android: platformData,
25
- * windows: platformData,
26
- * apple: platformData
27
- * }} AsanaOutput
28
- */
29
-
30
- /** @type {AsanaOutput} */
31
- const platforms = {
32
- android: {
33
- displayName: 'Android',
34
- taskGid: '',
35
- taskUrl: '',
36
- },
37
- windows: {
38
- displayName: 'Windows',
39
- taskGid: '',
40
- taskUrl: '',
41
- },
42
- apple: {
43
- displayName: 'Apple',
44
- taskGid: '',
45
- taskUrl: '',
46
- },
47
- };
48
18
 
49
19
  let asana;
50
20
 
@@ -58,7 +28,7 @@ const setupAsana = () => {
58
28
 
59
29
  const duplicateTemplateTask = (templateTaskGid) => {
60
30
  const duplicateOption = {
61
- include: ['notes', 'assignee', 'subtasks', 'projects'],
31
+ include: ['notes', 'assignee', 'projects'],
62
32
  name: `Autoconsent release ${version}`,
63
33
  opt_fields: 'html_notes',
64
34
  };
@@ -161,45 +131,13 @@ const asanaCreateTasks = async () => {
161
131
  const duplicateTaskResult = await waitForJobSuccess(duplicateTaskJobGid);
162
132
  console.error('duplicateTaskResult:', duplicateTaskResult);
163
133
 
164
- // Getting subtasks...
165
- const { data: subtasks } = await asana.tasks.getSubtasksForTask(new_task.gid, { opt_fields: 'name,html_notes,permalink_url' });
166
- console.error('subtasks:', subtasks);
167
-
168
- // Updating subtasks and moving to appropriate projects...
169
- for (const subtask of subtasks) {
170
- const { gid, name, html_notes, permalink_url } = subtask;
171
-
172
- const platform = Object.keys(platforms).find((key) => name.includes(platforms[key].displayName));
173
- if (!platform) throw new Error('Unexpected platform name: ' + name);
174
-
175
- platforms[platform].taskGid = gid;
176
- platforms[platform].taskUrl = permalink_url;
177
-
178
- const newName = name.replace('[[version]]', version);
179
- const extractedProjects = html_notes.match(projectExtractorRegex)?.[1];
180
-
181
- const subtaskNotes = html_notes.replace(projectExtractorRegex, '').replace('[[notes]]', updatedNotes);
182
-
183
- console.error(`updating task ${gid} with name ${newName} and notes ${subtaskNotes}`);
184
- await asana.tasks.updateTask(gid, { name: newName, html_notes: subtaskNotes });
185
-
186
- if (extractedProjects) {
187
- console.error(`adding projects ${extractedProjects} to task ${gid}`);
188
- for (const projectGidAndSection of extractedProjects.split(',')) {
189
- const [projectGid, sectionGid] = projectGidAndSection.split(':');
190
- await asana.tasks.addProjectForTask(gid, { project: projectGid, section: sectionGid });
191
- }
192
- }
193
- }
194
-
195
134
  const finalNotes = updatedNotes.replace('<li>[[pr_url]]</li>', version).replace('<li>[[extra_content]]</li>', version);
196
135
 
197
136
  console.error('finalNotes:', finalNotes);
198
137
  updateTaskResult = await asana.tasks.updateTask(new_task.gid, { html_notes: finalNotes });
199
138
  console.error('updateTaskResult:', updateTaskResult);
200
139
 
201
- const jsonString = JSON.stringify(platforms);
202
- return { stdout: jsonString };
140
+ return { stdout: new_task.gid };
203
141
  };
204
142
 
205
143
  asanaCreateTasks()
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 2,
3
3
  "name": "Autoconsent",
4
- "version": "2025.8.1",
4
+ "version": "2025.8.6",
5
5
  "background": {
6
6
  "scripts": [
7
7
  "background.bundle.js"