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

Feature/publish-command-teams #4

Merged
merged 29 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8003126
chore: version bump
erbenjak Dec 13, 2023
65236a8
feature: create teams publish command
erbenjak Dec 13, 2023
145a30a
feature: initial teams publish command
erbenjak Dec 13, 2023
a390823
feature: extend teams-build command
erbenjak Dec 13, 2023
8268085
refactor: minor reordering
erbenjak Dec 13, 2023
2f819bd
refactor: improve parameter names
erbenjak Dec 13, 2023
4078267
refactor: change build-command text slightly
erbenjak Dec 13, 2023
83a0ff3
feature: refine teams-publish command
erbenjak Dec 13, 2023
b322d92
refactor: format project
erbenjak Dec 13, 2023
d9ab002
refactor: improve output message
erbenjak Dec 13, 2023
2338197
refactor: reformat project
erbenjak Dec 13, 2023
755db0d
chore: complete version bump-up
erbenjak Dec 13, 2023
ccdec64
feature: remove artifact link from publish message
erbenjak Dec 13, 2023
520ab09
refactor: rename jscm sub-commands
erbenjak Dec 13, 2023
c309933
refactor: rename to match command-names
erbenjak Dec 13, 2023
c549b39
refactor: reformat files
erbenjak Dec 13, 2023
8ab85bf
feature: improve message quality
erbenjak Dec 15, 2023
4a913cb
wip
jkoenig134 Dec 15, 2023
fa0b316
chore: add test artifact-links
erbenjak Dec 20, 2023
55fb0d3
feature: adapt command to use environment variables
erbenjak Dec 20, 2023
1ea6867
chore: move isUrlValid to utility
jkoenig134 Dec 21, 2023
cf3fe4b
chore: simplify everything
jkoenig134 Dec 21, 2023
745c878
refactor: use semis
jkoenig134 Dec 21, 2023
96d28ac
refactor: use functions instead of classes
jkoenig134 Dec 21, 2023
5b32da6
test: add tests for teams messaging
erbenjak Jan 3, 2024
24e3b39
chore: formatting
jkoenig134 Jan 3, 2024
b5d190d
chore: formatting
jkoenig134 Jan 3, 2024
552d9c7
refactor: use correct artifact links file in testing
erbenjak Jan 3, 2024
e33582c
feature: improve artifact type check
erbenjak Jan 3, 2024
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
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "none",
"semi": false
"semi": true
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@js-soft/codemagic-tools",
"version": "0.0.2",
"version": "0.0.3",
erbenjak marked this conversation as resolved.
Show resolved Hide resolved
"description": "Codemagic extended tooling",
"homepage": "https://github.com/js-soft/codemagic-tools#readme",
"bugs": {
Expand Down
8 changes: 8 additions & 0 deletions src/CmArtifactLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface CmArtifactLink {
name: string;
type: string;
url: string;
md5: string;
versionName: string;
bundleId: string;
}
4 changes: 4 additions & 0 deletions src/commands/TeamsCommandLineOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface TeamsCommandLineOptions {
platform: string;
projectName: string;
}
61 changes: 61 additions & 0 deletions src/commands/TeamsDevelopMessaging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import axios from "axios";
import { isUrlValid } from "./isUrlValid";

export interface TeamsDevelopMessagingOptions {
projectName: string;
webhook: string;
artifactUrl: string;
buildUrl: string;
buildWasSuccessful: boolean;
platform: string;
buildNumber: number;
}

export class TeamsDevelopMessaging {
public async run(options: TeamsDevelopMessagingOptions): Promise<void> {
if (!isUrlValid(options.webhook)) {
console.error("The given webhook is not valid.");
process.exit(1);
}

if (!isUrlValid(options.artifactUrl)) {
console.error("The given artifactUrl is not valid.");
process.exit(1);
}

if (!isUrlValid(options.buildUrl)) {
console.error("The given buildUrl is not valid.");
process.exit(1);
}

const statusIdentifier = options.buildWasSuccessful ? "Successful" : "Failed";
const platformIdentifier = options.platform.toUpperCase();

const messageContents = {
title: `New ${statusIdentifier.toLowerCase()} ${options.platform} debug build for the "${
options.projectName
}" App`,
summary: `${options.projectName}: ${statusIdentifier} build - ${platformIdentifier}`,
text: options.buildWasSuccessful
? `New Build: #${options.buildNumber} - ${platformIdentifier} <br/> The latest version build successfully and is now available as an artifact.`
: `New Build: #${options.buildNumber} - ${platformIdentifier} <br/> A problem occurred while building the newly released version. The corresponding logs are available.`,
potentialAction: [
{
"@type": "OpenUri",
name: options.buildWasSuccessful ? `Download ${options.platform}-App` : "Download Flutter Logs",
targets: [{ os: "default", uri: options.artifactUrl }]
},
{
"@type": "OpenUri",
name: "Open Build",
targets: [{ os: "default", uri: options.buildUrl }]
}
]
};

await axios.post(options.webhook, messageContents).catch((_) => {
console.log("Could not send message to teams channel.");
process.exit(1);
});
}
}
81 changes: 0 additions & 81 deletions src/commands/TeamsMessaging.ts

This file was deleted.

45 changes: 45 additions & 0 deletions src/commands/TeamsProductionMessaging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import axios from "axios";
import { isUrlValid } from "./isUrlValid";

export interface TeamsProductionMessagingOptions {
projectName: string;
platform: string;
buildUrl: string;
buildNumber: number;
webhook: string;
}

export class TeamsProductionMessaging {
public async run(options: TeamsProductionMessagingOptions): Promise<void> {
if (!isUrlValid(options.webhook)) {
console.error("The given webhook is not valid.");
process.exit(1);
}

if (!isUrlValid(options.buildUrl)) {
console.error("The given buildUrl is not valid.");
process.exit(1);
}

const platformIdentifier = options.platform.toUpperCase();
const storeName = platformIdentifier === "IOS" ? "App Store" : "Google Play Store";
const messageContents = {
title: `${options.projectName}: New release is now available in the ${storeName} [${platformIdentifier}]`,
summary: `New Release - ${platformIdentifier}`,
text: `New Release: #${options.buildNumber} - ${platformIdentifier} <br/>
The newly released version is now available in the ${storeName}. `,
potentialAction: [
{
"@type": "OpenUri",
name: "Open Build",
targets: [{ os: "default", uri: options.buildUrl }]
}
]
};

await axios.post(options.webhook, messageContents).catch((_) => {
console.log("Could not send message to teams channel.");
process.exit(1);
});
}
}
9 changes: 9 additions & 0 deletions src/commands/isUrlValid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function isUrlValid(url: string): boolean {
try {
// eslint-disable-next-line no-new
new URL(url);
return true;
} catch (err) {
return false;
}
}
106 changes: 94 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,106 @@
#!/usr/bin/env node

import yargs from "yargs"
import { TeamsMessaging } from "./commands/TeamsMessaging"
import fs from "fs";
import yargs from "yargs";
import { CmArtifactLink } from "./CmArtifactLink";
import { TeamsCommandLineOptions } from "./commands/TeamsCommandLineOptions";
import { TeamsDevelopMessaging } from "./commands/TeamsDevelopMessaging";
import { TeamsProductionMessaging } from "./commands/TeamsProductionMessaging";

async function run() {
const buildWasSuccessful = fs.existsSync("~/SUCCESS");

const webhook = process.env.teams_webhook_url!;
const buildId = process.env.CM_BUILD_ID!;
const projectId = process.env.CM_PROJECT_ID!;
const buildNumber = parseInt(process.env.BUILD_NUMBER!);
const buildUrl = `https://codemagic.io/app/${projectId}/build/${buildId}`;

if (process.env.CM_ARTIFACT_LINKS === undefined) {
console.error(
"To ensure correct execution the environment variable CM_ARTIFACT_LINKS must be present in the system"
);
process.exit(1);
}

let artifactUrl: string;

const cmArtifactLinks: CmArtifactLink[] = JSON.parse(process.env.CM_ARTIFACT_LINKS!).filter(
(element: any) => element.type === "apk" || element.type === "ipa"
);
if (cmArtifactLinks.filter((element: any) => element.type === "apk" || element.type === "ipa").length !== 0) {
artifactUrl = cmArtifactLinks.filter((element: any) => element.type === "apk" || element.type === "ipa")[0].url;
} else {
// should link to the workflow-log can be determined from buildId and projectId
artifactUrl = buildUrl;
}

await yargs(process.argv.slice(2))
.command("teams", "This command is used to send a teams message via a passed webhook", async (args) => {
const teamsMessagingCommand = new TeamsMessaging()
const options = await teamsMessagingCommand.parseCLIOptions(args)
await teamsMessagingCommand.run(options)
return options
.option("platform", {
description: "identifier of the platform for which the build was created",
required: true,
type: "string",
choices: ["ios", "android"]
})
.demand(1, "Must provide a valid command from the ones listed above.")
.option("projectName", {
description: "Name of the project",
required: true,
type: "string"
})
.command(
"teams-develop",
"After Codemagic Build: Send MS-Teams message informing about the new build",
undefined,
async (args) => {
const teamsMessagingCommand = new TeamsDevelopMessaging();
checkArtifactLinkMatchesPlatform(args, artifactUrl);

await teamsMessagingCommand.run({
projectName: args.projectName,
webhook,
artifactUrl,
buildUrl,
buildWasSuccessful,
platform: args.platform,
buildNumber
});
}
)
.command(
"teams-production",
"After Codemagic Publish: Send MS-Teams message informing about the new release",
undefined,
async (args) => {
const teamsMessagePublish = new TeamsProductionMessaging();

await teamsMessagePublish.run({
projectName: args.projectName,
platform: args.platform,
buildUrl,
buildNumber,
webhook
});
}
)
.demandCommand(1, "Must provide a valid command from the ones listed above.")
.scriptName("jscm")
.parseAsync()
.parseAsync();
}

function checkArtifactLinkMatchesPlatform(resolvedOptions: TeamsCommandLineOptions, cmArtifactLink: string) {
// throw exception if the artifact link does not have the correct type for the given platform
if (
(resolvedOptions.platform === "ios" && cmArtifactLink.includes("ipa")!) ||
(resolvedOptions.platform === "android" && cmArtifactLink.includes("apk")!)
) {
console.log("The artifact link does not have the correct type for the given platform");
process.exit(1);
}
}

run()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
console.error(error);
process.exit(1);
});
16 changes: 16 additions & 0 deletions test/artifactLinks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[
{
"name": "Codemagic_Release.ipa",
"type": "ipa",
"url": "https://api.codemagic.io/artifacts/2e7564b2-9ffa-40c2-b9e0-8980436ac717/81c5a723-b162-488a-854e-3f5f7fdfb22f/Codemagic_Release.ipa",
"md5": "d2884be6985dad3ffc4d6f85b3a3642a",
"versionName": "1.0.2",
"bundleId": "io.codemagic.app"
},
{
"name": "logs.txt",
"type": "txt",
"url": "https://api.codemagic.io/artifacts/2e7564b2-9ffa-40c2-b9e0-8980436ac717/81c5a723-b162-488a-854e-3f5f7fdfb22f/logs.txt",
"md5": "d2884be6985dad3ffc4d6f85b3a3642a"
erbenjak marked this conversation as resolved.
Show resolved Hide resolved
}
]
Loading