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
Changes from 1 commit
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
Prev Previous commit
Next Next commit
feature: adapt command to use environment variables
erbenjak committed Dec 20, 2023
commit 55fb0d360a26bb8285215fee4e21fa9a10ad5b23
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
}
60 changes: 40 additions & 20 deletions src/commands/TeamsDevelopMessaging.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import axios from "axios"
import yargs from "yargs"
import { TeamsCommandLineOptions } from "./TeamsCommandLineOptions"

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

export class TeamsDevelopMessaging {
@@ -28,19 +28,21 @@ export class TeamsDevelopMessaging {
process.exit(1)
}

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

const messageContents = {
title: `New successful ${options.platform} debug build for the "${options.projectName}" App`,
title: `New ${statusIdentifier.toLowerCase()} ${options.platform} debug build for the "${
options.projectName
}" App`,
summary: `${options.projectName}: ${statusIdentifier} build - ${platformIdentifier}`,
text: options.wasBuildSuccessful
? `Build ${options.buildNumber}: The latest version did build and is now available as an artifact.`
: `Build ${options.buildNumber}: A problem occurred while building the newly released version. The corresponding logs are available.`,
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.wasBuildSuccessful ? `Download ${options.platform}-App` : "Open Logs",
name: options.buildWasSuccessful ? `Download ${options.platform}-App` : "Download Flutter Logs",
targets: [{ os: "default", uri: options.artifactUrl }]
},
{
@@ -57,15 +59,6 @@ export class TeamsDevelopMessaging {
})
}

public parseCLIOptions(argv: yargs.Argv<{}>): { platform: string } | Promise<{ platform: string }> {
return argv.option("platform", {
description: "identifier of the platform for which the build was created",
required: true,
type: "string",
choices: ["ios", "android"]
}).argv
}

private isUrlValid(url: string): boolean {
try {
// eslint-disable-next-line no-new
@@ -75,4 +68,31 @@ export class TeamsDevelopMessaging {
return false
}
}

public extractArguments(
webhook: string,
buildWasSuccessful: boolean,
buildNumber: number,
projectId: string,
buildId: string,
commandLineOptions: TeamsCommandLineOptions,
cmArtifactLink?: string
): TeamsDevelopMessagingOptions {
if (cmArtifactLink === undefined && buildWasSuccessful) {
console.log("variable CM_ARTIFACT_LINKS must be present in the system, if the build was successful")
process.exit(1)
}

const teamsDevelopMessagingOptions: TeamsDevelopMessagingOptions = {
projectName: commandLineOptions.projectName,
webhook: webhook,
artifactUrl: buildWasSuccessful ? cmArtifactLink! : `https://codemagic.io/app/${projectId}/build/${buildId}`,
buildUrl: `https://codemagic.io/app/${projectId}/build/${buildId}`,
buildWasSuccessful,
platform: commandLineOptions.platform,
buildNumber: buildNumber
}

return teamsDevelopMessagingOptions
}
}
38 changes: 20 additions & 18 deletions src/commands/TeamsProductionMessaging.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import axios from "axios"
import yargs from "yargs"
import { TeamsCommandLineOptions } from "./TeamsCommandLineOptions"

export interface TeamsProductionMessagingOptions {
projectName: string
@@ -43,9 +44,7 @@ export class TeamsProductionMessaging {
})
}

public parseCLIOptions(
argv: yargs.Argv<{}>
): TeamsProductionMessagingOptions | Promise<TeamsProductionMessagingOptions> {
public parseCLIOptions(argv: yargs.Argv<{}>): TeamsCommandLineOptions | Promise<TeamsCommandLineOptions> {
return argv
.option("projectName", {
description: "Name of the project",
@@ -57,21 +56,6 @@ export class TeamsProductionMessaging {
required: true,
type: "string",
choices: ["ios", "android"]
})
.option("buildUrl", {
description: "a link to the build page",
required: true,
type: "string"
})
.option("buildNumber", {
description: "the number of the run build",
required: true,
type: "number"
})
.option("webhook", {
description: "the webhook of the teams channel, that should receive the message",
required: true,
type: "string"
}).argv
}

@@ -84,4 +68,22 @@ export class TeamsProductionMessaging {
return false
}
}

public extractArguments(
webhook: string,
buildNumber: number,
projectId: string,
buildId: string,
commandLineOptions: TeamsCommandLineOptions
): TeamsProductionMessagingOptions {
const teamsDevelopMessagingOptions: TeamsProductionMessagingOptions = {
projectName: commandLineOptions.projectName,
platform: commandLineOptions.platform,
buildUrl: `https://codemagic.io/app/${projectId}/build/${buildId}`,
buildNumber: buildNumber,
webhook: webhook
}

return teamsDevelopMessagingOptions
}
}
96 changes: 81 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -5,45 +5,111 @@ import yargs from "yargs"
import { CmArtifactLink } from "./CmArtifactLink"
import { TeamsDevelopMessaging } from "./commands/TeamsDevelopMessaging"
import { TeamsProductionMessaging } from "./commands/TeamsProductionMessaging"
import { TeamsCommandLineOptions } from "./commands/TeamsCommandLineOptions"

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

const cmArtifactLinks: CmArtifactLink[] = JSON.parse(process.env.CM_ARTIFACT_LINKS!)
const webhook = process.env.teams_webhook_url!
const buildId = process.env.CM_BUILD_ID!
const projectId = process.env.CM_PROJECT_ID!
const buildNumber = process.env.BUILD_NUMBER!

console.log("isSuccess: ", isSuccess)
console.log("CM_ARTIFACT_LINKS: ", cmArtifactLinks)
let cmArtifactLink: string
try {
const cmArtifactLinks: CmArtifactLink[] = JSON.parse(process.env.CM_ARTIFACT_LINKS!).filter(
(element: any) => element.type === "apk" || element.type === "ipa"
)
let artifactLink: string
if (cmArtifactLinks.filter((element: any) => element.type === "apk" || element.type === "ipa").length !== 0) {
artifactLink = 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
artifactLink = `https://codemagic.io/app/${projectId}/build/${buildId}`
}
cmArtifactLink = artifactLink
} catch (error) {
console.log(error)
console.log("To ensure correct execution the environment variable CM_ARTIFACT_LINKS must be present in the system")
process.exit(1)
}

await yargs(process.argv.slice(2))
.command(
"teams-develop",
"After Codemagic Build: Send MS-Teams message informing about the new build",
async (args) => {
async () => {
const teamsMessagingCommand = new TeamsDevelopMessaging()
const options = await teamsMessagingCommand.parseCLIOptions(args)
await teamsMessagingCommand.run({
...options,
wasBuildSuccessful: isSuccess,
cmArtifactLinks
})
return options
const unresolvedOptions = parseCLIOptionsTeams(yargs)
const resolvedOptions: { platform: string; projectName: string } =
unresolvedOptions instanceof Promise ? await unresolvedOptions : unresolvedOptions
checkArtifactLinkMatchesPlatform(resolvedOptions, cmArtifactLink)

const parameters = teamsMessagingCommand.extractArguments(
webhook,
buildWasSuccessful,
Number(buildNumber),
projectId,
buildId,
resolvedOptions,
cmArtifactLink
)
await teamsMessagingCommand.run(parameters)
return
}
)
.command(
"teams-production",
"After Codemagic Publish: Send MS-Teams message informing about the new release",
async (args) => {
async () => {
const teamsMessagePublish = new TeamsProductionMessaging()
const options = await teamsMessagePublish.parseCLIOptions(args)
const unresolvedOptions = parseCLIOptionsTeams(yargs)
const resolvedOptions: { platform: string; projectName: string } =
unresolvedOptions instanceof Promise ? await unresolvedOptions : unresolvedOptions
checkArtifactLinkMatchesPlatform(resolvedOptions, cmArtifactLink)

const options = teamsMessagePublish.extractArguments(
webhook,
Number(buildNumber),
projectId,
buildId,
resolvedOptions
)
await teamsMessagePublish.run(options)
return options
return resolvedOptions
}
)
.demand(1, "Must provide a valid command from the ones listed above.")
.scriptName("jscm")
.parseAsync()
}

function parseCLIOptionsTeams(argv: yargs.Argv<{}>): TeamsCommandLineOptions | Promise<TeamsCommandLineOptions> {
return argv
.option("platform", {
description: "identifier of the platform for which the build was created",
required: true,
type: "string",
choices: ["ios", "android"]
})
.option("projectName", {
description: "objectIdentifier",
required: true,
type: "string"
}).argv
}

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) => {